<commit_before>/**
 * Copy Button modeled on Add button features from Django admin and Grappelli inlines.js
 */

var OPELEC = OPELEC || function() {};

OPELEC.inlines = {

    copy: function(copy_anchor) {
        // Get stacked inline container from copy button that was clicked
        var inline = grp.jQuery(copy_anchor).closest('div'),
            inlines_div = grp.jQuery(copy_anchor).closest('.grp-group'),
            prefix = OPELEC.inlines.getFormPrefix(inlines_div),
            empty_template = inlines_div.find("#" + prefix + "-empty"),
            meta = OPELEC.inlines.getInlinesAndFormMeta(inlines_div);

        var inline_copy = inline.clone();

        // Fix h3 text
        var header = inline_copy.find('h3');
        var new_header = header.text().split(/\d{4}/)[0].trim();
        header.text(new_header);

        var orig_idx = parseInt(inline_copy.attr('id').split(prefix)[1], 10),
            new_idx = meta.totalFormsCount,
            to_replace = prefix + '-' + orig_idx,
            replacement = prefix + '-' + new_idx;

        // Update index in form ids
        OPELEC.inlines.updateFormIndexes(inline_copy, to_replace, replacement);

        // Remove the ID value copied from prior record (this corresponds to db primary key)
        inline_copy.find('#id_' + prefix + '-' + new_idx + '-id').removeAttr('value');

        // Remove delete button input tag and change inline class to remove button
        // handler (this matches behavior of Add button)
        var opts = OPELEC.inlines.opts();
        inline_copy.find('#id_' + prefix + '-' + new_idx + '-DELETE').remove();
        inline_copy.find('.' + opts.deleteCssClass)
                   .removeClass(opts.deleteCssClass)
                   .addClass(opts.removeCssClass);

        // Update Total Forms count
        meta.totalForms.val(meta.totalFormsCount + 1);

        // Insert inline into DOM
        inline_copy.insertBefore(empty_template);

        OPELEC.inlines.onAfterCopied(inline_copy, prefix, opts);
    },
    opts: function() {
        return {
            prefix: "form",                         // The form prefix for your django formset
            addText: "add another",                 // Text for the add link
            deleteText: "remove",                   // Text for the delete link
            addCssClass: "grp-add-handler",             // CSS class applied to the add link
            copyCssClass: "grp-copy-handler",
            removeCssClass: "grp-remove-handler",       // CSS class applied to the remove link
            deleteCssClass: "grp-delete-handler",       // CSS class applied to the delete link
            emptyCssClass: "grp-empty-form",            // CSS class applied to the empty row
            formCssClass: "grp-dynamic-form",           // CSS class applied to each form in a formset
            predeleteCssClass: "grp-predelete"
        };
    },
    onAfterCopied: function(inline_copy, prefix, opts) {
        // Re-init some grappelli initializers and edge-case handling
        // datepicker (explained below)
        grappelli.updateSelectFilter(inline_copy);

        var date_opts = {
            //appendText: '(mm/dd/yyyy)',
            showOn: 'button',
            buttonImageOnly: false,
            buttonText: '',
            dateFormat: grappelli.getFormat('date'),
            showButtonPanel: true,
            showAnim: '',
            // HACK: sets the current instance to a global var.
            // needed to actually select today if the today-button is clicked.
            // see onClick handler for ".ui-datepicker-current"
            beforeShow: function(year, month, inst) {
                grappelli.datepicker_instance = this;
            }
        };
        // Reinitialize datepicker, due to issue described here:
        // http://stackoverflow.com/questions/2441061/problem-when-cloning-jquery-ui-datepicker
        var dateFields = inline_copy.find('.vDateField');
        dateFields.removeClass('hasDatepicker')
                  .removeData('datepicker')
                  .unbind()
                  .datepicker(date_opts);
        dateFields.each(function() {
            var buttons = grp.jQuery(this).siblings('.ui-datepicker-trigger');
            if (buttons.length > 1) {
                buttons.eq(1).remove();
            };
        });
        inline_copy.grp_collapsible();
        inline_copy.find('.grp-collapse').grp_collapsible();

        // Re-init remove handler
        OPELEC.inlines.removeButtonHandler(inline_copy.find("a." + opts.removeCssClass), prefix, opts);

        // Add "available" and "chosen" options to SelectBox cache
        OPELEC.inlines.updateSelectBoxCache(inline_copy, 'select[id^="id_"][id$="_from"]');
        OPELEC.inlines.updateSelectBoxCache(inline_copy, 'select[id^="id_"][id$="_to"]');

        // Re-init SelectBox selections (which lose the attribute on clone)
        inline_copy.find('.selector-chosen option').each(function() {
            this.selected = 'selected';
        });

        // Re-initialize copy handler
        inline_copy.find('a.' + opts.copyCssClass).click(function(e) {
            var target = e.target;
            var target = (e.target) ? e.target : e.srcElement;
            OPELEC.inlines.copy(target);
        });
    },
    removeButtonHandler: function(elem, prefix, options) {
        elem.bind("click", function() {
            var inline = elem.parents(".grp-group"),
                form = grp.jQuery(this).parents("." + options.formCssClass).first(),
                totalForms = inline.find("#id_" + prefix + "-TOTAL_FORMS"),
                maxForms = inline.find("#id_" + prefix + "-MAX_NUM_FORMS");
            // remove form
            form.remove();
            // update total forms
            var index = parseInt(totalForms.val(), 10);
            totalForms.val(index - 1);
            // show add button in case we've dropped below max
            if ((maxForms.val() !== 0) && (maxForms.val() - totalForms.val()) > 0) {
                showAddButtons(inline, options);
            }
            // update form index (for all forms)
            var re = /-\d+-/g,
                i = 0;
            inline.find("." + options.formCssClass).each(function() {
                updateFormIndex(grp.jQuery(this), options, re, "-" + i + "-");
                i++;
            });
        });
    },
    showAddButtons: function(elem, options) {
        var addButtons = elem.find("a." + options.addCssClass);
        addButtons.show().parents('.grp-add-item').show();
    },
    getInlinesAndFormMeta: function(inlines_div) {
        var prefix = OPELEC.inlines.getFormPrefix(inlines_div);
        var inlines = inlines_div.find(".grp-items");
        var totalForms = inlines_div.find("#id_" + prefix + "-TOTAL_FORMS");
        var maxForms = inlines_div.find("#id_" + prefix + "-MAX_NUM_FORMS");

        return {
            'inlines':inlines,
            'totalForms':totalForms,
            'totalFormsCount':parseInt(totalForms.val(), 10),
            'maxForms':maxForms,
            'maxFormsCount':parseInt(maxForms.val(), 10)
       };
    },
    getFormPrefix: function(inlines_div) {
        return inlines_div[0].id.split('-')[0];
    },
    updateFormIndexes: function(elem, replace_text, replace_with) {
        elem.find(':input,span,table,iframe,label,a,ul,p,img,div').each(function() {
            var replace_regex = new RegExp(replace_text, "g");
            var node = grp.jQuery(this),
                node_id = node.attr('id'),
                node_name = node.attr('name'),
                node_for = node.attr('for'),
                node_href = node.attr("href"),
                node_class = node.attr("class");
            if (node_id) { node.attr('id', node_id.replace(replace_regex, replace_with)); }
            if (node_name) { node.attr('name', node_name.replace(replace_regex, replace_with)); }
            if (node_for) { node.attr('for', node_for.replace(replace_regex, replace_with)); }
            if (node_href) { node.attr('href', node_href.replace(replace_regex, replace_with)); }
            if (node_class) { node.attr('class', node_class.replace(replace_regex, replace_with)); }
        });

        // Fix parent div's id which does not have a dash (e.g. elecdata_set0)
        var old_id = replace_text.replace('-',''),
            new_id = replace_with.replace('-','')
            div_id = elem.attr('id');
        elem.attr('id', div_id.replace(old_id, new_id));
    },
    updateSelectBoxCache: function(inline_div, selector) {
        var box = inline_div.find(selector),
            id = box.attr('id');
        SelectBox.cache[id] = new Array();
        var cache = SelectBox.cache[id];
        box.find('option').each(function(){
            //if box(
            //this.selected = 'selected';
            cache.push({value: this.value, text: this.text, displayed: 1});
        });
    }

};
<commit_msg>JS comments cleanup<commit_after>/**
 * Copy Button modeled on Add button features from Django admin and Grappelli inlines.js
 */

var OPELEC = OPELEC || function() {};

