<commit_before>var privates = require('./privates');

module.exports = function property(name, change, parse) {
  return {
    get: function() {
      return privates.get(this, name);
    },

    set: function(value) {
      if (parse) {
        value = parse.call(this, value, name);
      }
      var previous = this[name];
      if (value !== previous) {
        var changed = change.call(this, value, previous, name);
        if (changed !== false) {
          privates.set(this, name, value);
        }
      }
    }
  };
};
<commit_msg>add jsdoc comment to property.js<commit_after>var privates = require('./privates');

/**
 * A helpful property descriptor generator. As in:
 *
 * @example
 * var change = function(value, previous) {
 *   console.log('foo changed from', previous, 'to', value);
 * };
 *
 * Object.defineProperty(proto, 'foo', change);
 *
 * @param {String}    name    The *private* property name. This need not be the
 *                            same as the property's public name.
 * @param {Function}  change  The function to call when the value changes. If
 *                            this function returns `false` the change will be
 *                            canceled.
 * @param {Function?} parse   An optional function to parse or otherwise coerce
 *                            values, e.g. to turn strings into numbers.
 *
 * @return {Object}   returns a property descriptor for use with
 *                    Object.defineProperty()
 */
module.exports = function property(name, change, parse) {
  return {
    get: function() {
      return privates.get(this, name);
    },

    set: function(value) {
      if (parse) {
        value = parse.call(this, value, name);
      }
      var previous = this[name];
      if (value !== previous) {
        var changed = change.call(this, value, previous, name);
        if (changed !== false) {
          privates.set(this, name, value);
        }
      }
    }
  };
};
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import Warning from '../components/warning';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { me } from 'flavours/glitch/util/initial_state';
import { profileLink, termsLink } from 'flavours/glitch/util/backend_links';

const buildHashtagRE = () => {
  try {
    const HASHTAG_SEPARATORS = "_\\u00b7\\u200c";
    const ALPHA = '\\p{L}\\p{M}';
    const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}';
    return new RegExp(
      '(?:^|[^\\/\\)\\w])#((' +
      '[' + WORD + '_]' +
      '[' + WORD + HASHTAG_SEPARATORS + ']*' +
      '[' + ALPHA + HASHTAG_SEPARATORS + ']' +
      '[' + WORD + HASHTAG_SEPARATORS +']*' +
      '[' + WORD + '_]' +
      ')|(' +
      '[' + WORD + '_]*' +
      '[' + ALPHA + ']' +
      '[' + WORD + '_]*' +
      '))', 'iu'
    );
  } catch {
    return /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
  }
};

const APPROX_HASHTAG_RE = buildHashtagRE();

const mapStateToProps = state => ({
  needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
  hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),
  directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
});

const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
  if (needsLockWarning) {
    return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /> }} />} />;
  }

  if (hashtagWarning) {
    return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag." />} />;
  }

  if (directMessageWarning) {
    const message = (

        <FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> <FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' />

    );

    return <Warning message={message} />;
  }

  return null;
};

WarningWrapper.propTypes = {
  needsLockWarning: PropTypes.bool,
  hashtagWarning: PropTypes.bool,
  directMessageWarning: PropTypes.bool,
};

export default connect(mapStateToProps)(WarningWrapper);
<commit_msg>Fix backend terms link not being used<commit_after>import React from 'react';
import { connect } from 'react-redux';
import Warning from '../components/warning';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { me } from 'flavours/glitch/util/initial_state';
import { profileLink, termsLink } from 'flavours/glitch/util/backend_links';

const buildHashtagRE = () => {
  try {
    const HASHTAG_SEPARATORS = "_\\u00b7\\u200c";
    const ALPHA = '\\p{L}\\p{M}';
    const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}';
    return new RegExp(
      '(?:^|[^\\/\\)\\w])#((' +
      '[' + WORD + '_]' +
      '[' + WORD + HASHTAG_SEPARATORS + ']*' +
      '[' + ALPHA + HASHTAG_SEPARATORS + ']' +
      '[' + WORD + HASHTAG_SEPARATORS +']*' +
      '[' + WORD + '_]' +
      ')|(' +
      '[' + WORD + '_]*' +
      '[' + ALPHA + ']' +
      '[' + WORD + '_]*' +
      '))', 'iu'
    );
  } catch {
    return /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
  }
};

const APPROX_HASHTAG_RE = buildHashtagRE();

const mapStateToProps = state => ({
  needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
  hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),
  directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
});

const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
  if (needsLockWarning) {
    return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /> }} />} />;
  }

  if (hashtagWarning) {
    return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag." />} />;
  }

  if (directMessageWarning) {
    const message = (

        <FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> {!!termsLink && <FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' />}

    );

    return <Warning message={message} />;
  }

  return null;
};

WarningWrapper.propTypes = {
  needsLockWarning: PropTypes.bool,
  hashtagWarning: PropTypes.bool,
  directMessageWarning: PropTypes.bool,
};

export default connect(mapStateToProps)(WarningWrapper);
<|endoftext|>


<commit_before>const instanceVolumes = {
  templateUrl: 'views/partials/filtered-list.html',
  controller: OpenstackVolumesList,
  controllerAs: 'ListController',
  bindings: {
    resource: '<'
  }
};

export default instanceVolumes;

// @ngInject
function OpenstackVolumesList(
  baseResourceListController,
  $scope,
  $filter,
  $timeout,
  openstackVolumesService) {
  var controllerScope = this;
  var ResourceController = baseResourceListController.extend({
    init: function() {
      this.controllerScope = controllerScope;
      this._super();
      this.service = openstackVolumesService;
      this.addRowFields(['size', 'device']);

      $scope.$on('actionApplied', function(event, name) {
        if (name === 'volume') {
          $timeout(function() {
            controllerScope.resetCache();
          });
        }
      });
    },
    getTableOptions: function() {
      var options = this._super();
      options.noDataText = gettext('You have no volumes yet.');
      options.noMatchesText = gettext('No volumes found matching filter.');
      options.columns = [
        {
          title: gettext('Name'),
          className: 'all',
          render: row => this.renderResourceName(row)
        },
        {
          title: gettext('Size'),
          render: row => $filter('filesize')(row.size)
        },
        {
          title: gettext('Attached to'),
          render: row => row.device || 'N/A'
        },
        {
          title: gettext('State'),
          className: 'min-tablet-l',
          render: row => this.renderResourceState(row)
        },
      ];
      return options;
    },
    getFilter: function() {
      return {
        instance_uuid: controllerScope.resource.uuid
      };
    }
  });
  controllerScope.__proto__ = new ResourceController();
}
<commit_msg>[WAL-1172] Add "bootable" column to connected volume list in openstack instance tab.<commit_after>const instanceVolumes = {
  templateUrl: 'views/partials/filtered-list.html',
  controller: OpenstackVolumesList,
  controllerAs: 'ListController',
  bindings: {
    resource: '<'
  }
};

export default instanceVolumes;

// @ngInject
function OpenstackVolumesList(
  baseResourceListController,
  $scope,
  $filter,
  $timeout,
  ncUtils,
  openstackVolumesService) {
  var controllerScope = this;
  var ResourceController = baseResourceListController.extend({
    init: function() {
      this.controllerScope = controllerScope;
      this._super();
      this.service = openstackVolumesService;
      this.addRowFields(['size', 'device', 'bootable']);

      $scope.$on('actionApplied', function(event, name) {
        if (name === 'volume') {
          $timeout(function() {
            controllerScope.resetCache();
          });
        }
      });
    },
    getTableOptions: function() {
      var options = this._super();
      options.noDataText = gettext('You have no volumes yet.');
      options.noMatchesText = gettext('No volumes found matching filter.');
      options.columns = [
        {
          title: gettext('Name'),
          className: 'all',
          render: row => this.renderResourceName(row)
        },
        {
          title: gettext('Size'),
          render: row => $filter('filesize')(row.size)
        },
        {
          title: gettext('Bootable'),
          render: row => ncUtils.booleanField(row.bootable),
        },
        {
          title: gettext('Attached to'),
          render: row => row.device || 'N/A'
        },
        {
          title: gettext('State'),
          className: 'min-tablet-l',
          render: row => this.renderResourceState(row)
        },
      ];
      return options;
    },
    getFilter: function() {
      return {
        instance_uuid: controllerScope.resource.uuid
      };
    }
  });
  controllerScope.__proto__ = new ResourceController();
}
<|endoftext|>


<commit_before>function getDefault(key, valueInitializer) {

    const map = this;

    if (map.has(key)) {
        return map.get(key);
    }

    const value = valueInitializer(key, map);

    map.set(key, value);

    return value;

}

export function getAsyncIterator(iterable) {

    // direct iterators

    if (typeof iterable.next === 'function') {
        return iterable;
    }

    // async iterators

    if (Symbol.asyncIterator in iterable) {
        return iterable[Symbol.asyncIterator]();
    }

    // classic iterators

    if (Symbol.iterator in iterable) {
        return iterable[Symbol.iterator]();
    }

}

export async function toArray() {

    const iterator = getAsyncIterator(this);

    const result = [];

    let next;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        result.push(item);

    }

    return result;

}

export async function each(itemHandler) {

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        await itemHandler(item, i++);

    }

}

export async function* map(valueSelector) {

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        const value = await valueSelector(item, i++);

        yield value;

    }

}