OPELEC.inlines = {

    copy: function(copy_anchor) {
        // Get stacked inline container from copy button that was clicked
        var inline = grp.jQuery(copy_anchor).closest('div'),
            inlines_div = grp.jQuery(copy_anchor).closest('.grp-group'),
            prefix = OPELEC.inlines.getFormPrefix(inlines_div),
            empty_template = inlines_div.find("#" + prefix + "-empty"),
            meta = OPELEC.inlines.getInlinesAndFormMeta(inlines_div);

        var inline_copy = inline.clone();

        // Fix h3 text
        var header = inline_copy.find('h3');
        var new_header = header.text().split(/\d{4}/)[0].trim();
        header.text(new_header);

        var orig_idx = parseInt(inline_copy.attr('id').split(prefix)[1], 10),
            new_idx = meta.totalFormsCount,
            to_replace = prefix + '-' + orig_idx,
            replacement = prefix + '-' + new_idx;

        // Update index in form ids
        OPELEC.inlines.updateFormIndexes(inline_copy, to_replace, replacement);

        // Remove the ID value copied from prior record (this corresponds to db primary key)
        inline_copy.find('#id_' + prefix + '-' + new_idx + '-id').removeAttr('value');

        // Remove delete button input tag and change inline class to remove button
        // handler (this matches behavior of Add button)
        var opts = OPELEC.inlines.opts();
        inline_copy.find('#id_' + prefix + '-' + new_idx + '-DELETE').remove();
        inline_copy.find('.' + opts.deleteCssClass)
                   .removeClass(opts.deleteCssClass)
                   .addClass(opts.removeCssClass);

        // Update Total Forms count
        meta.totalForms.val(meta.totalFormsCount + 1);

        // Insert inline into DOM
        inline_copy.insertBefore(empty_template);

        OPELEC.inlines.onAfterCopied(inline_copy, prefix, opts);
    },
    opts: function() {
        return {
            prefix: "form",                         // The form prefix for your django formset
            addText: "add another",                 // Text for the add link
            deleteText: "remove",                   // Text for the delete link
            addCssClass: "grp-add-handler",             // CSS class applied to the add link
            copyCssClass: "grp-copy-handler",
            removeCssClass: "grp-remove-handler",       // CSS class applied to the remove link
            deleteCssClass: "grp-delete-handler",       // CSS class applied to the delete link
            emptyCssClass: "grp-empty-form",            // CSS class applied to the empty row
            formCssClass: "grp-dynamic-form",           // CSS class applied to each form in a formset
            predeleteCssClass: "grp-predelete"
        };
    },
    onAfterCopied: function(inline_copy, prefix, opts) {
        // Re-init some grappelli initializers and edge-case handling
        // datepicker (explained below)
        grappelli.updateSelectFilter(inline_copy);

        var date_opts = {
            //appendText: '(mm/dd/yyyy)',
            showOn: 'button',
            buttonImageOnly: false,
            buttonText: '',
            dateFormat: grappelli.getFormat('date'),
            showButtonPanel: true,
            showAnim: '',
            // HACK: sets the current instance to a global var.
            // needed to actually select today if the today-button is clicked.
            // see onClick handler for ".ui-datepicker-current"
            beforeShow: function(year, month, inst) {
                grappelli.datepicker_instance = this;
            }
        };
        // Reinitialize datepicker, due to issue described here:
        // http://stackoverflow.com/questions/2441061/problem-when-cloning-jquery-ui-datepicker
        var dateFields = inline_copy.find('.vDateField');
        dateFields.removeClass('hasDatepicker')
                  .removeData('datepicker')
                  .unbind()
                  .datepicker(date_opts);
        dateFields.each(function() {
            var buttons = grp.jQuery(this).siblings('.ui-datepicker-trigger');
            if (buttons.length > 1) {
                buttons.eq(1).remove();
            };
        });
        inline_copy.grp_collapsible();
        inline_copy.find('.grp-collapse').grp_collapsible();

        // Re-init remove handler
        OPELEC.inlines.removeButtonHandler(inline_copy.find("a." + opts.removeCssClass), prefix, opts);

        // Add "available" and "chosen" options to SelectBox cache
        OPELEC.inlines.updateSelectBoxCache(inline_copy, 'select[id^="id_"][id$="_from"]');
        OPELEC.inlines.updateSelectBoxCache(inline_copy, 'select[id^="id_"][id$="_to"]');

        // Re-init SelectBox selections (which lose the attribute on clone)
        inline_copy.find('.selector-chosen option').each(function() {
            this.selected = 'selected';
        });

        // Re-initialize copy handler
        inline_copy.find('a.' + opts.copyCssClass).click(function(e) {
            var target = e.target;
            var target = (e.target) ? e.target : e.srcElement;
            OPELEC.inlines.copy(target);
        });
    },
    removeButtonHandler: function(elem, prefix, options) {
        elem.bind("click", function() {
            var inline = elem.parents(".grp-group"),
                form = grp.jQuery(this).parents("." + options.formCssClass).first(),
                totalForms = inline.find("#id_" + prefix + "-TOTAL_FORMS"),
                maxForms = inline.find("#id_" + prefix + "-MAX_NUM_FORMS");
            // remove form
            form.remove();
            // update total forms
            var index = parseInt(totalForms.val(), 10);
            totalForms.val(index - 1);
            // show add button in case we've dropped below max
            if ((maxForms.val() !== 0) && (maxForms.val() - totalForms.val()) > 0) {
                showAddButtons(inline, options);
            }
            // update form index (for all forms)
            var re = /-\d+-/g,
                i = 0;
            inline.find("." + options.formCssClass).each(function() {
                updateFormIndex(grp.jQuery(this), options, re, "-" + i + "-");
                i++;
            });
        });
    },
    showAddButtons: function(elem, options) {
        var addButtons = elem.find("a." + options.addCssClass);
        addButtons.show().parents('.grp-add-item').show();
    },
    getInlinesAndFormMeta: function(inlines_div) {
        var prefix = OPELEC.inlines.getFormPrefix(inlines_div);
        var inlines = inlines_div.find(".grp-items");
        var totalForms = inlines_div.find("#id_" + prefix + "-TOTAL_FORMS");
        var maxForms = inlines_div.find("#id_" + prefix + "-MAX_NUM_FORMS");

        return {
            'inlines':inlines,
            'totalForms':totalForms,
            'totalFormsCount':parseInt(totalForms.val(), 10),
            'maxForms':maxForms,
            'maxFormsCount':parseInt(maxForms.val(), 10)
       };
    },
    getFormPrefix: function(inlines_div) {
        return inlines_div[0].id.split('-')[0];
    },
    updateFormIndexes: function(elem, replace_text, replace_with) {
        elem.find(':input,span,table,iframe,label,a,ul,p,img,div').each(function() {
            var replace_regex = new RegExp(replace_text, "g");
            var node = grp.jQuery(this),
                node_id = node.attr('id'),
                node_name = node.attr('name'),
                node_for = node.attr('for'),
                node_href = node.attr("href"),
                node_class = node.attr("class");
            if (node_id) { node.attr('id', node_id.replace(replace_regex, replace_with)); }
            if (node_name) { node.attr('name', node_name.replace(replace_regex, replace_with)); }
            if (node_for) { node.attr('for', node_for.replace(replace_regex, replace_with)); }
            if (node_href) { node.attr('href', node_href.replace(replace_regex, replace_with)); }
            if (node_class) { node.attr('class', node_class.replace(replace_regex, replace_with)); }
        });

        // Fix parent div's id which does not have a dash (e.g. elecdata_set0)
        var old_id = replace_text.replace('-',''),
            new_id = replace_with.replace('-','')
            div_id = elem.attr('id');
        elem.attr('id', div_id.replace(old_id, new_id));
    },
    updateSelectBoxCache: function(inline_div, selector) {
        var box = inline_div.find(selector),
            id = box.attr('id');
        SelectBox.cache[id] = new Array();
        var cache = SelectBox.cache[id];
        box.find('option').each(function(){
            cache.push({value: this.value, text: this.text, displayed: 1});
        });
    }

};
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2020 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * 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
 *
 *      http://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.
 */

const crypto = require('crypto');

/**
 * get a constraint name for tables in JHipster preferred style after applying any length limits required.
 *
 * @param {string} entityName - name of the entity
 * @param {string} columnOrRelationName - name of the column or related entity
 * @param {object} options
 * @param {boolean} options.noSnakeCase - do not convert names to snakecase
 * @param {string} options.prefix
 * @param {string} options.separator
 * @param {boolean} options.appendHash - adds a calculated hash based on entityName and columnOrRelationName to prevent trimming conflict.
 */
function calculateDbNameWithLimit(entityName, columnOrRelationName, limit, options) {
    const { noSnakeCase, prefix, separator, appendHash } = options;
    const halfLimit = Math.floor(limit / 2);
    const suffix = !appendHash
        ? ''
        : `_${crypto.createHash('shake256', { outputLength: 1 }).update(`${entityName}.${columnOrRelationName}`, 'utf8').digest('hex')}`;

    let entityTable = noSnakeCase ? entityName : this.getTableName(entityName);
    let otherTable = noSnakeCase ? columnOrRelationName : this.getTableName(columnOrRelationName);

    entityTable = entityTable.substring(0, halfLimit - (!appendHash ? 0 : separator.length));
    otherTable = otherTable.substring(0, limit - entityTable.length - separator.length - prefix.length - suffix.length);

    return `${prefix}${entityTable}${separator}${otherTable}${suffix}`;
}

module.exports = { calculateDbNameWithLimit };
<commit_msg>Improve api of calculateDbNameWithLimit.<commit_after>/**
 * Copyright 2013-2020 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * 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
 *
 *      http://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.
 */

const crypto = require('crypto');

/**
 * get for tables/constraints in JHipster preferred style after applying any length limits required.
 *
 * @param {string} tableOrEntityName - name of the table or entity
 * @param {string} columnOrRelationshipName - name of the column or relationship
 * @param {number} limit - max length of the returned db reference name
 * @param {object} [options]
 * @param {boolean} [options.noSnakeCase = false] - do not convert names to snakecase
 * @param {string} [options.prefix = '']
 * @param {string} [options.separator = '__']
 * @param {boolean} [options.appendHash = true] - adds a calculated hash based on tableOrEntityName and columnOrRelationshipName to prevent trimming conflict.
 * @return {string} db referente name
 */
function calculateDbNameWithLimit(tableOrEntityName, columnOrRelationshipName, limit, options = {}) {
    const { noSnakeCase = false, prefix = '', separator = '__', appendHash = true } = options;
    const halfLimit = Math.floor(limit / 2);
    const suffix = !appendHash
        ? ''
        : `_${crypto
              .createHash('shake256', { outputLength: 1 })
              .update(`${tableOrEntityName}.${columnOrRelationshipName}`, 'utf8')
              .digest('hex')}`;

    let formattedName = noSnakeCase ? tableOrEntityName : this.getTableName(tableOrEntityName);
    formattedName = formattedName.substring(0, halfLimit - (!appendHash ? 0 : separator.length));

    let otherFormattedName = noSnakeCase ? columnOrRelationshipName : this.getTableName(columnOrRelationshipName);
    otherFormattedName = otherFormattedName.substring(0, limit - formattedName.length - separator.length - prefix.length - suffix.length);

    return `${prefix}${formattedName}${separator}${otherFormattedName}${suffix}`;
}

module.exports = { calculateDbNameWithLimit };
<|endoftext|>


<commit_before>
var React = require('react-native');
var CameraRollView = require('./CameraRollView.ios.js');

var styles = require('../../../styles.js');

var { TouchableOpacity, View, Image, } = React;

var CameraRoll = React.createClass({

  render: function() {
    return (
      <View style={{ width: require('Dimensions').get('window').width }}>
        <CameraRollView
          ref='cameraRollView'
          batchSize={4}
          groupTypes='SavedPhotos'
          renderImage={this._renderImage}
        />
      </View>
    );
  },

  _renderImage: function(asset) {
    return (
      <TouchableOpacity onPress={()=>{this._handleSelection(asset)}}>
          <Image
            source={asset.node.image}
            style={[styles.image, { borderWidth: 10, borderColor: 'white', alignSelf: 'center' }]}
          />
      </TouchableOpacity>
    );
  },

  _handleSelection: function(asset){
    this.props.route.selectImage(asset);
    this.props.navigator.pop();
  }

});

module.exports = CameraRoll;
<commit_msg>camera roll/ cleaned component. Moved styles to styles.js.<commit_after>
var React = require('react-native');

/* ------ Components ------- */

var CameraRollView = require('./CameraRollView.ios.js');

/* ------ Configs ------- */

var styles = require('../../../styles.js');

/* ------ Destructuring Block ------- */

var {
	TouchableOpacity,
	View,
	Image,
} = React;

/* ------ Main Component ------- */

var CameraRoll = React.createClass({

  render: function() {
    return (
      <View style={{ width: require('Dimensions').get('window').width }}>
        <CameraRollView
          ref='cameraRollView'
          batchSize={4}
          groupTypes='SavedPhotos'
          renderImage={this._renderImage}
        />
      </View>
    );
  },

  _renderImage: function(asset) {
    return (
      <TouchableOpacity onPress={()=>{this._handleSelection(asset)}}>
          <Image
            source={asset.node.image}
            style={[styles.image, styles.imagePreview]}
          />
      </TouchableOpacity>
    );
  },

  _handleSelection: function(asset){
    this.props.route.selectImage(asset);
    this.props.navigator.pop();
  }

});

module.exports = CameraRoll;
<|endoftext|>


<commit_before>/**
 * @copyright Copyright 2014 Google Inc. All rights reserved.
 *
 * 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
 *
 *     http://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.
 *
 * @fileoverview Service for the configuration of the Explorer app.
 *
 * The initial settings are loaded from a global let INITIAL_CONFIG.  This
 * is set by the server-side templates when rendering the page, to minimize
 * initial roundtrips. For tests, INITIAL_CONFIG is set in the test/globals.js
 * file.
 *
 * @author joemu@google.com (Joe Allan Muharsky)
 */

goog.provide('p3rf.perfkit.explorer.components.config.ConfigService');

goog.require('p3rf.perfkit.explorer.components.error.ErrorService');
goog.require('p3rf.perfkit.explorer.components.error.ErrorTypes');

goog.scope(function() {
const explorer = p3rf.perfkit.explorer;
const ErrorService = explorer.components.error.ErrorService;
const ErrorTypes = explorer.components.error.ErrorTypes;

/**
 * Service that provides model access for the Explorer page at the top-level.
 * @param {!angular.HttpService} $http
 * @param {!angular.LocationService} $location
 * @constructor
 * @ngInject
 */
explorer.components.config.ConfigService = function($http, $location,
    errorService) {
  var INITIAL_CONFIG = goog.global['INITIAL_CONFIG'];

  /** @private {!angular.HttpService} */
  this.http_ = $http;

  /** @private {!angular.LocationService} */
  this.location_ = location;

  /** @private {!ErrorService} */
  this.errorSvc_ = errorService;

  /** @export {string} */
  this.default_project = INITIAL_CONFIG.default_project;

  /** @export {string} */
  this.default_dataset = INITIAL_CONFIG.default_dataset;

  /** @export {string} */
  this.default_table = INITIAL_CONFIG.default_table;

  /** @export {string} */
  this.analytics_key = INITIAL_CONFIG.analytics_key;

  /** @export {number} */
  this.cache_duration = INITIAL_CONFIG.cache_duration;

  /** @export {number} */
  this.max_parallel_queries = INITIAL_CONFIG.max_parallel_queries;

  /** @export {boolean} */
  this.grant_view_to_public = INITIAL_CONFIG.grant_view_to_public;

  /** @export {boolean} */
  this.grant_save_to_public = INITIAL_CONFIG.grant_save_to_public;

  /** @export {boolean} */
  this.grant_query_to_public = INITIAL_CONFIG.grant_query_to_public;
};
const ConfigService = explorer.components.config.ConfigService;

/**
 * Sets properties based on the JSON data received.
 *
 * @param {!Object} data A JSON object containing config data.
 */
ConfigService.prototype.populate = function(data) {
  if (goog.isDef(data.default_project)) {
    this.default_project = data.default_project;
  }

  if (goog.isDef(data.default_dataset)) {
    this.default_dataset = data.default_dataset;
  }

  if (goog.isDef(data.default_table)) {
    this.default_table = data.default_table;
  }

  if (goog.isDef(data.analytics_key)) {
    this.analytics_key = data.analytics_key;
  }

  if (goog.isDef(data.cache_duration)) {
    this.cache_duration = data.cache_duration;
  }

  if (goog.isDef(data.max_parallel_queries)) {
    this.max_parallel_queries = data.max_parallel_queries;
  }

  if (goog.isDef(data.grant_view_to_public)) {
    this.grant_view_to_public = data.grant_view_to_public;
  }

  if (goog.isDef(data.grant_save_to_public)) {
    this.grant_save_to_public = data.grant_save_to_public;
  }

  if (goog.isDef(data.grant_query_to_public)) {
    this.grant_query_to_public = data.grant_query_to_public;
  }
};

/**
 * Returns basic configuration for use in tests.
 *
 * It only contains values that are expected to be set to non-default
 * values for typical dashboards. Other values that can remain as
 * defaults should not be included here.
 *
 * The returned object is a fresh copy, so the caller may modify
 * values as needed.
 *
 * @return {!object} A JSON object containing config data.
 */
ConfigService.prototype.getConfigForTesting = function() {
  return goog.object.clone({
    'default_project': 'TEST_PROJECT',
    'default_dataset': 'TEST_DATASET',
    'default_table': 'TEST_TABLE',
    'analytics_key': 'TEST_ANALYTICS_KEY'
  });
};

/**
 * Provides a copy of the object as JSON.
 *
 * @param {?Object} data An object that the properties will be applied to.
 * @return {!Object} A JSON representation of the config properties.
 */
ConfigService.prototype.toJSON = function(data) {
  let result = data || {};

  result.default_project = this.default_project;
  result.default_dataset = this.default_dataset;
  result.default_table = this.default_table;
  result.analytics_key = this.analytics_key;
  result.cache_duration = this.cache_duration;
  result.max_parallel_queries = this.max_parallel_queries;
  result.grant_view_to_public = this.grant_view_to_public;
  result.grant_save_to_public = this.grant_save_to_public;
  result.grant_query_to_public = this.grant_query_to_public;

  return result;
};

/**
 * Reloads the global config from the server.
 */
ConfigService.prototype.refresh = function() {
  let promise = this.http_.get('/config');

  promise.then(
      angular.bind(this, function(config) {
        this.populate(config.data);
      })
  );
};

/**
 * Updates the global config on the server.
 */
ConfigService.prototype.update = function() {
  let promise = this.http_.post('/config', this.toJSON());

  promise.then(angular.bind(this, function() {
    this.errorSvc_.addError(ErrorTypes.INFO, 'Global config updated.');
  }));
};

});  // goog.scope
<commit_msg>ConfigService.toJSON: remove optional parameter<commit_after>/**
 * @copyright Copyright 2014 Google Inc. All rights reserved.
 *
 * 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
 *
 *     http://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.
 *
 * @fileoverview Service for the configuration of the Explorer app.
 *
 * The initial settings are loaded from a global let INITIAL_CONFIG.  This
 * is set by the server-side templates when rendering the page, to minimize
 * initial roundtrips. For tests, INITIAL_CONFIG is set in the test/globals.js
 * file.
 *
 * @author joemu@google.com (Joe Allan Muharsky)
 */

goog.provide('p3rf.perfkit.explorer.components.config.ConfigService');

goog.require('p3rf.perfkit.explorer.components.error.ErrorService');
goog.require('p3rf.perfkit.explorer.components.error.ErrorTypes');