export async function* many(itemsSelector = items => items, valueSelector = item => item) {

    const outerIterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await outerIterator.next()).done !== true) {

        const outer = next.value;

        const innerItems = await itemsSelector(outer, i++);

        const innerIterator = getAsyncIterator(innerItems);

        while ((next = await innerIterator.next()).done !== true) {

            const inner = next.value;

            const value = await valueSelector(inner, outer);

            yield value;

        }

    }

}

export async function reduce(reducer, initialValue) {

    const hasInitialValue = initialValue !== undefined;

    let result = hasInitialValue ? await initialValue : undefined;

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        // if we're on the first item and we don't have an initial value then use the first iteration to establish the first result
        if (i === 0 && hasInitialValue !== true) {
            result = item;
        } else {
            result = await reducer(result, item, i);
        }

        i++;

    }

    return result;

}

export function concat(...otherSequences) {

    const sequence = this;
    const sequences = [sequence, ...otherSequences];

    return sequences::many();

}

export async function* group(keySelector, valueSelector = item => item) {

    // todo: make this deferred, currently we execute immediately

    const groups = new Map();

    await this::each(async item => {

        const key = await keySelector(item);
        const value = await valueSelector(item);

        const group = groups::getDefault(key, () => []);

        group.push(value);

    });

    const iterator = getAsyncIterator(groups.entries());

    let next;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        yield item;

    }

}

export async function last(predicate) {

    let result;

    await this::each((item, i) => {

        if (predicate == null || predicate(item, i)) {
            result = item;
        }

    });

    return result;

}
<commit_msg>fix: ensure we increment our loop index<commit_after>function getDefault(key, valueInitializer) {

    const map = this;

    if (map.has(key)) {
        return map.get(key);
    }

    const value = valueInitializer(key, map);

    map.set(key, value);

    return value;

}

export function getAsyncIterator(iterable) {

    // direct iterators

    if (typeof iterable.next === 'function') {
        return iterable;
    }

    // async iterators

    if (Symbol.asyncIterator in iterable) {
        return iterable[Symbol.asyncIterator]();
    }

    // classic iterators

    if (Symbol.iterator in iterable) {
        return iterable[Symbol.iterator]();
    }

}

export async function toArray() {

    const iterator = getAsyncIterator(this);

    const result = [];

    let next;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        result.push(item);

    }

    return result;

}

export async function each(itemHandler) {

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        await itemHandler(item, i++);

    }

}

export async function* map(valueSelector) {

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        const value = await valueSelector(item, i++);

        yield value;

    }

}

export async function* many(itemsSelector = items => items, valueSelector = item => item) {

    const outerIterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await outerIterator.next()).done !== true) {

        const outer = next.value;

        const innerItems = await itemsSelector(outer, i++);

        const innerIterator = getAsyncIterator(innerItems);

        while ((next = await innerIterator.next()).done !== true) {

            const inner = next.value;

            const value = await valueSelector(inner, outer);

            yield value;

        }

    }

}

export async function reduce(reducer, initialValue) {

    const hasInitialValue = initialValue !== undefined;

    let result = hasInitialValue ? await initialValue : undefined;

    const iterator = getAsyncIterator(this);

    let next, i = 0;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        // if we're on the first item and we don't have an initial value then use the first iteration to establish the first result
        if (i === 0 && hasInitialValue !== true) {
            result = item;
        } else {
            result = await reducer(result, item, i);
        }

        i++;

    }

    return result;

}

export function concat(...otherSequences) {

    const sequence = this;
    const sequences = [sequence, ...otherSequences];

    return sequences::many();

}

export async function* group(keySelector, valueSelector = item => item) {

    // todo: make this deferred, currently we execute immediately

    const groups = new Map();

    await this::each(async item => {

        const key = await keySelector(item);
        const value = await valueSelector(item);

        const group = groups::getDefault(key, () => []);

        group.push(value);

    });

    const iterator = getAsyncIterator(groups.entries());

    let next;

    while ((next = await iterator.next()).done !== true) {

        const item = next.value;

        yield item;

    }

}

export async function last(predicate) {

    let result;

    await this::each((item, i) => {

        if (predicate == null || predicate(item, i++)) {
            result = item;
        }

    });

    return result;

}
<|endoftext|>


<commit_before>/**
 *
 */
/*
 * The aspiredb project
 *
 * Copyright (c) 2013 University of British Columbia
 *
 * 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.
 *
 */

Ext.require( [ 'Ext.Window', 'Matrix2Viz' ] );