goog.scope(function() {
const explorer = p3rf.perfkit.explorer;
const ErrorService = explorer.components.error.ErrorService;
const ErrorTypes = explorer.components.error.ErrorTypes;

/**
 * Service that provides model access for the Explorer page at the top-level.
 * @param {!angular.HttpService} $http
 * @param {!angular.LocationService} $location
 * @constructor
 * @ngInject
 */
explorer.components.config.ConfigService = function($http, $location,
    errorService) {
  var INITIAL_CONFIG = goog.global['INITIAL_CONFIG'];

  /** @private {!angular.HttpService} */
  this.http_ = $http;

  /** @private {!angular.LocationService} */
  this.location_ = location;

  /** @private {!ErrorService} */
  this.errorSvc_ = errorService;

  /** @export {string} */
  this.default_project = INITIAL_CONFIG.default_project;

  /** @export {string} */
  this.default_dataset = INITIAL_CONFIG.default_dataset;

  /** @export {string} */
  this.default_table = INITIAL_CONFIG.default_table;

  /** @export {string} */
  this.analytics_key = INITIAL_CONFIG.analytics_key;

  /** @export {number} */
  this.cache_duration = INITIAL_CONFIG.cache_duration;

  /** @export {number} */
  this.max_parallel_queries = INITIAL_CONFIG.max_parallel_queries;

  /** @export {boolean} */
  this.grant_view_to_public = INITIAL_CONFIG.grant_view_to_public;

  /** @export {boolean} */
  this.grant_save_to_public = INITIAL_CONFIG.grant_save_to_public;

  /** @export {boolean} */
  this.grant_query_to_public = INITIAL_CONFIG.grant_query_to_public;
};
const ConfigService = explorer.components.config.ConfigService;

/**
 * Sets properties based on the JSON data received.
 *
 * @param {!Object} data A JSON object containing config data.
 */
ConfigService.prototype.populate = function(data) {
  if (goog.isDef(data.default_project)) {
    this.default_project = data.default_project;
  }

  if (goog.isDef(data.default_dataset)) {
    this.default_dataset = data.default_dataset;
  }

  if (goog.isDef(data.default_table)) {
    this.default_table = data.default_table;
  }

  if (goog.isDef(data.analytics_key)) {
    this.analytics_key = data.analytics_key;
  }

  if (goog.isDef(data.cache_duration)) {
    this.cache_duration = data.cache_duration;
  }

  if (goog.isDef(data.max_parallel_queries)) {
    this.max_parallel_queries = data.max_parallel_queries;
  }

  if (goog.isDef(data.grant_view_to_public)) {
    this.grant_view_to_public = data.grant_view_to_public;
  }

  if (goog.isDef(data.grant_save_to_public)) {
    this.grant_save_to_public = data.grant_save_to_public;
  }

  if (goog.isDef(data.grant_query_to_public)) {
    this.grant_query_to_public = data.grant_query_to_public;
  }
};

/**
 * Returns basic configuration for use in tests.
 *
 * It only contains values that are expected to be set to non-default
 * values for typical dashboards. Other values that can remain as
 * defaults should not be included here.
 *
 * The returned object is a fresh copy, so the caller may modify
 * values as needed.
 *
 * @return {!object} A JSON object containing config data.
 */
ConfigService.prototype.getConfigForTesting = function() {
  return goog.object.clone({
    'default_project': 'TEST_PROJECT',
    'default_dataset': 'TEST_DATASET',
    'default_table': 'TEST_TABLE',
    'analytics_key': 'TEST_ANALYTICS_KEY'
  });
};

/**
 * Provides a copy of the object as JSON.
 *
 * @return {!Object} A JSON representation of the config properties.
 */
ConfigService.prototype.toJSON = function() {
  let result = {};

  result.default_project = this.default_project;
  result.default_dataset = this.default_dataset;
  result.default_table = this.default_table;
  result.analytics_key = this.analytics_key;
  result.cache_duration = this.cache_duration;
  result.max_parallel_queries = this.max_parallel_queries;
  result.grant_view_to_public = this.grant_view_to_public;
  result.grant_save_to_public = this.grant_save_to_public;
  result.grant_query_to_public = this.grant_query_to_public;

  return result;
};

/**
 * Reloads the global config from the server.
 */
ConfigService.prototype.refresh = function() {
  let promise = this.http_.get('/config');

  promise.then(
      angular.bind(this, function(config) {
        this.populate(config.data);
      })
  );
};

/**
 * Updates the global config on the server.
 */
ConfigService.prototype.update = function() {
  let promise = this.http_.post('/config', this.toJSON());

  promise.then(angular.bind(this, function() {
    this.errorSvc_.addError(ErrorTypes.INFO, 'Global config updated.');
  }));
};

});  // goog.scope
<|endoftext|>


<commit_before>"use strict";