Ext.define( 'ASPIREdb.view.SubjectPhenotypeHeatmapWindow', {
   /**
    * @memberOf ASPIREdb.view.SubjectPhenotypeHeatmapWindow
    */
   extend : 'Ext.Window',
   alias : 'widget.subjectPhenotypeHeatmapWindow',
   singleton : true,
   title : 'Subject Phenotype Heatmap',
   closable : true,
   closeAction : 'hide',
   width : 800,
   height : 600,
   layout : 'fit',
   bodyStyle : 'padding: 10px;',
   id : 'subjectPhenotypeHeatmapWindow',
   // TODO FIXME Bug 4419. Combine labels and dendrograms with the matrix image
   /*tbar : new Ext.Toolbar( {
      items : [ {
         xtype : 'button',
         itemId : 'exportButton',
         text : '',
         tooltip : 'Save heatmap as PNG',
         icon : 'scripts/ASPIREdb/resources/images/icons/export.png'
      } ]
   } ),*/

   initComponent : function() {
      var ref = this;
      this.callParent();

      this.down( '#exportButton' ).on( 'click', function() {
         ref.exportButtonHandler();
      }, this );

   },

   /**
    * TODO FIXME Bug 4419. Combine labels and dendrograms with the matrix image
    */
   exportButtonHandler : function() {
      if ( this.heatmap == null ) {
         return;
      }

      var canvas = this.heatmap.down( '#matrixCanvas' );
      if ( canvas == null ) {
         return;
      }

      var imgsrc = canvas.el.dom.toDataURL( 'image/png' );
      var strDownloadMime = "image/octet-stream";
      document.location.href = imgsrc.replace( "image/png", strDownloadMime );
   },

   draw : function(matrix) {

      var matrixColumnMetadata = [];
      var matrixRowMetadata = [];

      // TODO determine values dynamically

      for (var i = 0; i < matrix.columnNames.length; i++) {
         var type;
         if ( matrix.columnNames[i] == "Gender" || matrix.columnNames[i] == "Family history" ) {
            type = 'gender';
         } else if ( matrix.columnNames[i] == "Hairwhorls" ) {
            type = 'count';
         } else {
            type = 'binary';
         }
         matrixColumnMetadata.push( {
            Phenotype : matrix.columnNames[i],
            type : type
         } );
      }

      for (var i = 0; i < matrix.rowNames.length; i++) {
         matrixRowMetadata.push( {
            Subject : matrix.rowNames[i]
         } );
      }

      var convertedData = this.convertData( matrix.matrix, matrixColumnMetadata );

      var order = h2m.ClusterHelper.produceClusteredOrder( convertedData );

      var dataMatrix = {
         dimensions : {
            numberOfRows : matrix.rowNames.length,
            numberOfColumns : matrix.columnNames.length
         },
         getDataAt : function(rowIndex, columnIndex) {
            return matrix.matrix[rowIndex][columnIndex];
         }
      };

      M2V = {};
      M2V.Util = {};
      M2V.Util.dataType = {};

      // See PhenotypeGrid colors
      var colors = [ "#b35806", "#31a354", "#636363", "#d8b365", "#2c7fb8", "#addd8e", "#7570b3", "#a6bddb" ];
      colorNAIndex = 2;

      // a bit hard to match this with PhenotypeGrid because it depends on the
      // db value order
      M2V.Util.dataType.renderCountCell = function(ctx, value, row, column, size) {
         var color;
         var offset = 2;
         var idx = parseInt( value ) + offset;
         if ( idx < colors.length ) {
            color = colors[idx];
         } else {
            color = colors[colorNAIndex];
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      M2V.Util.dataType.renderGenderCell = function(ctx, value, row, column, size) {
         var color;
         value = value.toUpperCase();
         if ( value === "M" || value === "Y" ) {
            color = colors[4]; // blue
         } else if ( value === "F" || value === "N" ) {
            color = colors[3]; // yellow
         } else {
            color = colors[2]; // grey
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      // TODO support data types with more than 2 values
      M2V.Util.dataType.renderAbsentPresentCell = function(ctx, value, row, column, size) {
         // TODO write a legend
         var color;
         value = value.toUpperCase();
         if ( value === 0 || value === "0" || value === "N" || value === "M" ) {
            color = colors[1]; // green
         } else if ( value === 1 || value === "1" || value === "Y" || value === "F" ) {
            color = colors[0]; // brown
         } else {
            color = colors[2]; // unknown
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      // TODO: provide centering helper function
      var renderDefaults = {
         text : function(ctx, box, text) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( text, 0, 0 );
         },
         label : function(ctx, box, text) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( text, 0, 0 );
         },
         group : function(ctx, box, value) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( value, 0, 0 );
         },
         type : function(ctx, box, value) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( value, 0, 0 );
         },
         metaNumber : function(ctx, box, value) {
            ctx.fillStyle = 'rgb(0,100,0)';
            ctx.fillRect( 0, 1, box.width * value, box.height - 2 );
         }
      };

      var heatmap = Ext.create( 'Matrix2Viz', {
         // renderTo: "matrix_div",
         // renderTo: document.body,
         // renderTo: this.down('#matrix_div').getEl(),
         renderTo : this.el,
         width : 900,
         height : 700,

         data : dataMatrix,
         labelFormat : {
            row : [ {
               name : 'Subject',
               size : 90
            },
            // {name: 'group', size: 50}
            ],
            column : [ {
               name : 'Phenotype',
               size : 100
            },
            // {name: 'metaNumber', size: 10},
            // {name: 'type', size: 50}
            ]
         },
         renderers : {
            cell : {
               'count' : {
                  render : M2V.Util.dataType.renderCountCell
               },
               'gender' : {
                  render : M2V.Util.dataType.renderGenderCell
               },
               'binary' : {
                  render : M2V.Util.dataType.renderAbsentPresentCell
               },
               'numeric' : {
                  render : function(ctx, data, row, column, size) {
                     var red = Math.round( 255 * (data / (column.range.high - column.range.low)) );
                     ctx.fillStyle = "rgb(" + red + ",0,0)";
                     ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
                  }
               }
            },
            rowMetadata : {
               'Subject' : {
                  render : renderDefaults.text
               },
            /*
             * 'group': { render: renderDefaults.text }
             */
            },
            columnMetadata : {
               'Phenotype' : {
                  render : renderDefaults.text
               },
            /*
             * 'metaNumber': { render: renderDefaults.metaNumber }, 'type': { render: renderDefaults.text }
             */
            }
         },

         // rows: rows, //sample_data.js
         rows : matrixRowMetadata,

         rowOrder : order.rowOrder,

         // columns: columns, //sample_data.js
         columns : matrixColumnMetadata,

         columnOrder : order.columnOrder,

         clustering : order,

         cellSize : {
            width : 20,
            height : 10
         },

         controlPanel : 'DefaultControlPanel',

         // TODO: add row/column options for both
         displayOptions : {
            showRowDendrogram : true,
            showColumnDendrogram : true,
            showRowLabels : true,
            showColumnLabels : true
         }
      } );

      this.heatmap = heatmap;

      var resizer = Ext.create( 'Ext.resizer.Resizer', {
         handles : 'all',
         target : heatmap
      } );

      // hack to fix known Extjs bug with tooltip width being too small
      // http://stackoverflow.com/questions/15834689/extjs-4-2-tooltips-not-wide-enough-to-see-contents
      delete Ext.tip.Tip.prototype.minWidth;

      var t = new Ext.ToolTip( {
         floating : {
            shadow : false
         },
         html : 'Events',
         hideDelay : 1,
         target : heatmap.el,
         closable : false
      } );
      t.show();

      heatmap
         .on( 'cell-mouse-in',
            function(index) {
               // t.update('Cell Enter: '+index.row+','+index.col);
               var colLabel = this.matrix.columns[this.matrix.colOrder[index.col]].Phenotype;
               var rowLabel = this.matrix.rows[this.matrix.rowOrder[index.row]].Subject;
               var cellValue = this.matrix.data.getDataAt( this.matrix.rowOrder[index.row],
                  this.matrix.colOrder[index.col] );
               t.update( "Subject : " + rowLabel + "
" + "Phenotype : " + colLabel + "
" + "Value : "
                  + cellValue );
               t.show();
            } );

      heatmap.on( 'cell-mouse-out', function() {
         // t.update('Cell Leave');
         t.show();
      } );

      heatmap.on( 'cell-mouse-click', function() {
         // t.update('Cell Click');
         t.show();
      } );

      heatmap.on( 'label-mouse-in', function(index) {
         // t.update('Label Enter: '+index.index+','+index.subIndex);
         if ( index.orientation == Orientation.HORIZONTAL ) {
            t.update( this.matrix.rows[this.matrix.rowOrder[index.index]].Subject );
         } else if ( index.orientation == Orientation.VERTICAL ) {
            t.update( this.matrix.columns[this.matrix.colOrder[index.index]].Phenotype );
         }
         t.show();
      } );

      heatmap.on( 'label-mouse-out', function() {
         // t.update('Label leave: ');
         t.show();
      } );

      heatmap.on( 'label-mouse-click', function(index) {
         // t.update('Label click: '+index.index+','+index.subIndex);
         t.show();
      } );

      this.removeAll();
      this.add( heatmap );

      heatmap.draw();

   },

   bin : function(numberOfBins, value, range) {
      return Math.floor( value / ((range.high - range.low) / numberOfBins) );
   },

   convertData : function(data, columns) {
      var converted = [];
      for (var i = 0; i < data.length; i++) {
         var row = data[i];
         var convertedRow = [];
         for (var j = 0; j < row.length; j++) {
            var value = row[j];
            var convertedValue = value;
            if ( value == null ) {
               continue;
            }
            if ( columns[j].type === 'gender' ) {
               if ( value.toUpperCase() === 'M' ) {
                  convertedValue = 1;
               } else {
                  convertedValue = 0;
               }
            } else if ( columns[j].type === 'numeric' ) {
               convertedValue = this.bin( 3, value, columns[j].range );
            } else if ( columns[j].type === 'binary' ) {
               if ( value.toUpperCase() === 'Y' || value === '1' ) {
                  convertedValue = 1;
               } else if ( value.toUpperCase() === 'N' || value === '0' ) {
                  convertedValue = 0;
               }
            }
            convertedRow.push( convertedValue );
         }
         converted.push( convertedRow );
      }
      return converted;
   }

} );<commit_msg>Diable heatmap export to PNG for now<commit_after>/**
 *
 */
/*
 * The aspiredb project
 *
 * Copyright (c) 2013 University of British Columbia
 *
 * 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.
 *
 */

Ext.require( [ 'Ext.Window', 'Matrix2Viz' ] );

Ext.define( 'ASPIREdb.view.SubjectPhenotypeHeatmapWindow', {
   /**
    * @memberOf ASPIREdb.view.SubjectPhenotypeHeatmapWindow
    */
   extend : 'Ext.Window',
   alias : 'widget.subjectPhenotypeHeatmapWindow',
   singleton : true,
   title : 'Subject Phenotype Heatmap',
   closable : true,
   closeAction : 'hide',
   width : 800,
   height : 600,
   layout : 'fit',
   bodyStyle : 'padding: 10px;',
   id : 'subjectPhenotypeHeatmapWindow',
   // TODO FIXME Bug 4419. Combine labels and dendrograms with the matrix image
   /*tbar : new Ext.Toolbar( {
      items : [ {
         xtype : 'button',
         itemId : 'exportButton',
         text : '',
         tooltip : 'Save heatmap as PNG',
         icon : 'scripts/ASPIREdb/resources/images/icons/export.png'
      } ]
   } ),*/

   initComponent : function() {
      var ref = this;
      this.callParent();

      // TODO FIXME Bug 4419. Combine labels and dendrograms with the matrix image
      //this.down( '#exportButton' ).on( 'click', function() {
      //   ref.exportButtonHandler();
      //}, this );

   },

   /**
    * TODO FIXME Bug 4419. Combine labels and dendrograms with the matrix image
    */
   exportButtonHandler : function() {
      if ( this.heatmap == null ) {
         return;
      }

      var canvas = this.heatmap.down( '#matrixCanvas' );
      if ( canvas == null ) {
         return;
      }

      var imgsrc = canvas.el.dom.toDataURL( 'image/png' );
      var strDownloadMime = "image/octet-stream";
      document.location.href = imgsrc.replace( "image/png", strDownloadMime );
   },

   draw : function(matrix) {

      var matrixColumnMetadata = [];
      var matrixRowMetadata = [];

      // TODO determine values dynamically

      for (var i = 0; i < matrix.columnNames.length; i++) {
         var type;
         if ( matrix.columnNames[i] == "Gender" || matrix.columnNames[i] == "Family history" ) {
            type = 'gender';
         } else if ( matrix.columnNames[i] == "Hairwhorls" ) {
            type = 'count';
         } else {
            type = 'binary';
         }
         matrixColumnMetadata.push( {
            Phenotype : matrix.columnNames[i],
            type : type
         } );
      }

      for (var i = 0; i < matrix.rowNames.length; i++) {
         matrixRowMetadata.push( {
            Subject : matrix.rowNames[i]
         } );
      }

      var convertedData = this.convertData( matrix.matrix, matrixColumnMetadata );

      var order = h2m.ClusterHelper.produceClusteredOrder( convertedData );

      var dataMatrix = {
         dimensions : {
            numberOfRows : matrix.rowNames.length,
            numberOfColumns : matrix.columnNames.length
         },
         getDataAt : function(rowIndex, columnIndex) {
            return matrix.matrix[rowIndex][columnIndex];
         }
      };

      M2V = {};
      M2V.Util = {};
      M2V.Util.dataType = {};

      // See PhenotypeGrid colors
      var colors = [ "#b35806", "#31a354", "#636363", "#d8b365", "#2c7fb8", "#addd8e", "#7570b3", "#a6bddb" ];
      colorNAIndex = 2;

      // a bit hard to match this with PhenotypeGrid because it depends on the
      // db value order
      M2V.Util.dataType.renderCountCell = function(ctx, value, row, column, size) {
         var color;
         var offset = 2;
         var idx = parseInt( value ) + offset;
         if ( idx < colors.length ) {
            color = colors[idx];
         } else {
            color = colors[colorNAIndex];
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      M2V.Util.dataType.renderGenderCell = function(ctx, value, row, column, size) {
         var color;
         value = value.toUpperCase();
         if ( value === "M" || value === "Y" ) {
            color = colors[4]; // blue
         } else if ( value === "F" || value === "N" ) {
            color = colors[3]; // yellow
         } else {
            color = colors[2]; // grey
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      // TODO support data types with more than 2 values
      M2V.Util.dataType.renderAbsentPresentCell = function(ctx, value, row, column, size) {
         // TODO write a legend
         var color;
         value = value.toUpperCase();
         if ( value === 0 || value === "0" || value === "N" || value === "M" ) {
            color = colors[1]; // green
         } else if ( value === 1 || value === "1" || value === "Y" || value === "F" ) {
            color = colors[0]; // brown
         } else {
            color = colors[2]; // unknown
         }

         ctx.fillStyle = color;
         ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
      };

      // TODO: provide centering helper function
      var renderDefaults = {
         text : function(ctx, box, text) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( text, 0, 0 );
         },
         label : function(ctx, box, text) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( text, 0, 0 );
         },
         group : function(ctx, box, value) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( value, 0, 0 );
         },
         type : function(ctx, box, value) {
            ctx.translate( 0, box.height / 2 + 4 ); // fontSize
            ctx.fillText( value, 0, 0 );
         },
         metaNumber : function(ctx, box, value) {
            ctx.fillStyle = 'rgb(0,100,0)';
            ctx.fillRect( 0, 1, box.width * value, box.height - 2 );
         }
      };

      var heatmap = Ext.create( 'Matrix2Viz', {
         // renderTo: "matrix_div",
         // renderTo: document.body,
         // renderTo: this.down('#matrix_div').getEl(),
         renderTo : this.el,
         width : 900,
         height : 700,

         data : dataMatrix,
         labelFormat : {
            row : [ {
               name : 'Subject',
               size : 90
            },
            // {name: 'group', size: 50}
            ],
            column : [ {
               name : 'Phenotype',
               size : 100
            },
            // {name: 'metaNumber', size: 10},
            // {name: 'type', size: 50}
            ]
         },
         renderers : {
            cell : {
               'count' : {
                  render : M2V.Util.dataType.renderCountCell
               },
               'gender' : {
                  render : M2V.Util.dataType.renderGenderCell
               },
               'binary' : {
                  render : M2V.Util.dataType.renderAbsentPresentCell
               },
               'numeric' : {
                  render : function(ctx, data, row, column, size) {
                     var red = Math.round( 255 * (data / (column.range.high - column.range.low)) );
                     ctx.fillStyle = "rgb(" + red + ",0,0)";
                     ctx.fillRect( 1, 1, size.width - 2, size.height - 2 );
                  }
               }
            },
            rowMetadata : {
               'Subject' : {
                  render : renderDefaults.text
               },
            /*
             * 'group': { render: renderDefaults.text }
             */
            },
            columnMetadata : {
               'Phenotype' : {
                  render : renderDefaults.text
               },
            /*
             * 'metaNumber': { render: renderDefaults.metaNumber }, 'type': { render: renderDefaults.text }
             */
            }
         },

         // rows: rows, //sample_data.js
         rows : matrixRowMetadata,

         rowOrder : order.rowOrder,

         // columns: columns, //sample_data.js
         columns : matrixColumnMetadata,

         columnOrder : order.columnOrder,

         clustering : order,

         cellSize : {
            width : 20,
            height : 10
         },

         controlPanel : 'DefaultControlPanel',

         // TODO: add row/column options for both
         displayOptions : {
            showRowDendrogram : true,
            showColumnDendrogram : true,
            showRowLabels : true,
            showColumnLabels : true
         }
      } );

      this.heatmap = heatmap;

      var resizer = Ext.create( 'Ext.resizer.Resizer', {
         handles : 'all',
         target : heatmap
      } );

      // hack to fix known Extjs bug with tooltip width being too small
      // http://stackoverflow.com/questions/15834689/extjs-4-2-tooltips-not-wide-enough-to-see-contents
      delete Ext.tip.Tip.prototype.minWidth;

      var t = new Ext.ToolTip( {
         floating : {
            shadow : false
         },
         html : 'Events',
         hideDelay : 1,
         target : heatmap.el,
         closable : false
      } );
      t.show();

      heatmap
         .on( 'cell-mouse-in',
            function(index) {
               // t.update('Cell Enter: '+index.row+','+index.col);
               var colLabel = this.matrix.columns[this.matrix.colOrder[index.col]].Phenotype;
               var rowLabel = this.matrix.rows[this.matrix.rowOrder[index.row]].Subject;
               var cellValue = this.matrix.data.getDataAt( this.matrix.rowOrder[index.row],
                  this.matrix.colOrder[index.col] );
               t.update( "Subject : " + rowLabel + "
" + "Phenotype : " + colLabel + "
" + "Value : "
                  + cellValue );
               t.show();
            } );

      heatmap.on( 'cell-mouse-out', function() {
         // t.update('Cell Leave');
         t.show();
      } );

      heatmap.on( 'cell-mouse-click', function() {
         // t.update('Cell Click');
         t.show();
      } );

      heatmap.on( 'label-mouse-in', function(index) {
         // t.update('Label Enter: '+index.index+','+index.subIndex);
         if ( index.orientation == Orientation.HORIZONTAL ) {
            t.update( this.matrix.rows[this.matrix.rowOrder[index.index]].Subject );
         } else if ( index.orientation == Orientation.VERTICAL ) {
            t.update( this.matrix.columns[this.matrix.colOrder[index.index]].Phenotype );
         }
         t.show();
      } );

      heatmap.on( 'label-mouse-out', function() {
         // t.update('Label leave: ');
         t.show();
      } );

      heatmap.on( 'label-mouse-click', function(index) {
         // t.update('Label click: '+index.index+','+index.subIndex);
         t.show();
      } );

      this.removeAll();
      this.add( heatmap );

      heatmap.draw();

   },

   bin : function(numberOfBins, value, range) {
      return Math.floor( value / ((range.high - range.low) / numberOfBins) );
   },

   convertData : function(data, columns) {
      var converted = [];
      for (var i = 0; i < data.length; i++) {
         var row = data[i];
         var convertedRow = [];
         for (var j = 0; j < row.length; j++) {
            var value = row[j];
            var convertedValue = value;
            if ( value == null ) {
               continue;
            }
            if ( columns[j].type === 'gender' ) {
               if ( value.toUpperCase() === 'M' ) {
                  convertedValue = 1;
               } else {
                  convertedValue = 0;
               }
            } else if ( columns[j].type === 'numeric' ) {
               convertedValue = this.bin( 3, value, columns[j].range );
            } else if ( columns[j].type === 'binary' ) {
               if ( value.toUpperCase() === 'Y' || value === '1' ) {
                  convertedValue = 1;
               } else if ( value.toUpperCase() === 'N' || value === '0' ) {
                  convertedValue = 0;
               }
            }
            convertedRow.push( convertedValue );
         }
         converted.push( convertedRow );
      }
      return converted;
   }

} );<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * 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.
 */
function (w) {
	'use strict';
	w || (w = window);

    function DragAndDropService() {}

    DragAndDropService.prototype.$dndTypeMap$ = {};

    /**
     * Register a drag and drop component.
     * @param {String[]} types - drag and drop operations type that the component should be registered as
     * @param {Aura.Component} component - the drag and drop component
     */
    DragAndDropService.prototype.register = function(types, component) {
    	var ns;
    	if (component.isInstanceOf("ui:draggable")) {
    		ns = "ui:draggable";
    	} else if (component.isInstanceOf("ui:dropzone")) {
    		ns = "ui:dropzone";
    	}

    	if (ns) {
    		var globalId = component.getGlobalId();
    		$A.util.forEach(types, function(type) {
    			if (this.$dndTypeMap$[type] === undefined) {
    				this.$dndTypeMap$[type] = {
    					"ui:draggable": [],
    					"ui:dropzone": []
    				};
        		}
    			this.$dndTypeMap$[type][ns].push(globalId);
    		}, this);
    	}
    };

    /**
     * Deregister a drag and drop component.
     * @param {String[]} types - drag and drop operations type that the component should be registered as
     * @param {Aura.Component} component - the drag and drop component
     */
    DragAndDropService.prototype.deregister = function(types, component) {
    	var ns;
    	if (component.isInstanceOf("ui:draggable")) {
    		ns = "ui:draggable";
    	} else if (component.isInstanceOf("ui:dropzone")) {
    		ns = "ui:dropzone";
    	}

    	if (ns) {
    		var globalId = component.getGlobalId();
    		$A.util.forEach(types, function(type) {
    			var removeIndex = this.$dndTypeMap$[type][ns].indexOf(globalId);
    			if (removeIndex > -1) {
    				this.$dndTypeMap$[type][ns].splice(removeIndex, 1);
        		}
    		}, this);
    	}
    };

    /**
     * Get dropzone components that can handle drop operation of the specified type.
     * @return {Aura.Component[]} dropzone components of specified type
     */
    DragAndDropService.prototype.getDropzoneComponents = function(type) {
    	var globalIds = this.$dndTypeMap$[type]["ui:dropzone"];
    	var components = [];
    	$A.util.forEach(globalIds, function(globalId) {
    		components.push($A.componentService.get(globalId));
    	});
    	return components;
    };

    /**
     * Fire a drop complete event.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent.
     * @param {boolean} isSuccess - true if the drop has been completed successfully or false otherwise
     */
    DragAndDropService.prototype.fireDropComplete = function(dragEvent, isSuccess) {
      var dropComponent = dragEvent.getParam("dropComponent");
      var dragComponent = dragEvent.getParam("dragComponent");
      var type = dragEvent.getParam("type");

      var dropCompleteEvent = dragComponent.getEvent("dropComplete");
      dropCompleteEvent.setParams({
         "type": type,
         "dropComponent": dropComponent,
         "dropComplete": isSuccess
      });
      dropCompleteEvent.fire();
    };

    /**
     * Resolve context component for drag and drop component.
     * @return {Aura.Component} context component or null/ undefined if there is none
     */
    DragAndDropService.prototype.getContext = function(component) {
    	var context = component.get("v.inContextOf");
    	if (context) {
    		if ($A.util.isComponent(context)) {
    			return context;
    		}

    		var globalId;
    		var valueProvider = component.getAttributeValueProvider();
    		var refCmp = valueProvider.find(context);
    		if (refCmp) {
    			refCmp = refCmp.length ? refCmp[0] : refCmp;
    			globalId = refCmp.getGlobalId();
    		} else {
    			globalId = $A.componentService.get(context) ? context : null;
    		}

    		if (!$A.util.isEmpty(globalId)) {
    			return $A.componentService.get(globalId);
    		}
    	}

    	return context;
    };

    /**
     * Add data being transferred to dropzone component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent.
     * @param {Object} addParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.addDataTransfer = function(dragEvent, addParams) {
    	var dropComponent = dragEvent.getParam("dropComponent");
    	var context = this.getContext(dropComponent);

    	if (context) {
    		var dragComponent = dragEvent.getParam("dragComponent");
    		var dataTransfer = dragComponent.get("v.dataTransfer");

//    		if (context.getEvent("addRemove")) {
//    			// fire addRemove event -- addRemove event in ui:abstractList is unsupported yet!
//    			var addRemoveEvent = context.getEvent("addRemove");
//    			addRemoveEvent.setParams(addParams);
//    			addRemoveEvent.fire();
//    		} else
    		if (context.get("v.dataProvider[0]")) {
    			// fire onchange event on dataProvider -- this will only add to last index
    			var dataProvider = context.get("v.dataProvider[0]");
    	    	var onChangeEvent = dataProvider.getEvent("onchange");
    	    	onChangeEvent.setParams({
    				"data" : addParams["items"]
    			});
    	    	onChangeEvent.fire();
    		}
    	}
    };

    /**
     * Remove data being transferred from a draggable component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent
     * @param {Object} removeParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.removeDataTransfer = function(dragEvent, removeParams) {
    	var dragComponent = dragEvent.getParam("dragComponent");
    	var context = this.getContext(dragComponent);

    	if (context) {
    		if(context.getEvent("addRemove")) {
    			var addRemoveEvent = context.getEvent("addRemove");
				addRemoveEvent.setParams(removeParams);
				addRemoveEvent.fire();
    		}
    	}
    };

    /**
     * Move data being transferred from a draggable component to a dropzone component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent
     * @param {Object} addParams - parameter for adding data transfer. See ui:addRemove.
     * @param {Object} removeParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.moveDataTransfer = function(dragEvent, addParams, removeParams) {
    	if (addParams) {
    		this.addDataTransfer(dragEvent, addParams);
    	}

    	if (removeParams) {
    		this.removeDataTransfer(dragEvent, removeParams);
    	}
    };

    w.$A["dragAndDropService"] = new DragAndDropService();
}
<commit_msg>fixed getContext and addDataTransfer<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * 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.
 */
function (w) {
	'use strict';
	w || (w = window);

    function DragAndDropService() {}

    DragAndDropService.prototype.$dndTypeMap$ = {};

    /**
     * Register a drag and drop component.
     * @param {String[]} types - drag and drop operations type that the component should be registered as
     * @param {Aura.Component} component - the drag and drop component
     */
    DragAndDropService.prototype.register = function(types, component) {
    	var ns;
    	if (component.isInstanceOf("ui:draggable")) {
    		ns = "ui:draggable";
    	} else if (component.isInstanceOf("ui:dropzone")) {
    		ns = "ui:dropzone";
    	}

    	if (ns) {
    		var globalId = component.getGlobalId();
    		$A.util.forEach(types, function(type) {
    			if (this.$dndTypeMap$[type] === undefined) {
    				this.$dndTypeMap$[type] = {
    					"ui:draggable": [],
    					"ui:dropzone": []
    				};
        		}
    			this.$dndTypeMap$[type][ns].push(globalId);
    		}, this);
    	}
    };

    /**
     * Deregister a drag and drop component.
     * @param {String[]} types - drag and drop operations type that the component should be registered as
     * @param {Aura.Component} component - the drag and drop component
     */
    DragAndDropService.prototype.deregister = function(types, component) {
    	var ns;
    	if (component.isInstanceOf("ui:draggable")) {
    		ns = "ui:draggable";
    	} else if (component.isInstanceOf("ui:dropzone")) {
    		ns = "ui:dropzone";
    	}

    	if (ns) {
    		var globalId = component.getGlobalId();
    		$A.util.forEach(types, function(type) {
    			var removeIndex = this.$dndTypeMap$[type][ns].indexOf(globalId);
    			if (removeIndex > -1) {
    				this.$dndTypeMap$[type][ns].splice(removeIndex, 1);
        		}
    		}, this);
    	}
    };

    /**
     * Get dropzone components that can handle drop operation of the specified type.
     * @return {Aura.Component[]} dropzone components of specified type
     */
    DragAndDropService.prototype.getDropzoneComponents = function(type) {
    	var globalIds = this.$dndTypeMap$[type]["ui:dropzone"];
    	var components = [];
    	$A.util.forEach(globalIds, function(globalId) {
    		components.push($A.componentService.get(globalId));
    	});
    	return components;
    };

    /**
     * Fire a drop complete event.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent.
     * @param {boolean} isSuccess - true if the drop has been completed successfully or false otherwise
     */
    DragAndDropService.prototype.fireDropComplete = function(dragEvent, isSuccess) {
      var dropComponent = dragEvent.getParam("dropComponent");
      var dragComponent = dragEvent.getParam("dragComponent");
      var type = dragEvent.getParam("type");

      var dropCompleteEvent = dragComponent.getEvent("dropComplete");
      dropCompleteEvent.setParams({
         "type": type,
         "dropComponent": dropComponent,
         "dropComplete": isSuccess
      });
      dropCompleteEvent.fire();
    };

    /**
     * Resolve context component for drag and drop component.
     * @return {Aura.Component} context component or null/ undefined if there is none
     */
    DragAndDropService.prototype.getContext = function(component) {
    	var context = component.get("v.inContextOf");
    	if (context) {
    		if ($A.util.isComponent(context)) {
    			return context;
    		}

    		var globalId;
    		var valueProvider = component.getAttributeValueProvider();
    		var refCmp = valueProvider.find(context);
    		if (refCmp) {
    			refCmp = refCmp.length ? refCmp[0] : refCmp;
    			globalId = refCmp.getGlobalId();
    		} else {
    			globalId = $A.componentService.get(context) ? context : null;
    		}

    		if (!$A.util.isEmpty(globalId)) {
    			return $A.componentService.get(globalId);
    		}
    	}

    	// no context defined so returned the original component
    	return component.getConcreteComponent();
    };

    /**
     * Add data being transferred to dropzone component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent.
     * @param {Object} addParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.addDataTransfer = function(dragEvent, addParams) {
    	var dropComponent = dragEvent.getParam("dropComponent");
    	var context = this.getContext(dropComponent);

    	if (context) {
    		if (context.getEvent("addRemove")) {
    			// fire addRemove event
    			var addRemoveEvent = context.getEvent("addRemove");
    			addRemoveEvent.setParams(addParams);
    			addRemoveEvent.fire();
    		} else if (context.get("v.dataProvider[0]")) {
    			// fire onchange event on dataProvider -- this will only add to last index
    			var dataProvider = context.get("v.dataProvider[0]");
    	    	var onChangeEvent = dataProvider.getEvent("onchange");
    	    	onChangeEvent.setParams({
    				"data" : addParams["items"]
    			});
    	    	onChangeEvent.fire();
    		}
    	}
    };

    /**
     * Remove data being transferred from a draggable component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent
     * @param {Object} removeParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.removeDataTransfer = function(dragEvent, removeParams) {
    	var dragComponent = dragEvent.getParam("dragComponent");
    	var context = this.getContext(dragComponent);

    	if (context) {
    		if(context.getEvent("addRemove")) {
    			var addRemoveEvent = context.getEvent("addRemove");
				addRemoveEvent.setParams(removeParams);
				addRemoveEvent.fire();
    		}
    	}
    };

    /**
     * Move data being transferred from a draggable component to a dropzone component.
     * @param {Aura.Event} dragEvent - the drop event that is occurred. Must be of type ui:dragEvent
     * @param {Object} addParams - parameter for adding data transfer. See ui:addRemove.
     * @param {Object} removeParams - parameter for adding data transfer. See ui:addRemove.
     */
    DragAndDropService.prototype.moveDataTransfer = function(dragEvent, addParams, removeParams) {
    	if (addParams) {
    		this.addDataTransfer(dragEvent, addParams);
    	}

    	if (removeParams) {
    		this.removeDataTransfer(dragEvent, removeParams);
    	}
    };

    w.$A["dragAndDropService"] = new DragAndDropService();
}
<|endoftext|>


<commit_before>import React from 'react'

/**
 * Return the weather. This component is not loaded on the homepage, to test that getInitialProps works client-side too.
 */
export default class TopArticles extends React.Component {
  static async getInitialProps ({ props, req, res }) {
    // Fetch the weather from a remote API, it may take some time...
    return new Promise(resolve => {
      console.log(typeof window !== 'undefined' ? 'client-side' : 'server-side')
      // Simulate a delay (slow network, huge computation...)
      setTimeout(
        () =>
          resolve({
            ...props, // Props from the main page, passed through the internal fragment URL server-side
            weather: 'sunny ☀'
          }),
        2000
      )
    })
  }

  render () {
    console.log(typeof window !== 'undefined' ? 'client-side' : 'server-side')

    return (

Weather

        {this.props.weather}

          generated at {new Date().toISOString()}

    )
  }
}
<commit_msg>Typo in class name in with-react-esi example (#8414)<commit_after>import React from 'react'

/**
 * Return the weather. This component is not loaded on the homepage, to test that getInitialProps works client-side too.
 */
export default class Weather extends React.Component {
  static async getInitialProps ({ props, req, res }) {
    // Fetch the weather from a remote API, it may take some time...
    return new Promise(resolve => {
      console.log(typeof window !== 'undefined' ? 'client-side' : 'server-side')
      // Simulate a delay (slow network, huge computation...)
      setTimeout(
        () =>
          resolve({
            ...props, // Props from the main page, passed through the internal fragment URL server-side
            weather: 'sunny ☀'
          }),
        2000
      )
    })
  }

  render () {
    console.log(typeof window !== 'undefined' ? 'client-side' : 'server-side')

    return (

Weather

        {this.props.weather}

          generated at {new Date().toISOString()}

    )
  }
}
<|endoftext|>


<commit_before>"use strict";
var aGameOptionList = [
	[
		{"id":"radiant_gold_multiplier", "linked_equal_player_id":"dire_gold_multiplier", "type":"dropdown", "options":[1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"dire_gold_multiplier", "linked_equal_player_id":"radiant_gold_multiplier", "type":"dropdown", "options":[1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"radiant_xp_multiplier", "linked_equal_player_id":"dire_xp_multiplier", "type":"dropdown", "options":[1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"dire_xp_multiplier", "linked_equal_player_id":"radiant_xp_multiplier", "type":"dropdown", "options":[1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"radiant_player_number", "linked_equal_player_id":"dire_player_number", "type":"dropdown", "options":[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "default_value":12, "toolsmode_default_value":1},
		{"id":"dire_player_number", "linked_equal_player_id":"radiant_player_number", "type":"dropdown", "options":[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "default_value":12, "toolsmode_default_value":1},
		{"id":"respawn_time_percentage", "type":"dropdown", "options":[100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "percentage":true, "default_value":100},
		{"id":"buyback_cooldown", "type":"dropdown", "options":[480, 420, 360, 300, 240, 180, 120, 60, 50, 40, 30, 20, 10, 0], "default_value":480},
		{"id":"tower_power", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"tower_endure", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "default_value": 1},
		{"id":"max_level", "type":"dropdown", "options":[30, 50, 100, 200, 400, 800, 1600], "default_value" : 30},
		{"id":"radiant_fun_item_total_price_thresold", "linked_equal_player_id":"dire_fun_item_total_price_thresold", "type":"dropdown", "options":[0, 10000, 15000, 30000, 45000, 60000, 75000, 90000, 150000, 200000, 1000000], "default_value" : 1000000},
		{"id":"dire_fun_item_total_price_thresold", "linked_equal_player_id":"radiant_fun_item_total_price_thresold", "type":"dropdown", "options":[0, 10000, 15000, 30000, 45000, 60000, 75000, 90000, 150000, 200000, 1000000], "default_value" : 1000000},
	],
	[
		{"id":"imbalanced_economizer", "type":"toggle", "default_value":false},
		{"id":"bot_has_fun_item", "type":"toggle", "default_value":true},
		{"id":"universal_shop", "type":"toggle", "default_value":false},
		{"id":"fast_courier", "type":"toggle", "default_value":true},
		{"id":"bot_protection", "type":"toggle", "default_value":true},
		{"id":"anti_diving", "type":"toggle", "default_value":true},
		{"id":"enable_lottery", "type":"toggle", "default_value":true},
	]
//	{"id":"dynamic_exp_gold", "type":"toggle", "default_value":false},
]

var aVoteOptions = [
	{name:'#wheter_activate_fun_heroes',options:['#aifun_vote_no', '#aifun_vote_yes'], lua_name:'iActivateFunHeroes'},
	{name:'#wheter_activate_imba_fun_heroes',options:['#aifun_vote_no', '#aifun_vote_yes'], tooltip:"#imba_fun_heroes_tooltip", lua_name:'iActivateImbaFunHeroes'},
//	{name:'#wheter_ban_fun_items',options:['#aifun_vote_no', '#aifun_vote_yes'], lua_name:'iBanFunItems'},
]

//$.Msg("game mode data loaded")<commit_msg>Update game_mode_data.js<commit_after>"use strict";
var aGameOptionList = [
	[
		{"id":"radiant_gold_multiplier", "linked_equal_player_id":"dire_gold_multiplier", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40], "default_value":1},
		{"id":"dire_gold_multiplier", "linked_equal_player_id":"radiant_gold_multiplier", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40], "default_value":1},
		{"id":"radiant_xp_multiplier", "linked_equal_player_id":"dire_xp_multiplier", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40], "default_value":1},
		{"id":"dire_xp_multiplier", "linked_equal_player_id":"radiant_xp_multiplier", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 35, 40], "default_value":1},
		{"id":"radiant_player_number", "linked_equal_player_id":"dire_player_number", "type":"dropdown", "options":[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "default_value":12, "toolsmode_default_value":1},
		{"id":"dire_player_number", "linked_equal_player_id":"radiant_player_number", "type":"dropdown", "options":[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "default_value":12, "toolsmode_default_value":1},
		{"id":"respawn_time_percentage", "type":"dropdown", "options":[100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], "percentage":true, "default_value":100},
		{"id":"buyback_cooldown", "type":"dropdown", "options":[480, 420, 360, 300, 240, 180, 120, 60, 50, 40, 30, 20, 10, 0], "default_value":480},
		{"id":"tower_power", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "default_value":1},
		{"id":"tower_endure", "type":"dropdown", "options":[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "default_value": 1},
		{"id":"max_level", "type":"dropdown", "options":[30, 50, 100, 200, 400, 800, 1600], "default_value" : 30},
		{"id":"radiant_fun_item_total_price_thresold", "linked_equal_player_id":"dire_fun_item_total_price_thresold", "type":"dropdown", "options":[0, 10000, 12000, 15000, 17000, 30000, 45000, 60000, 75000, 90000, 150000, 200000, 1000000], "default_value" : 1000000},
		{"id":"dire_fun_item_total_price_thresold", "linked_equal_player_id":"radiant_fun_item_total_price_thresold", "type":"dropdown", "options":[0, 10000, 12000, 15000, 17000, 30000, 45000, 60000, 75000, 90000, 150000, 200000, 1000000], "default_value" : 1000000},
	],
	[
		{"id":"imbalanced_economizer", "type":"toggle", "default_value":false},
		{"id":"bot_has_fun_item", "type":"toggle", "default_value":true},
		{"id":"universal_shop", "type":"toggle", "default_value":true},
		{"id":"fast_courier", "type":"toggle", "default_value":true},
		{"id":"bot_protection", "type":"toggle", "default_value":false},
		{"id":"anti_diving", "type":"toggle", "default_value":false},
		{"id":"enable_lottery", "type":"toggle", "default_value":true},
	]
//	{"id":"dynamic_exp_gold", "type":"toggle", "default_value":false},
]

var aVoteOptions = [
	{name:'#wheter_activate_fun_heroes',options:['#aifun_vote_no', '#aifun_vote_yes'], lua_name:'iActivateFunHeroes'},
	{name:'#wheter_activate_imba_fun_heroes',options:['#aifun_vote_no', '#aifun_vote_yes'], tooltip:"#imba_fun_heroes_tooltip", lua_name:'iActivateImbaFunHeroes'},
//	{name:'#wheter_ban_fun_items',options:['#aifun_vote_no', '#aifun_vote_yes'], lua_name:'iBanFunItems'},
]

//$.Msg("game mode data loaded")<|endoftext|>


<commit_before>function Muppet(age, hobby) {
  this.age = age;
  this.hobby = hobby;

  this.answerNanny = function(){
	return "Everything's cool!";
  }
}

function SwedishChef(age, hobby, mood) {
  Muppet.call(this, age, hobby);
  this.mood = mood;

  this.cook = function() {
    return "Mmmm soup!";
  }
}

SwedishChef.prototype = new Muppet();

describe("About inheritance", function() {
  beforeEach(function(){
    this.muppet = new Muppet(2, "coding");
  	this.swedishChef = new SwedishChef(2, "cooking", "chillin");
  });

  it("should be able to call a method on the derived object", function() {
    expect(this.swedishChef.cook()).toEqual(FILL_ME_IN);
  });

  it("should be able to call a method on the base object", function() {
    expect(this.swedishChef.answerNanny()).toEqual(FILL_ME_IN);
  });

  it("should set constructor parameters on the base object", function() {
    expect(this.swedishChef.age).toEqual(FILL_ME_IN);
    expect(this.swedishChef.hobby).toEqual(FILL_ME_IN);
  });

  it("should set constructor parameters on the derived object", function() {
    expect(this.swedishChef.mood).toEqual(FILL_ME_IN);
  });
});

// http://javascript.crockford.com/prototypal.html
Object.prototype.beget = function () {
  function F() {}
  F.prototype = this;
  return new F();
}

function Gonzo(age, hobby, trick) {
  Muppet.call(this, age, hobby);
  this.trick = trick;

  this.doTrick = function() {
    return this.trick;
  }
}

//no longer need to call the Muppet (base type) constructor
Gonzo.prototype = Muppet.prototype.beget();
//note: if you're wondering how this line affects the below tests, the answer is that it doesn't.
//however, it does do something interesting -- it makes this work:
//  var g = new Gonzo(...);
//  g instanceOf Muppet //true

describe("About Crockford's inheritance improvement", function() {
  beforeEach(function(){
    this.gonzo = new Gonzo(3, "daredevil performer", "eat a tire");
  });

  it("should be able to call a method on the derived object", function() {
    expect(this.gonzo.doTrick()).toEqual(FILL_ME_IN);
  });

  it("should be able to call a method on the base object", function() {
    expect(this.gonzo.answerNanny()).toEqual(FILL_ME_IN);
  });

  it("should set constructor parameters on the base object", function() {
    expect(this.gonzo.age).toEqual(FILL_ME_IN);
    expect(this.gonzo.hobby).toEqual(FILL_ME_IN);
  });

  it("should set constructor parameters on the derived object", function() {
    expect(this.gonzo.trick).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Inheritance koan completed<commit_after>function Muppet(age, hobby) {
  this.age = age;
  this.hobby = hobby;

  this.answerNanny = function(){
	return "Everything's cool!";
  }
}

function SwedishChef(age, hobby, mood) {
  Muppet.call(this, age, hobby);
  this.mood = mood;

  this.cook = function() {
    return "Mmmm soup!";
  }
}

SwedishChef.prototype = new Muppet();

describe("About inheritance", function() {
  beforeEach(function(){
    this.muppet = new Muppet(2, "coding");
  	this.swedishChef = new SwedishChef(2, "cooking", "chillin");
  });

  it("should be able to call a method on the derived object", function() {
    expect(this.swedishChef.cook()).toEqual("Mmmm soup!");
  });

  it("should be able to call a method on the base object", function() {
    expect(this.swedishChef.answerNanny()).toEqual("Everything's cool!");
  });

  it("should set constructor parameters on the base object", function() {
    expect(this.swedishChef.age).toEqual(2);
    expect(this.swedishChef.hobby).toEqual("cooking");
  });

  it("should set constructor parameters on the derived object", function() {
    expect(this.swedishChef.mood).toEqual("chillin");
  });
});

// http://javascript.crockford.com/prototypal.html
Object.prototype.beget = function () {
  function F() {}
  F.prototype = this;
  return new F();
}

function Gonzo(age, hobby, trick) {
  Muppet.call(this, age, hobby);
  this.trick = trick;

  this.doTrick = function() {
    return this.trick;
  }
}

//no longer need to call the Muppet (base type) constructor
Gonzo.prototype = Muppet.prototype.beget();
//note: if you're wondering how this line affects the below tests, the answer is that it doesn't.
//however, it does do something interesting -- it makes this work:
//  var g = new Gonzo(...);
//  g instanceOf Muppet //true

describe("About Crockford's inheritance improvement", function() {
  beforeEach(function(){
    this.gonzo = new Gonzo(3, "daredevil performer", "eat a tire");
  });

  it("should be able to call a method on the derived object", function() {
    expect(this.gonzo.doTrick()).toEqual("eat a tire");
  });

  it("should be able to call a method on the base object", function() {
    expect(this.gonzo.answerNanny()).toEqual("Everything's cool!");
  });

  it("should set constructor parameters on the base object", function() {
    expect(this.gonzo.age).toEqual(3);
    expect(this.gonzo.hobby).toEqual("daredevil performer");
  });

  it("should set constructor parameters on the derived object", function() {
    expect(this.gonzo.trick).toEqual("eat a tire");
  });
});
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2012 Jesse Glick.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

function progressivelyRender(handler, callback) {
    function checkNews(response) {
        var r = response.responseObject();
        if (r.status == 'done') {
            // XXX why does window[callback] not work?
            eval(callback)(r.data);
            $('status').style.display = 'none';
        } else if (r.status == 'canceled') {
            // XXX ugly; replace with single tr of class=unknown?
            $$('#status .progress-bar-done')[0].innerHTML = 'Aborted.';
        } else if (r.status == 'error') {
            $$('#status .progress-bar-done')[0].style.width = '100%';
            $$('#status .progress-bar-left')[0].style.width = '0%';
            $('status').className = 'progress-bar red';
        } else {
            eval(callback)(r.data);
            $$('#status .progress-bar-done')[0].style.width = (100 * r.status) + '%';
            $$('#status .progress-bar-left')[0].style.width = (100 - 100 * r.status) + '%';
            checkNewsLater();
        }
    }
    function checkNewsLater() {
        setTimeout(function() {
            handler.news(checkNews);
        }, 500);
    }
    checkNewsLater();
}
<commit_msg>No need to really wait the first time.<commit_after>/*
 * The MIT License
 *
 * Copyright 2012 Jesse Glick.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

function progressivelyRender(handler, callback) {
    function checkNews(response) {
        var r = response.responseObject();
        if (r.status == 'done') {
            // XXX why does window[callback] not work?
            eval(callback)(r.data);
            $('status').style.display = 'none';
        } else if (r.status == 'canceled') {
            // XXX ugly; replace with single tr of class=unknown?
            $$('#status .progress-bar-done')[0].innerHTML = 'Aborted.';
        } else if (r.status == 'error') {
            $$('#status .progress-bar-done')[0].style.width = '100%';
            $$('#status .progress-bar-left')[0].style.width = '0%';
            $('status').className = 'progress-bar red';
        } else {
            eval(callback)(r.data);
            $$('#status .progress-bar-done')[0].style.width = (100 * r.status) + '%';
            $$('#status .progress-bar-left')[0].style.width = (100 - 100 * r.status) + '%';
            checkNewsLater(500);
        }
    }
    function checkNewsLater(timeout) {
        setTimeout(function() {
            handler.news(checkNews);
        }, timeout);
    }
    checkNewsLater(0);
}
<|endoftext|>


<commit_before>SectionParticipantsController.$inject = ['$stateParams', 'sections',
    'TbUtils', 'tableContent', '$rootScope'
];

function SectionParticipantsController($stateParams, sections,
    TbUtils, tableContent, $rootScope) {
    const vm = this;
    vm.participantsLoading = true;
    $rootScope.Role = 'Professor';
    vm.editHours = {
        visible: $rootScope.Role === 'Professor',
        value: false,
        text: 'Habilitar la edición de las horas'
    }
    vm.studentsTable = TbUtils.getTable(['Número de Cuenta', 'Nombre', 'Horas en este proyecto']);
    if ($rootScope.Role === 'Professor')
        vm.studentsTable.headers.push('Horas Trabajadas');

    sections.getStudents($stateParams.sectionId, getStudentsSuccess, getStudentsFail);

    function getStudentsSuccess(response) {
        if (response.data.length <= 0)
            return;
        for (let i = 0; i < response.data.length; i++) {
            let student = response.data[i];
            let newTableElement = {
                content: [
                    tableContent.createALableElement(student.AccountId),
                    tableContent.createALableElement(student.Name),
                    tableContent.createALableElement('0')
                    /*
                    	TODO: cambiar ese 0 por el valor correspondiente
                    	no hay llamada en el api que me de las horas en un proyecto
                    	específicio.
                    */
                ],
                data: student
            };
            if ($rootScope.Role === 'Professor') {
                let inputProperties = {
                    type: 'number',
                    min: 0,
                    max: 100
                }
                newTableElement.content.push(
                    tableContent.createAnInputElement(inputProperties)
                );
            }
            vm.studentsTable.body.push(newTableElement);
        }
        vm.participantsLoading = false;
        console.log(vm.studentsTable);
    }

    function getStudentsFail() {
        vm.participantsLoading = false;
        TbUtils.displayNotification('error', 'Error',
            'No se pudieron cargar los alumnos correctamente.');
    }
}

module.exports = {
    name: 'SectionParticipantsController',
    ctrl: SectionParticipantsController
};<commit_msg>get input values array<commit_after>SectionParticipantsController.$inject = ['$stateParams', 'sections',
    'TbUtils', 'tableContent', '$rootScope'
];

function SectionParticipantsController($stateParams, sections,
    TbUtils, tableContent, $rootScope) {
    const vm = this;
    vm.participantsLoading = true;
    vm.editHours = {
        visible: $rootScope.Role === 'Professor',
        value: false,
        text: 'Habilitar la edición de las horas'
    }
    vm.studentsTable = TbUtils.getTable(['Número de Cuenta', 'Nombre', 'Horas en este proyecto']);
    if ($rootScope.Role === 'Professor')
        vm.studentsTable.headers.push('Horas Trabajadas');

    sections.getStudents($stateParams.sectionId, getStudentsSuccess, getStudentsFail);

    function getStudentsSuccess(response) {
        if (response.data.length <= 0)
            return;
        for (let i = 0; i < response.data.length; i++) {
            let student = response.data[i];
            let newTableElement = {
                content: [
                    tableContent.createALableElement(student.AccountId),
                    tableContent.createALableElement(student.Name),
                    tableContent.createALableElement('0')
                    /*
                    	TODO: cambiar ese 0 por el valor correspondiente
                    	no hay llamada en el api que me de las horas en un proyecto
                    	específicio.
                    */
                ],
                data: student
            };
            if ($rootScope.Role === 'Professor') {
                let inputProperties = {
                    type: 'number',
                    min: 0,
                    max: 100
                }
                newTableElement.content.push(
                    tableContent.createAnInputElement(inputProperties)
                );
            }
            vm.studentsTable.body.push(newTableElement);
        }
        vm.participantsLoading = false;
    }

    function getStudentsFail() {
        vm.participantsLoading = false;
        TbUtils.displayNotification('error', 'Error',
            'No se pudieron cargar los alumnos correctamente.');
    }

    function getInputValue() {
        let table = [];
        for (let i = 0; i < vm.studentsTable.body.length; i++) {
        	let student = vm.studentsTable.body[i];
        	let element = {
        		data: student.data,
        		inputValue: student.content[4].properties.value
        	}
        	table.push(element);
        }
        return table;
    }
}

module.exports = {
    name: 'SectionParticipantsController',
    ctrl: SectionParticipantsController
};<|endoftext|>


<commit_before>import Component from '@glimmer/component';
import ConfirmArchiveModal from '../../modals/edit-newsletter/confirm-archive';
import ConfirmUnarchiveModal from '../../modals/edit-newsletter/confirm-unarchive';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';

export default class NewsletterManagementComponent extends Component {
    @service modals;
    @service router;
    @service store;

    @tracked statusFilter = 'active';
    @tracked filteredNewsletters = [];

    statusFilters = ['active', 'archived'];
    newsletters = this.store.peekAll('newsletter');

    constructor() {
        super(...arguments);
        this.loadNewslettersTask.perform();

        this.router.on('routeDidChange', this.handleNewRouteChange);
    }

    willDestroy() {
        super.willDestroy(...arguments);
        this.router.off('routeDidChange', this.handleNewRouteChange);

        this.confirmArchiveModal?.close();
        this.confirmUnarchiveModal?.close();
    }

    get activeNewsletters() {
        return this.newsletters.filter(n => n.status === 'active');
    }

    get archivedNewsletters() {
        return this.newsletters.filter(n => n.status === 'archived');
    }

    get displayingDefault() {
        return this.statusFilter === 'active' && this.filteredNewsletters.length === 1;
    }

    @action
    changeStatusFilter(status) {
        this.statusFilter = status;
        this.updateFilteredNewsletters();
    }

    @action
    updateFilteredNewsletters() {
        this.filteredNewsletters = this.newsletters.filter((n) => {
            return n.status === this.statusFilter
                && !n.isNew
                && !n.isDestroyed;
        });
    }

    @action
    handleNewRouteChange(transition) {
        // NOTE: this is necessary because ember-drag-drop has forced us into using
        // an explicit tracked filteredNewsletters property rather than using a reactive
        // getter that automatically displays newly added newsletters

        if (transition.from.name === 'settings.members-email-labs.new-newsletter') {
            this.updateFilteredNewsletters();
        }
    }

    @action
    archiveNewsletter(newsletter) {
        this.confirmArchiveModal = this.modals.open(ConfirmArchiveModal, {
            newsletter,
            archiveNewsletterTask: this.archiveNewsletterTask
        });
    }

    @task
    *archiveNewsletterTask(newsletter) {
        newsletter.status = 'archived';
        const result = yield newsletter.save();

        this.updateFilteredNewsletters();

        this.confirmArchiveModal?.close();

        return result;
    }

    @action
    unarchiveNewsletter(newsletter) {
        this.confirmUnarchiveModal = this.modals.open(ConfirmUnarchiveModal, {
            newsletter,
            unarchiveNewsletterTask: this.unarchiveNewsletterTask
        });
    }

    @task
    *unarchiveNewsletterTask(newsletter) {
        newsletter.status = 'active';
        const result = yield newsletter.save();

        if (this.statusFilter === 'archived' && !this.archivedNewsletters.length) {
            this.statusFilter = 'active';
        }

        this.updateFilteredNewsletters();

        this.confirmUnarchiveModal?.close();

        return result;
    }

    @task
    *loadNewslettersTask() {
        const newsletters = yield this.store.findAll('newsletter');

        this.updateFilteredNewsletters();

        return newsletters;
    }

    @task
    *reorderNewslettersTask() {
        // filteredNewsletters is the array that gets updated by <SortableObjects> whilst dragging.
        // we only want to update ordering when _active_ newsletters are re-ordered to make sure
        // archived newsletters don't end up with a lower sort order than active ones

        if (this.statusFilter !== 'active') {
            return;
        }

        // use filteredNewsletters rather than activeNewsletters so we're using'the ordered array
        const activeNewsletters = this.filteredNewsletters;

        const otherNewsletters = this.newsletters
            .filter(n => !activeNewsletters.includes(n))
            .sort(({sortOrder: a}, {sortOrder: b}) => b - a);

        let sortOrder = 0;

        for (const n of [...activeNewsletters, ...otherNewsletters]) {
            n.sortOrder = sortOrder;
            yield n.save();

            sortOrder += 1;
        }
    }
}
<commit_msg>Fixed newsletter list sometimes showing no newsletters<commit_after>import Component from '@glimmer/component';
import ConfirmArchiveModal from '../../modals/edit-newsletter/confirm-archive';
import ConfirmUnarchiveModal from '../../modals/edit-newsletter/confirm-unarchive';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';

export default class NewsletterManagementComponent extends Component {
    @service modals;
    @service router;
    @service store;

    @tracked statusFilter = 'active';
    @tracked filteredNewsletters = [];

    statusFilters = ['active', 'archived'];
    newsletters = this.store.peekAll('newsletter');

    constructor() {
        super(...arguments);
        this.loadNewslettersTask.perform();

        this.router.on('routeDidChange', this.handleNewRouteChange);
    }

    willDestroy() {
        super.willDestroy(...arguments);
        this.router.off('routeDidChange', this.handleNewRouteChange);

        this.confirmArchiveModal?.close();
        this.confirmUnarchiveModal?.close();
    }

    get activeNewsletters() {
        return this.newsletters.filter(n => n.status === 'active');
    }

    get archivedNewsletters() {
        return this.newsletters.filter(n => n.status === 'archived');
    }

    get displayingDefault() {
        return this.statusFilter === 'active' && this.filteredNewsletters.length === 1;
    }

    @action
    changeStatusFilter(status) {
        this.statusFilter = status;
        this.updateFilteredNewsletters();
    }

    @action
    updateFilteredNewsletters() {
        this.filteredNewsletters = this.newsletters.filter((n) => {
            return n.status === this.statusFilter
                && !n.isNew
                && !n.isDestroyed;
        });
    }

    @action
    handleNewRouteChange(transition) {
        // NOTE: this is necessary because ember-drag-drop has forced us into using
        // an explicit tracked filteredNewsletters property rather than using a reactive
        // getter that automatically displays newly added newsletters

        if (transition.from.name === 'settings.members-email-labs.new-newsletter') {
            this.updateFilteredNewsletters();
        }
    }

    @action
    archiveNewsletter(newsletter) {
        this.confirmArchiveModal = this.modals.open(ConfirmArchiveModal, {
            newsletter,
            archiveNewsletterTask: this.archiveNewsletterTask
        });
    }

    @task
    *archiveNewsletterTask(newsletter) {
        newsletter.status = 'archived';
        const result = yield newsletter.save();

        this.updateFilteredNewsletters();

        this.confirmArchiveModal?.close();

        return result;
    }

    @action
    unarchiveNewsletter(newsletter) {
        this.confirmUnarchiveModal = this.modals.open(ConfirmUnarchiveModal, {
            newsletter,
            unarchiveNewsletterTask: this.unarchiveNewsletterTask
        });
    }

    @task
    *unarchiveNewsletterTask(newsletter) {
        newsletter.status = 'active';
        const result = yield newsletter.save();

        if (this.statusFilter === 'archived' && !this.archivedNewsletters.length) {
            this.statusFilter = 'active';
        }

        this.updateFilteredNewsletters();

        this.confirmUnarchiveModal?.close();

        return result;
    }

    @task
    *loadNewslettersTask() {
        const newsletters = yield this.store.findAll('newsletter', {reload: true});

        this.updateFilteredNewsletters();

        return newsletters;
    }

    @task
    *reorderNewslettersTask() {
        // filteredNewsletters is the array that gets updated by <SortableObjects> whilst dragging.
        // we only want to update ordering when _active_ newsletters are re-ordered to make sure
        // archived newsletters don't end up with a lower sort order than active ones

        if (this.statusFilter !== 'active') {
            return;
        }

        // use filteredNewsletters rather than activeNewsletters so we're using'the ordered array
        const activeNewsletters = this.filteredNewsletters;

        const otherNewsletters = this.newsletters
            .filter(n => !activeNewsletters.includes(n))
            .sort(({sortOrder: a}, {sortOrder: b}) => b - a);

        let sortOrder = 0;

        for (const n of [...activeNewsletters, ...otherNewsletters]) {
            n.sortOrder = sortOrder;
            yield n.save();

            sortOrder += 1;
        }
    }
}
<|endoftext|>