define(['js/PanelBase/PanelBaseWithHeader',
    'js/PanelManager/IActivePanel',
    'js/Widgets/GraphViz/GraphVizWidget',
    './GraphVizPanelControl'], function (PanelBaseWithHeader,
                                         IActivePanel,
                                            GraphVizWidget,
                                            GraphVizPanelControl) {

    var GraphVizPanel;

    GraphVizPanel = function (layoutManager, params) {
        var options = {};
        //set properties from options
        options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = "GraphVizPanel";
        options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;

        //call parent's constructor
        PanelBaseWithHeader.apply(this, [options, layoutManager]);

        this._client = params.client;

        //initialize UI
        this._initialize();

        this.logger.debug("GraphVizPanel ctor finished");
    };

    //inherit from PanelBaseWithHeader
    _.extend(GraphVizPanel.prototype, PanelBaseWithHeader.prototype);
    _.extend(GraphVizPanel.prototype, IActivePanel.prototype);

    GraphVizPanel.prototype._initialize = function () {
        var self = this;

        //set Widget title
        this.setTitle("Graph visualizer");

        this.widget = new GraphVizWidget(this.$el);

        this.widget.setTitle = function (title) {
            self.setTitle(title);
        };

        this.control = new GraphVizPanelControl({"client": this._client,
            "widget": this.widget});

        this.onActivate();
    };

    /* OVERRIDE FROM WIDGET-WITH-HEADER */
    /* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
    GraphVizPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
        //apply parent's onReadOnlyChanged
        PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);

        //this._graphVizWidget.setReadOnly(isReadOnly);
    };

    GraphVizPanel.prototype.onResize = function (width, height) {
        this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
        this.widget.onWidgetContainerResize(width, height);
    };

    GraphVizPanel.prototype.destroy = function () {
        this.control.destroy();
        this.widget.destroy();

        PanelBaseWithHeader.prototype.destroy.call(this);
        WebGMEGlobal.KeyboardManager.setListener(undefined);
        WebGMEGlobal.Toolbar.refresh();
    };

    GraphVizPanel.prototype.onActivate = function () {
        this.widget.onActivate();
        this.control.onActivate();
        WebGMEGlobal.KeyboardManager.setListener(this.widget);
        WebGMEGlobal.Toolbar.refresh();
    };

    GraphVizPanel.prototype.onDeactivate = function () {
        this.widget.onDeactivate();
        this.control.onDeactivate();
        WebGMEGlobal.KeyboardManager.setListener(undefined);
        WebGMEGlobal.Toolbar.refresh();
    };

    return GraphVizPanel;
});
<commit_msg>set empty title on load<commit_after>"use strict";

define(['js/PanelBase/PanelBaseWithHeader',
    'js/PanelManager/IActivePanel',
    'js/Widgets/GraphViz/GraphVizWidget',
    './GraphVizPanelControl'], function (PanelBaseWithHeader,
                                         IActivePanel,
                                            GraphVizWidget,
                                            GraphVizPanelControl) {

    var GraphVizPanel;

    GraphVizPanel = function (layoutManager, params) {
        var options = {};
        //set properties from options
        options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = "GraphVizPanel";
        options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;

        //call parent's constructor
        PanelBaseWithHeader.apply(this, [options, layoutManager]);

        this._client = params.client;

        //initialize UI
        this._initialize();

        this.logger.debug("GraphVizPanel ctor finished");
    };

    //inherit from PanelBaseWithHeader
    _.extend(GraphVizPanel.prototype, PanelBaseWithHeader.prototype);
    _.extend(GraphVizPanel.prototype, IActivePanel.prototype);

    GraphVizPanel.prototype._initialize = function () {
        var self = this;

        //set Widget title
        this.setTitle("");

        this.widget = new GraphVizWidget(this.$el);

        this.widget.setTitle = function (title) {
            self.setTitle(title);
        };

        this.control = new GraphVizPanelControl({"client": this._client,
            "widget": this.widget});

        this.onActivate();
    };

    /* OVERRIDE FROM WIDGET-WITH-HEADER */
    /* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
    GraphVizPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
        //apply parent's onReadOnlyChanged
        PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);

        //this._graphVizWidget.setReadOnly(isReadOnly);
    };

    GraphVizPanel.prototype.onResize = function (width, height) {
        this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
        this.widget.onWidgetContainerResize(width, height);
    };

    GraphVizPanel.prototype.destroy = function () {
        this.control.destroy();
        this.widget.destroy();

        PanelBaseWithHeader.prototype.destroy.call(this);
        WebGMEGlobal.KeyboardManager.setListener(undefined);
        WebGMEGlobal.Toolbar.refresh();
    };

    GraphVizPanel.prototype.onActivate = function () {
        this.widget.onActivate();
        this.control.onActivate();
        WebGMEGlobal.KeyboardManager.setListener(this.widget);
        WebGMEGlobal.Toolbar.refresh();
    };

    GraphVizPanel.prototype.onDeactivate = function () {
        this.widget.onDeactivate();
        this.control.onDeactivate();
        WebGMEGlobal.KeyboardManager.setListener(undefined);
        WebGMEGlobal.Toolbar.refresh();
    };

    return GraphVizPanel;
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { VOTING_NOT_STARTED, VOTING_IN_PROGRESS, VOTING_FINISHED } from 'common/actionTypes/issues';
import {
  adminCloseIssue,
  adminDeleteIssue,
  enableVoting,
  disableVoting,
} from 'features/adminButtons/actionCreators';
import { getIssueText, activeIssueExists, getIssue, getIssueKey } from 'features/issue/selectors';
import Button from '../../Button';
import Card from '../../Card';
import Dialog from '../../Dialog';
import ButtonIconText from '../../ButtonIconText';
import Pin from '../Pin';
import css from './Issue.css';

class Issue extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      redirectToEditIssue: false,
      showCloseIssueDialog: false,
    };
  }

  onClickDeleteIssue() {
    this.setState({ showCloseIssueDialog: true });
  }

  deleteIssue() {
    this.setState({ showCloseIssueDialog: false });
    this.props.deleteIssue();
  }

  votingBtnOnClick() {
    if (this.props.issueStatus === VOTING_NOT_STARTED) {
      this.props.enableVoting();
    } else {
      this.props.disableVoting();
    }
  }

  closeDeleteDialog() {
    this.setState({ showCloseIssueDialog: false });
  }

  render() {
    const {
      closeIssue, issueIsActive, issueStatus, issueText, pin, registrationOpen,
    } = this.props;
    const { showCloseIssueDialog } = this.state;
    const votingInProgress = issueStatus === VOTING_IN_PROGRESS;
    let enableDisableVotingBtnText;
    if (issueStatus === VOTING_NOT_STARTED) enableDisableVotingBtnText = 'Start votering';
    else if (issueStatus === VOTING_IN_PROGRESS) enableDisableVotingBtnText = 'Avslutt votering';
    else enableDisableVotingBtnText = 'Votering er ferdig';
    return (
      <Card classes={css.issue}>
        {this.state.redirectToEditIssue && <Redirect to="/admin/question" />}
        <Dialog
          title="Bekreft sletting av sak"
          subtitle={`Bekreft sletting av "${issueText}"`}
          visible={showCloseIssueDialog}
          onClose={() => this.closeDeleteDialog()}
        >
          <Button background onClick={() => this.deleteIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDeleteDialog()}
          >Avbryt</Button>
        </Dialog>

            <Pin code={registrationOpen ? pin : 'Registreringen er ikke åpen.'} />

Aktiv sak

          {issueIsActive &&

            <ButtonIconText
              text={enableDisableVotingBtnText}
              iconClass={votingInProgress || issueStatus === VOTING_FINISHED
                ? css.lock : css.unlock}
              onClick={() => this.votingBtnOnClick()}
              disabled={this.props.issueStatus === VOTING_FINISHED}
            />
            <ButtonIconText
              text="Rediger"
              iconClass={css.edit}
              onClick={() => { this.setState({ redirectToEditIssue: true }); }}
            />
            <ButtonIconText text="Avslutt" iconClass={css.end} onClick={closeIssue} />
            <ButtonIconText
              text="Slett"
              iconClass={css.delete}
              onClick={() => this.onClickDeleteIssue()}
            />

          }

{issueText}

      </Card>
    );
  }
}

Issue.defaultProps = {
  pin: 0,
  issueStatus: VOTING_NOT_STARTED,
  registrationOpen: false,
};

Issue.propTypes = {
  closeIssue: PropTypes.func.isRequired,
  deleteIssue: PropTypes.func.isRequired,
  disableVoting: PropTypes.func.isRequired,
  enableVoting: PropTypes.func.isRequired,
  issueIsActive: PropTypes.bool.isRequired,
  issueStatus: PropTypes.string,
  issueText: PropTypes.string.isRequired,
  pin: PropTypes.number,
  registrationOpen: PropTypes.bool,
};

const mapStateToProps = state => ({
  issueIsActive: activeIssueExists(state),
  issueStatus: getIssueKey(state, 'status'),
  issueText: getIssueText(state),
  issue: getIssue(state),
  pin: state.meeting.pin,
  registrationOpen: state.meeting.registrationOpen,
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
    deleteIssue: () => {
      dispatch(adminDeleteIssue({ issue: stateProps.issue.id }));
    },
    disableVoting: () => {
      dispatch(disableVoting({ issue: stateProps.issue.id }));
    },
    enableVoting: () => {
      dispatch(enableVoting({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<commit_msg>Added a dialog that pops up when admin wants to close an issue. It should now be more difficult to accidentaly close an issue.<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { VOTING_NOT_STARTED, VOTING_IN_PROGRESS, VOTING_FINISHED } from 'common/actionTypes/issues';
import {
  adminCloseIssue,
  adminDeleteIssue,
  enableVoting,
  disableVoting,
} from 'features/adminButtons/actionCreators';
import { getIssueText, activeIssueExists, getIssue, getIssueKey } from 'features/issue/selectors';
import Button from '../../Button';
import Card from '../../Card';
import Dialog from '../../Dialog';
import ButtonIconText from '../../ButtonIconText';
import Pin from '../Pin';
import css from './Issue.css';

class Issue extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      redirectToEditIssue: false,
      showDeleteIssueDialog: false,
      showCloseIssueDialog: false,
    };
  }

  onClickDeleteIssue() {
    this.setState({ showDeleteIssueDialog: true });
  }

  deleteIssue() {
    this.setState({ showDeleteIssueDialog: false });
    this.props.deleteIssue();
  }

  onClickCloseIssue() {
    this.setState({ showCloseIssueDialog: true });
  }

  closeIssue() {
    this.setState({ showCloseIssueDialog: false });
    this.props.closeIssue();
  }

  votingBtnOnClick() {
    if (this.props.issueStatus === VOTING_NOT_STARTED) {
      this.props.enableVoting();
    } else {
      this.props.disableVoting();
    }
  }

  closeDeleteDialog() {
    this.setState({ showDeleteIssueDialog: false });
  }

  closeCloseDialog() {
    this.setState({ showCloseIssueDialog: false });
  }

  render() {
    const {
      issueIsActive, issueStatus, issueText, pin, registrationOpen,
    } = this.props;
    const { showDeleteIssueDialog, showCloseIssueDialog } = this.state;
    const votingInProgress = issueStatus === VOTING_IN_PROGRESS;
    let enableDisableVotingBtnText;
    if (issueStatus === VOTING_NOT_STARTED) enableDisableVotingBtnText = 'Start votering';
    else if (issueStatus === VOTING_IN_PROGRESS) enableDisableVotingBtnText = 'Avslutt votering';
    else enableDisableVotingBtnText = 'Votering er ferdig';
    return (
      <Card classes={css.issue}>
        {this.state.redirectToEditIssue && <Redirect to="/admin/question" />}
        <Dialog
          title="Bekreft sletting av sak"
          subtitle={`Bekreft sletting av "${issueText}"`}
          visible={showDeleteIssueDialog}
          onClose={() => this.closeDeleteDialog()}
        >
          <Button background onClick={() => this.deleteIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDeleteDialog()}
          >Avbryt</Button>
        </Dialog>
        <Dialog
          title="Bekreft avslutting av sak"
          subtitle={`Bekreft avslutting av "${issueText}"`}
          visible={showCloseIssueDialog}
          onClose={() => this.closeCloseDialog()}
        >
          <Button background onClick={() => this.closeIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeCloseDialog()}
          >Avbryt</Button>
        </Dialog>

            <Pin code={registrationOpen ? pin : 'Registreringen er ikke åpen.'} />

Aktiv sak

          {issueIsActive &&

            <ButtonIconText
              text={enableDisableVotingBtnText}
              iconClass={votingInProgress || issueStatus === VOTING_FINISHED
                ? css.lock : css.unlock}
              onClick={() => this.votingBtnOnClick()}
              disabled={this.props.issueStatus === VOTING_FINISHED}
            />
            <ButtonIconText
              text="Rediger"
              iconClass={css.edit}
              onClick={() => { this.setState({ redirectToEditIssue: true }); }}
            />
            <ButtonIconText text="Avslutt" iconClass={css.end} onClick={() => this.onClickCloseIssue()} />
            <ButtonIconText
              text="Slett"
              iconClass={css.delete}
              onClick={() => this.onClickDeleteIssue()}
            />

          }

{issueText}

      </Card>
    );
  }
}

Issue.defaultProps = {
  pin: 0,
  issueStatus: VOTING_NOT_STARTED,
  registrationOpen: false,
};

Issue.propTypes = {
  closeIssue: PropTypes.func.isRequired,
  deleteIssue: PropTypes.func.isRequired,
  disableVoting: PropTypes.func.isRequired,
  enableVoting: PropTypes.func.isRequired,
  issueIsActive: PropTypes.bool.isRequired,
  issueStatus: PropTypes.string,
  issueText: PropTypes.string.isRequired,
  pin: PropTypes.number,
  registrationOpen: PropTypes.bool,
};

const mapStateToProps = state => ({
  issueIsActive: activeIssueExists(state),
  issueStatus: getIssueKey(state, 'status'),
  issueText: getIssueText(state),
  issue: getIssue(state),
  pin: state.meeting.pin,
  registrationOpen: state.meeting.registrationOpen,
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
    deleteIssue: () => {
      dispatch(adminDeleteIssue({ issue: stateProps.issue.id }));
    },
    disableVoting: () => {
      dispatch(disableVoting({ issue: stateProps.issue.id }));
    },
    enableVoting: () => {
      dispatch(enableVoting({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<|endoftext|>


<commit_before>import React from "react";
import { filter } from "lodash";
import { connect } from "react-redux";
import { ClipLoader } from "halogenium";
import { Row, Col, Panel, ListGroup } from "react-bootstrap";

import { getSoftwareUpdates, showInstallModal } from "../actions";
import { updateSetting } from "../../settings/actions";
import { Button, Checkbox, Icon, InputSave } from "../../base";
import { versionComparator } from "../../utils";
import Release from "./Release";
import InstallModal from "./Install";

class SoftwareUpdateViewer extends React.Component {

    constructor (props) {
        super(props);
    }

    componentWillMount () {
        this.props.onGet();
    }

    render () {

        if (this.props.updates === null) {
            return (

                    <ClipLoader color="#3c8786" size="24px" />

            );
        }

        console.log(this.props.updates);

        const currentVersion = this.props.updates.current_version;

        const releases = filter(this.props.updates.releases, release => {
            return versionComparator(release.name, currentVersion) === 1;
        });

        let installModal;
        let updateComponent;

        if (releases.length) {
            const releaseComponents = releases.map(release =>
                <Release key={release.name} {...release} />
            );

            installModal = <InstallModal releases={releases} />;

            updateComponent = (
                <Panel>

                            <Icon name="info" /> Update{releases.length === 1 ? "": "s"} Available

                    <ListGroup>
                        {releaseComponents}
                    </ListGroup>

                        <Button icon="download" bsStyle="primary" onClick={this.props.onShowModal}>
                            Install
                        </Button>

                </Panel>
            );
        } else {
            updateComponent = (
                <Panel>
                    <Icon bsStyle="success" name="checkmark" />
                     Software is up-to-date
                </Panel>
            );
        }

        return (

                <Row>
                    <Col xs={12}>

                            Software Updates

                    </Col>
                    <Col xs={12} md={7}>
                        {updateComponent}
                    </Col>
                    <Col xs={12} md={5}>
                        <Panel>
                            <Row>
                                <Col xs={12}>
                                    <InputSave
                                        label="Repository"
                                        initialValue={this.props.softwareRepo}
                                        onSave={(value) => console.log(value)}
                                    />
                                </Col>
                                <Col xs={12}>
                                    <Checkbox label="Ignore pre-releases" checked={true} />
                                </Col>
                            </Row>
                        </Panel>
                    </Col>
                </Row>
                {installModal}

        );
    }
}

const mapStateToProps = (state) => {
    return {
        updates: state.updates.software,
        softwareRepo: state.settings.data.software_repo
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        onGet: () => {
            dispatch(getSoftwareUpdates());
        },

        onUpdateSoftwareRepo: (value) => {
            dispatch(updateSetting("software_repo", value));
        },

        onShowModal: () => {
            dispatch(showInstallModal());
        }
    };
};

const Container = connect(mapStateToProps, mapDispatchToProps)(SoftwareUpdateViewer);

export default Container;
<commit_msg>Update software releases view<commit_after>import React from "react";
import { capitalize, filter, toNumber } from "lodash";
import { connect } from "react-redux";
import { ClipLoader } from "halogenium";
import { Row, Col, Panel, ListGroup } from "react-bootstrap";

import { getSoftwareUpdates, showInstallModal } from "../actions";
import { updateSetting } from "../../settings/actions";
import { Button, Icon, Radio } from "../../base";
import Release from "./Release";
import InstallModal from "./Install";

class SoftwareUpdateViewer extends React.Component {

    constructor (props) {
        super(props);
    }

    componentWillMount () {
        this.props.onGet();
    }

    render () {

        if (this.props.updates === null) {
            return (

                    <ClipLoader color="#3c8786" size="24px" />

            );
        }

        const currentVersion = this.props.updates.current_version;

        let [ currentNumber, currentPre ] = currentVersion.replace("v", "").split("-").map(part =>
            part.split(".").map(toNumber)
        );

        const releases = filter(this.props.updates.releases, release => {
            const [ number, pre ] = release.name.replace("v", "").split("-").map(part => part.split("."));

            if (currentNumber[0] > number[0] || currentNumber[1] > number[1] || currentNumber[2] > number[2]) {
                return false;
            }

            // Reject if release is a pre-release, but current one isn't.
            if (!currentPre && pre) {
                return false;
            }

            // Reject if the release is alpha, but current on is beta.
            if (currentPre[0] === "beta" && pre[0] === "alpha") {
                return false;
            }

            return currentPre[1]

                <Release key={release.name} {...release} />
            );

            installModal = <InstallModal releases={releases} />;

            updateComponent = (
                <Panel>

                            <Icon name="info" /> Update{releases.length === 1 ? "": "s"} Available

                    <ListGroup>
                        {releaseComponents}
                    </ListGroup>

                        <Button icon="download" bsStyle="primary" onClick={this.props.onShowModal}>
                            Install
                        </Button>

                </Panel>
            );
        } else {
            updateComponent = (
                <Panel>
                    <Icon bsStyle="success" name="checkmark" />
                     Software is up-to-date
                </Panel>
            );
        }

        const radioComponents = ["stable", "beta", "alpha"].map((channel) =>
            <Radio
                key={channel}
                checked={this.props.channel === channel}
                label={`${capitalize(channel)}${channel === "stable" ? " (recommended)": ""}`}
                onClick={() => this.props.onSetSoftwareChannel(channel)}
            />
        );

        return (

                <Row>
                    <Col xs={12}>

                            Software Updates

                    </Col>
                    <Col xs={12} md={8}>
                        {updateComponent}
                    </Col>
                    <Col xs={12} md={4}>
                        <Panel>
                            <Row>
                                <Col xs={12}>
                                    Software Channel
                                    {radioComponents}
                                </Col>
                            </Row>
                        </Panel>
                    </Col>
                </Row>
                {installModal}

        );
    }
}

const mapStateToProps = (state) => {
    return {
        updates: state.updates.software,
        channel: state.settings.data.software_channel
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        onGet: () => {
            dispatch(getSoftwareUpdates());
        },

        onSetSoftwareChannel: (value) => {
            dispatch(updateSetting("software_channel", value));
        },

        onShowModal: () => {
            dispatch(showInstallModal());
        }
    };
};

const Container = connect(mapStateToProps, mapDispatchToProps)(SoftwareUpdateViewer);

export default Container;
<|endoftext|>


<commit_before>Template.courseSidebar.rendered = function () {
    // Get the template instance
    var instance = Template.instance();

    // Get the current router object
    var controller = Router.current();

    // Get course ID from router object
    var courseID = controller.params._id;
};

Template.courseSidebar.helpers({
    /*
    Return true when editing the active course
    Used to display 'Add section' form
    */
    'editingThisCourse': function () {
        // return true if editing this course
        return (Session.get('editingCourseID') === this._id);
    },
    'sections': function () {
      return Courses.findOne().sections();
    }
});
<commit_msg>Cleanup.<commit_after>Template.courseSidebar.helpers({
    /*
    Return true when editing the active course
    Used to display 'Add section' form
    */
    'editingThisCourse': function () {
        // return true if editing this course
        return (Session.get('editingCourseID') === this._id);
    },
    'sections': function () {
      return Courses.findOne().sections();
    }
});
<|endoftext|>


<commit_before>var Base64 = (function() {

    // private property
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // private method for UTF-8 encoding
    function utf8Encode(string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }

    // public method for encoding
    return {
        encode : (typeof btoa == 'function') ? function(input) { return btoa(input); } : function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = utf8Encode(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                keyStr.charAt(enc3) + keyStr.charAt(enc4);
            }
            return output;
        }
    };
})();

//http://druckit.wordpress.com/2013/10/26/generate-an-excel-file-from-an-ext-js-4-grid/
Ext.define('My.grid.ExcelGridPanel', {
    extend: 'Ext.grid.GridPanel',
    requires: 'Ext.form.action.StandardSubmit',

    /*
        Kick off process
    */

    downloadExcelXml: function(includeHidden, title) {

        if (!title) title = this.title;

        var vExportContent = this.getExcelXml(includeHidden, title);

        var location = 'data:application/vnd.ms-excel;base64,' + Base64.encode(vExportContent);

        /*
          dynamically create and anchor tag to force download with suggested filename
          note: download attribute is Google Chrome specific
        */

        if (Ext.isChrome || Ext.isGecko) { // local download
            var gridEl = this.getEl();

            var el = Ext.DomHelper.append(gridEl, {
                tag: "a",
                download: title + "-" + Ext.Date.format(new Date(), 'Y-m-d Hi') + '.xls',
                href: location
            });

            el.click();

            Ext.fly(el).destroy();

        } else { // remote download

            var form = this.down('form#uploadForm');
            if (form) {
                form.destroy();
            }
            form = this.add({
                xtype: 'form',
                itemId: 'uploadForm',
                hidden: true,
                standardSubmit: true,
                url: 'exportexcel.php',
                items: [{
                    xtype: 'hiddenfield',
                    name: 'ex',
                    value: vExportContent
                }]
            });

            form.getForm().submit();
        }
    },

    /*

        Welcome to XML Hell
        See: http://msdn.microsoft.com/en-us/library/office/aa140066(v=office.10).aspx
        for more details

    */
    getExcelXml: function(includeHidden, title) {

        var theTitle = title || this.title;

        var worksheet = this.createWorksheet(includeHidden, theTitle);
        var totalWidth = this.columns.length;

        return ''.concat(
            '<?xml version="1.0"?>',
            '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">',
            '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Title>' + theTitle + '</Title></DocumentProperties>',
            '<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office"><AllowPNG/></OfficeDocumentSettings>',
            '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">',
            '<WindowHeight>' + worksheet.height + '</WindowHeight>',
            '<WindowWidth>' + worksheet.width + '</WindowWidth>',
            '<ProtectStructure>False</ProtectStructure>',
            '<ProtectWindows>False</ProtectWindows>',
            '</ExcelWorkbook>',

            '<Styles>',

            '<Style ss:ID="Default" ss:Name="Normal">',
            '<Alignment ss:Vertical="Bottom"/>',
            '<Borders/>',
            '<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>',
            '<Interior/>',
            '<NumberFormat/>',
            '<Protection/>',
            '</Style>',

            '<Style ss:ID="title">',
            '<Borders />',
            '<Font ss:Bold="1" ss:Size="18" />',
            '<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1" />',
            '<NumberFormat ss:Format="@" />',
            '</Style>',

            '<Style ss:ID="headercell">',
            '<Font ss:Bold="1" ss:Size="10" />',
            '<Alignment ss:Horizontal="Center" ss:WrapText="1" />',
            '<Interior ss:Color="#A3C9F1" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="even">',
            '<Interior ss:Color="#CCFFFF" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="evendate" ss:Parent="even">',
            '<NumberFormat ss:Format="yyyy-mm-dd" />',
            '</Style>',

            '<Style ss:ID="evenint" ss:Parent="even">',
            '<Numberformat ss:Format="0" />',
            '</Style>',

            '<Style ss:ID="evenfloat" ss:Parent="even">',
            '<Numberformat ss:Format="0.00" />',
            '</Style>',

            '<Style ss:ID="odd">',
            '<Interior ss:Color="#CCCCFF" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="groupSeparator">',
            '<Interior ss:Color="#D3D3D3" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="odddate" ss:Parent="odd">',
            '<NumberFormat ss:Format="yyyy-mm-dd" />',
            '</Style>',

            '<Style ss:ID="oddint" ss:Parent="odd">',
            '<NumberFormat Format="0" />',
            '</Style>',

            '<Style ss:ID="oddfloat" ss:Parent="odd">',
            '<NumberFormat Format="0.00" />',
            '</Style>',

            '</Styles>',
            worksheet.xml,
            '</Workbook>'
        );
    },

    /*

        Support function to return field info from store based on fieldname

    */

    getModelField: function(fieldName) {

        var fields = this.store.model.getFields();
        for (var i = 0; i < fields.length; i++) {
            if (fields[i].name === fieldName) {
                return fields[i];
            }
        }
    },

    /*

        Convert store into Excel Worksheet

    */
    generateEmptyGroupRow: function(dataIndex, value, cellTypes, includeHidden) {

        var cm = this.columns;
        var colCount = this.columns.length;
        var rowTpl = '<Row ss:AutoFitHeight="0"><Cell ss:StyleID="groupSeparator" ss:MergeAcross="{0}"><Data ss:Type="String"><html:b>{1}</html:b></Data></Cell></Row>';
        var visibleCols = 0;

        // rowXml += '<Cell ss:StyleID="groupSeparator">'

        for (var j = 0; j < colCount; j++) {
            if (cm[j].xtype != 'actioncolumn' && (cm[j].dataIndex != '') && (includeHidden || !cm[j].hidden)) {
                // rowXml += '<Cell ss:StyleID="groupSeparator"/>';
                visibleCols++;
            }
        }

        // rowXml += "</Row>";

        return Ext.String.format(rowTpl, visibleCols - 1, value);
    },

    createWorksheet: function(includeHidden, theTitle) {
        // Calculate cell data types and extra class names which affect formatting
    	var cellType = [];
        var cellTypeClass = [];
        var cm = this.columns;
        var totalWidthInPixels = 0;
        var colXml = '';
        var headerXml = '';
        var visibleColumnCountReduction = 0;
        var colCount = cm.length;
        for (var i = 0; i < colCount; i++) {
            if (cm[i].xtype != 'actioncolumn' && (cm[i].dataIndex != '') && (includeHidden || !cm[i].hidden)) {
                var w = cm[i].getEl().getWidth();
                totalWidthInPixels += w;

                if (cm[i].text === "") {
                    cellType.push("None");
                    cellTypeClass.push("");
                    ++visibleColumnCountReduction;
                } else {
                    colXml += '<Column ss:AutoFitWidth="1" ss:Width="' + w + '" />';
                    headerXml += '<Cell ss:StyleID="headercell">' +
                        '<Data ss:Type="String">' + cm[i].text + '</Data>' +
                        '<NamedCell ss:Name="Print_Titles"></NamedCell></Cell>';

                    var fld = this.getModelField(cm[i].dataIndex);
                    switch (fld.type.type) {
                        case "int":
                            cellType.push("Number");
                            cellTypeClass.push("int");
                            break;
                        case "float":
                            cellType.push("Number");
                            cellTypeClass.push("float");
                            break;

                        case "bool":

                        case "boolean":
                            cellType.push("String");
                            cellTypeClass.push("");
                            break;
                        case "date":
                            cellType.push("DateTime");
                            cellTypeClass.push("date");
                            break;
                        default:
                            cellType.push("String");
                            cellTypeClass.push("");
                            break;
                    }
                }
            }
        }
        var visibleColumnCount = cellType.length - visibleColumnCountReduction;

        var result = {
            height: 9000,
            width: Math.floor(totalWidthInPixels * 30) + 50
        };

        // Generate worksheet header details.

        // determine number of rows
        var numGridRows = this.store.getCount() + 2;
        if (!Ext.isEmpty(this.store.groupField)) {
            numGridRows = numGridRows + this.store.getGroups().length;
        }

        // create header for worksheet
        var t = ''.concat(
            '<Worksheet ss:Name="' + theTitle + '">',

            '<Names>',
            '<NamedRange ss:Name="Print_Titles" ss:RefersTo="=\'' + theTitle + '\'!R1:R2">',
            '</NamedRange></Names>',

            '<Table ss:ExpandedColumnCount="' + (visibleColumnCount + 2),
            '" ss:ExpandedRowCount="' + numGridRows + '" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="15">',
            colXml,
            '<Row ss:Height="38">',
            '<Cell ss:MergeAcross="' + (visibleColumnCount - 1) + '" ss:StyleID="title">',
            '<Data ss:Type="String" xmlns:html="http://www.w3.org/TR/REC-html40">',
            '<html:b>' + theTitle + '</html:b></Data><NamedCell ss:Name="Print_Titles">',
            '</NamedCell></Cell>',
            '</Row>',
            '<Row ss:AutoFitHeight="1">',
            headerXml +
            '</Row>'
        );

        // Generate the data rows from the data in the Store
        var groupVal = "";
        for (var i = 0, it = this.store.data.items, l = it.length; i < l; i++) {

            if (!Ext.isEmpty(this.store.groupField)) {
                if (groupVal != this.store.getAt(i).get(this.store.groupField)) {
                    groupVal = this.store.getAt(i).get(this.store.groupField);
                    t += this.generateEmptyGroupRow(this.store.groupField, groupVal, cellType, includeHidden);
                }
            }
            t += '<Row>';
            var cellClass = (i & 1) ? 'odd' : 'even';
            r = it[i].data;
            var k = 0;
            for (var j = 0; j < colCount; j++) {
                if (cm[j].xtype != 'actioncolumn' && (cm[j].dataIndex != '') && (includeHidden || !cm[j].hidden)) {
                    var v = r[cm[j].dataIndex];
                    if (cellType[k] !== "None") {
                        t += '<Cell ss:StyleID="' + cellClass + cellTypeClass[k] + '"><Data ss:Type="' + cellType[k] + '">';
                        if (cellType[k] == 'DateTime') {
                            t += Ext.Date.format(v, 'Y-m-d');
                        } else {
                            t += v;
                        }
                        t += '</Data></Cell>';
                    }
                    k++;
                }
            }
            t += '</Row>';
        }

        result.xml = t.concat(
            '</Table>',
            '<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">',
            '<PageLayoutZoom>0</PageLayoutZoom>',
            '<Selected/>',
            '<Panes>',
            '<Pane>',
            '<Number>3</Number>',
            '<ActiveRow>2</ActiveRow>',
            '</Pane>',
            '</Panes>',
            '<ProtectObjects>False</ProtectObjects>',
            '<ProtectScenarios>False</ProtectScenarios>',
            '</WorksheetOptions>',
            '</Worksheet>'
        );
        return result;
    }
});
<commit_msg>set the worksheet title to just worksheet<commit_after>var Base64 = (function() {

    // private property
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // private method for UTF-8 encoding
    function utf8Encode(string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    }

    // public method for encoding
    return {
        encode : (typeof btoa == 'function') ? function(input) { return btoa(input); } : function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = utf8Encode(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                keyStr.charAt(enc3) + keyStr.charAt(enc4);
            }
            return output;
        }
    };
})();

//http://druckit.wordpress.com/2013/10/26/generate-an-excel-file-from-an-ext-js-4-grid/
Ext.define('My.grid.ExcelGridPanel', {
    extend: 'Ext.grid.GridPanel',
    requires: 'Ext.form.action.StandardSubmit',

    /*
        Kick off process
    */

    downloadExcelXml: function(includeHidden, title) {

        if (!title) title = this.title;

        var vExportContent = this.getExcelXml(includeHidden, title);

        var location = 'data:application/vnd.ms-excel;base64,' + Base64.encode(vExportContent);

        /*
          dynamically create and anchor tag to force download with suggested filename
          note: download attribute is Google Chrome specific
        */

        if (Ext.isChrome || Ext.isGecko) { // local download
            var gridEl = this.getEl();

            var el = Ext.DomHelper.append(gridEl, {
                tag: "a",
                download: title + "-" + Ext.Date.format(new Date(), 'Y-m-d Hi') + '.xls',
                href: location
            });

            el.click();

            Ext.fly(el).destroy();

        } else { // remote download

            var form = this.down('form#uploadForm');
            if (form) {
                form.destroy();
            }
            form = this.add({
                xtype: 'form',
                itemId: 'uploadForm',
                hidden: true,
                standardSubmit: true,
                url: 'exportexcel.php',
                items: [{
                    xtype: 'hiddenfield',
                    name: 'ex',
                    value: vExportContent
                }]
            });

            form.getForm().submit();
        }
    },

    /*

        Welcome to XML Hell
        See: http://msdn.microsoft.com/en-us/library/office/aa140066(v=office.10).aspx
        for more details

    */
    getExcelXml: function(includeHidden, title) {

        //var theTitle = title || this.title;
        var theTitle = 'myworksheet';

        var worksheet = this.createWorksheet(includeHidden, theTitle);
        var totalWidth = this.columns.length;

        return ''.concat(
            '<?xml version="1.0"?>',
            '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">',
            '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Title>' + theTitle + '</Title></DocumentProperties>',
            '<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office"><AllowPNG/></OfficeDocumentSettings>',
            '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">',
            '<WindowHeight>' + worksheet.height + '</WindowHeight>',
            '<WindowWidth>' + worksheet.width + '</WindowWidth>',
            '<ProtectStructure>False</ProtectStructure>',
            '<ProtectWindows>False</ProtectWindows>',
            '</ExcelWorkbook>',

            '<Styles>',

            '<Style ss:ID="Default" ss:Name="Normal">',
            '<Alignment ss:Vertical="Bottom"/>',
            '<Borders/>',
            '<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>',
            '<Interior/>',
            '<NumberFormat/>',
            '<Protection/>',
            '</Style>',

            '<Style ss:ID="title">',
            '<Borders />',
            '<Font ss:Bold="1" ss:Size="18" />',
            '<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1" />',
            '<NumberFormat ss:Format="@" />',
            '</Style>',

            '<Style ss:ID="headercell">',
            '<Font ss:Bold="1" ss:Size="10" />',
            '<Alignment ss:Horizontal="Center" ss:WrapText="1" />',
            '<Interior ss:Color="#A3C9F1" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="even">',
            '<Interior ss:Color="#CCFFFF" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="evendate" ss:Parent="even">',
            '<NumberFormat ss:Format="yyyy-mm-dd" />',
            '</Style>',

            '<Style ss:ID="evenint" ss:Parent="even">',
            '<Numberformat ss:Format="0" />',
            '</Style>',

            '<Style ss:ID="evenfloat" ss:Parent="even">',
            '<Numberformat ss:Format="0.00" />',
            '</Style>',

            '<Style ss:ID="odd">',
            '<Interior ss:Color="#CCCCFF" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="groupSeparator">',
            '<Interior ss:Color="#D3D3D3" ss:Pattern="Solid" />',
            '</Style>',

            '<Style ss:ID="odddate" ss:Parent="odd">',
            '<NumberFormat ss:Format="yyyy-mm-dd" />',
            '</Style>',

            '<Style ss:ID="oddint" ss:Parent="odd">',
            '<NumberFormat Format="0" />',
            '</Style>',

            '<Style ss:ID="oddfloat" ss:Parent="odd">',
            '<NumberFormat Format="0.00" />',
            '</Style>',

            '</Styles>',
            worksheet.xml,
            '</Workbook>'
        );
    },

    /*

        Support function to return field info from store based on fieldname

    */

    getModelField: function(fieldName) {

        var fields = this.store.model.getFields();
        for (var i = 0; i < fields.length; i++) {
            if (fields[i].name === fieldName) {
                return fields[i];
            }
        }
    },

    /*

        Convert store into Excel Worksheet

    */
    generateEmptyGroupRow: function(dataIndex, value, cellTypes, includeHidden) {

        var cm = this.columns;
        var colCount = this.columns.length;
        var rowTpl = '<Row ss:AutoFitHeight="0"><Cell ss:StyleID="groupSeparator" ss:MergeAcross="{0}"><Data ss:Type="String"><html:b>{1}</html:b></Data></Cell></Row>';
        var visibleCols = 0;

        // rowXml += '<Cell ss:StyleID="groupSeparator">'

        for (var j = 0; j < colCount; j++) {
            if (cm[j].xtype != 'actioncolumn' && (cm[j].dataIndex != '') && (includeHidden || !cm[j].hidden)) {
                // rowXml += '<Cell ss:StyleID="groupSeparator"/>';
                visibleCols++;
            }
        }

        // rowXml += "</Row>";

        return Ext.String.format(rowTpl, visibleCols - 1, value);
    },

    createWorksheet: function(includeHidden, theTitle) {
        // Calculate cell data types and extra class names which affect formatting
    	var cellType = [];
        var cellTypeClass = [];
        var cm = this.columns;
        var totalWidthInPixels = 0;
        var colXml = '';
        var headerXml = '';
        var visibleColumnCountReduction = 0;
        var colCount = cm.length;
        for (var i = 0; i < colCount; i++) {
            if (cm[i].xtype != 'actioncolumn' && (cm[i].dataIndex != '') && (includeHidden || !cm[i].hidden)) {
                var w = cm[i].getEl().getWidth();
                totalWidthInPixels += w;

                if (cm[i].text === "") {
                    cellType.push("None");
                    cellTypeClass.push("");
                    ++visibleColumnCountReduction;
                } else {
                    colXml += '<Column ss:AutoFitWidth="1" ss:Width="' + w + '" />';
                    headerXml += '<Cell ss:StyleID="headercell">' +
                        '<Data ss:Type="String">' + cm[i].text + '</Data>' +
                        '<NamedCell ss:Name="Print_Titles"></NamedCell></Cell>';

                    var fld = this.getModelField(cm[i].dataIndex);
                    switch (fld.type.type) {
                        case "int":
                            cellType.push("Number");
                            cellTypeClass.push("int");
                            break;
                        case "float":
                            cellType.push("Number");
                            cellTypeClass.push("float");
                            break;

                        case "bool":

                        case "boolean":
                            cellType.push("String");
                            cellTypeClass.push("");
                            break;
                        case "date":
                            cellType.push("DateTime");
                            cellTypeClass.push("date");
                            break;
                        default:
                            cellType.push("String");
                            cellTypeClass.push("");
                            break;
                    }
                }
            }
        }
        var visibleColumnCount = cellType.length - visibleColumnCountReduction;

        var result = {
            height: 9000,
            width: Math.floor(totalWidthInPixels * 30) + 50
        };

        // Generate worksheet header details.

        // determine number of rows
        var numGridRows = this.store.getCount() + 2;
        if (!Ext.isEmpty(this.store.groupField)) {
            numGridRows = numGridRows + this.store.getGroups().length;
        }

        // create header for worksheet
        var t = ''.concat(
            '<Worksheet ss:Name="' + theTitle + '">',

            '<Names>',
            '<NamedRange ss:Name="Print_Titles" ss:RefersTo="=\'' + theTitle + '\'!R1:R2">',
            '</NamedRange></Names>',

            '<Table ss:ExpandedColumnCount="' + (visibleColumnCount + 2),
            '" ss:ExpandedRowCount="' + numGridRows + '" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="15">',
            colXml,
            '<Row ss:Height="38">',
            '<Cell ss:MergeAcross="' + (visibleColumnCount - 1) + '" ss:StyleID="title">',
            '<Data ss:Type="String" xmlns:html="http://www.w3.org/TR/REC-html40">',
            '<html:b>' + theTitle + '</html:b></Data><NamedCell ss:Name="Print_Titles">',
            '</NamedCell></Cell>',
            '</Row>',
            '<Row ss:AutoFitHeight="1">',
            headerXml +
            '</Row>'
        );

        // Generate the data rows from the data in the Store
        var groupVal = "";
        for (var i = 0, it = this.store.data.items, l = it.length; i < l; i++) {

            if (!Ext.isEmpty(this.store.groupField)) {
                if (groupVal != this.store.getAt(i).get(this.store.groupField)) {
                    groupVal = this.store.getAt(i).get(this.store.groupField);
                    t += this.generateEmptyGroupRow(this.store.groupField, groupVal, cellType, includeHidden);
                }
            }
            t += '<Row>';
            var cellClass = (i & 1) ? 'odd' : 'even';
            r = it[i].data;
            var k = 0;
            for (var j = 0; j < colCount; j++) {
                if (cm[j].xtype != 'actioncolumn' && (cm[j].dataIndex != '') && (includeHidden || !cm[j].hidden)) {
                    var v = r[cm[j].dataIndex];
                    if (cellType[k] !== "None") {
                        t += '<Cell ss:StyleID="' + cellClass + cellTypeClass[k] + '"><Data ss:Type="' + cellType[k] + '">';
                        if (cellType[k] == 'DateTime') {
                            t += Ext.Date.format(v, 'Y-m-d');
                        } else {
                            t += v;
                        }
                        t += '</Data></Cell>';
                    }
                    k++;
                }
            }
            t += '</Row>';
        }

        result.xml = t.concat(
            '</Table>',
            '<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">',
            '<PageLayoutZoom>0</PageLayoutZoom>',
            '<Selected/>',
            '<Panes>',
            '<Pane>',
            '<Number>3</Number>',
            '<ActiveRow>2</ActiveRow>',
            '</Pane>',
            '</Panes>',
            '<ProtectObjects>False</ProtectObjects>',
            '<ProtectScenarios>False</ProtectScenarios>',
            '</WorksheetOptions>',
            '</Worksheet>'
        );
        return result;
    }
});
<|endoftext|>