<commit_before>const cv = global.dut;
const { assertMetaData, assertPropsWithValue, funcShouldRequireArgs, readTestImage } = global.utils;
const { assert, expect } = require('chai');

describe.only('ximgproc', () => {
  if (!cv.xmodules.ximgproc) {
    it('compiled without ximgproc');
    return;
  }

  let testImg;

  before(() => {
    testImg = readTestImage().resizeToMax(250);
  });

  describe('SuperpixelSEEDS', () => {
    const numSuperpixels = 100;
    const numLevels = 2;

    describe('constructor', () => {
      funcShouldRequireArgs(() => new cv.SuperpixelSEEDS());

      it('should be constructable with required args', () => {
        const superpixelSeeds = new cv.SuperpixelSEEDS(testImg, numSuperpixels, numLevels);
        expect(superpixelSeeds).to.have.property('img').instanceOf(cv.Mat);
        assertMetaData(testImg)(superpixelSeeds.img);
        assertPropsWithValue(superpixelSeeds)({
          numSuperpixels,
          numLevels
        });
      });
    });

    describe('iterate', () => {
      it('should iterate with default values', () => {
        const superpixelSeeds = new cv.SuperpixelSEEDS(testImg, numSuperpixels, numLevels);
        superpixelSeeds.iterate();
        assert(superpixelSeeds.numCalculatedSuperpixels > 0, 'no superpixels calculated');
        assertPropsWithValue(superpixelSeeds.labels)({
          rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
        });
      });
    });
  });

  if (cv.version.minor > 0) {
    describe('SuperpixelSLIC', () => {
      const algorithm = cv.SLICO;

      describe('constructor', () => {
        funcShouldRequireArgs(() => new cv.SuperpixelSLIC());

        it('should be constructable with required args', () => {
          const superpixel = new cv.SuperpixelSLIC(testImg, algorithm);
          expect(superpixel).to.have.property('img').instanceOf(cv.Mat);
          assertMetaData(testImg)(superpixel.img);
          assertPropsWithValue(superpixel)({
            algorithm
          });
        });
      });

      describe('iterate', () => {
        it('should iterate with default values', () => {
          const superpixel = new cv.SuperpixelSLIC(testImg, algorithm);
          superpixel.iterate();
          assert(superpixel.numCalculatedSuperpixels > 0, 'no superpixels calculated');
          assertPropsWithValue(superpixel.labels)({
            rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
          });
        });
      });
    });

    describe('SuperpixelLSC', () => {
      describe('constructor', () => {
        funcShouldRequireArgs(() => new cv.SuperpixelLSC());

        it('should be constructable with required args', () => {
          const superpixel = new cv.SuperpixelLSC(testImg);
          expect(superpixel).to.have.property('img').instanceOf(cv.Mat);
          assertMetaData(testImg)(superpixel.img);
        });
      });

      describe('iterate', () => {
        it('should iterate with default values', () => {
          const superpixel = new cv.SuperpixelLSC(testImg);
          superpixel.iterate();
          assert(superpixel.numCalculatedSuperpixels > 0, 'no superpixels calculated');
          assertPropsWithValue(superpixel.labels)({
            rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
          });
        });
      });
    });
  }
});
<commit_msg>run all tests...<commit_after>const cv = global.dut;
const { assertMetaData, assertPropsWithValue, funcShouldRequireArgs, readTestImage } = global.utils;
const { assert, expect } = require('chai');

describe('ximgproc', () => {
  if (!cv.xmodules.ximgproc) {
    it('compiled without ximgproc');
    return;
  }

  let testImg;

  before(() => {
    testImg = readTestImage().resizeToMax(250);
  });

  describe('SuperpixelSEEDS', () => {
    const numSuperpixels = 100;
    const numLevels = 2;

    describe('constructor', () => {
      funcShouldRequireArgs(() => new cv.SuperpixelSEEDS());

      it('should be constructable with required args', () => {
        const superpixelSeeds = new cv.SuperpixelSEEDS(testImg, numSuperpixels, numLevels);
        expect(superpixelSeeds).to.have.property('img').instanceOf(cv.Mat);
        assertMetaData(testImg)(superpixelSeeds.img);
        assertPropsWithValue(superpixelSeeds)({
          numSuperpixels,
          numLevels
        });
      });
    });

    describe('iterate', () => {
      it('should iterate with default values', () => {
        const superpixelSeeds = new cv.SuperpixelSEEDS(testImg, numSuperpixels, numLevels);
        superpixelSeeds.iterate();
        assert(superpixelSeeds.numCalculatedSuperpixels > 0, 'no superpixels calculated');
        assertPropsWithValue(superpixelSeeds.labels)({
          rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
        });
      });
    });
  });

  if (cv.version.minor > 0) {
    describe('SuperpixelSLIC', () => {
      const algorithm = cv.SLICO;

      describe('constructor', () => {
        funcShouldRequireArgs(() => new cv.SuperpixelSLIC());

        it('should be constructable with required args', () => {
          const superpixel = new cv.SuperpixelSLIC(testImg, algorithm);
          expect(superpixel).to.have.property('img').instanceOf(cv.Mat);
          assertMetaData(testImg)(superpixel.img);
          assertPropsWithValue(superpixel)({
            algorithm
          });
        });
      });

      describe('iterate', () => {
        it('should iterate with default values', () => {
          const superpixel = new cv.SuperpixelSLIC(testImg, algorithm);
          superpixel.iterate();
          assert(superpixel.numCalculatedSuperpixels > 0, 'no superpixels calculated');
          assertPropsWithValue(superpixel.labels)({
            rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
          });
        });
      });
    });

    describe('SuperpixelLSC', () => {
      describe('constructor', () => {
        funcShouldRequireArgs(() => new cv.SuperpixelLSC());

        it('should be constructable with required args', () => {
          const superpixel = new cv.SuperpixelLSC(testImg);
          expect(superpixel).to.have.property('img').instanceOf(cv.Mat);
          assertMetaData(testImg)(superpixel.img);
        });
      });

      describe('iterate', () => {
        it('should iterate with default values', () => {
          const superpixel = new cv.SuperpixelLSC(testImg);
          superpixel.iterate();
          assert(superpixel.numCalculatedSuperpixels > 0, 'no superpixels calculated');
          assertPropsWithValue(superpixel.labels)({
            rows: testImg.rows, cols: testImg.cols, type: cv.CV_32S
          });
        });
      });
    });
  }
});
<|endoftext|>


<commit_before>(function () {

	'use strict';

	var parameters = {
		diameter: 10,
	};

	var geometries;

	QUnit.module( "Extras - Helpers - BoxHelper", {

		beforeEach: function() {
			var greenMaterial = new THREE.MeshBasicMaterial( {color: 0x00ff00} );

			// Test with a normal cube and a box helper
			var boxGeometry = new THREE.BoxGeometry( parameters.diameter );
			var box = new THREE.Mesh( boxGeometry, greenMaterial );
			var boxHelper = new THREE.BoxHelper( box );

			// The same should happen with a comparable sphere
			var sphereGeometry = new THREE.SphereGeometry( parameters.diameter / 2 );
			var sphere = new THREE.Mesh( sphereGeometry, greenMaterial );
			var sphereBoxHelper = new THREE.BoxHelper( sphere );

			// Note that unlike what I'd like to, these doesn't check the equivalency of the two generated geometries
			geometries = [ boxHelper.geometry, sphereBoxHelper.geometry ];
		}

	});

	QUnit.test( "standard geometry tests", function( assert ) {
		runStdGeometryTests( assert, geometries );
	});

})();
<commit_msg>Remove unneeded comma from BoxHelper test<commit_after>(function () {

	'use strict';

	var parameters = {
		diameter: 10
	};

	var geometries;

	QUnit.module( "Extras - Helpers - BoxHelper", {

		beforeEach: function() {
			var greenMaterial = new THREE.MeshBasicMaterial( {color: 0x00ff00} );

			// Test with a normal cube and a box helper
			var boxGeometry = new THREE.BoxGeometry( parameters.diameter );
			var box = new THREE.Mesh( boxGeometry, greenMaterial );
			var boxHelper = new THREE.BoxHelper( box );

			// The same should happen with a comparable sphere
			var sphereGeometry = new THREE.SphereGeometry( parameters.diameter / 2 );
			var sphere = new THREE.Mesh( sphereGeometry, greenMaterial );
			var sphereBoxHelper = new THREE.BoxHelper( sphere );

			// Note that unlike what I'd like to, these doesn't check the equivalency of the two generated geometries
			geometries = [ boxHelper.geometry, sphereBoxHelper.geometry ];
		}

	});

	QUnit.test( "standard geometry tests", function( assert ) {
		runStdGeometryTests( assert, geometries );
	});

})();
<|endoftext|>


<commit_before>export default {
  title: {
    withLocation: 'Annual tree cover loss by dominant driver in {location}',
    global: 'Global annual tree cover loss by dominant driver'
  },
  config: {
    admins: ['global', 'country'],
    selectors: ['tscDriverGroups', 'thresholds', 'startYears', 'endYears'],
    layers: ['loss_by_driver'],
    yearRange: [2001, 2015],
    metaKey: 'widget_tsc_drivers',
    sortOrder: {
      summary: 0,
      forestChange: 0,
      global: 0
    },
    sentences: {
      initial:
        'In {location} from {startYear} to {endYear}, {permPercent} of tree cover loss occurred in areas where the dominant drivers of loss resulted in permanent deforestation.',
      globalInitial:
        '{location} from {startYear} to {endYear}, {permPercent} of tree cover loss occurred in areas where the dominant drivers of loss resulted in permanent deforestation.'
    }
  },
  settings: {
    tscDriverGroup: 'all',
    endYear: 2015,
    layers: ['loss_by_driver']
  },
  enabled: true
};
<commit_msg>Global widget position<commit_after>export default {
  title: {
    withLocation: 'Annual tree cover loss by dominant driver in {location}',
    global: 'Global annual tree cover loss by dominant driver'
  },
  config: {
    admins: ['global', 'country'],
    selectors: ['tscDriverGroups', 'thresholds', 'startYears', 'endYears'],
    layers: ['loss_by_driver'],
    yearRange: [2001, 2015],
    metaKey: 'widget_tsc_drivers',
    sortOrder: {
      summary: 1,
      forestChange: 1,
      global: 1
    },
    sentences: {
      initial:
        'In {location} from {startYear} to {endYear}, {permPercent} of tree cover loss occurred in areas where the dominant drivers of loss resulted in permanent deforestation.',
      globalInitial:
        '{location} from {startYear} to {endYear}, {permPercent} of tree cover loss occurred in areas where the dominant drivers of loss resulted in permanent deforestation.'
    }
  },
  settings: {
    tscDriverGroup: 'all',
    endYear: 2015,
    layers: ['loss_by_driver']
  },
  enabled: true
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Toggle from 'react-toggle';
import AsyncSelect from 'react-select/async';
import { NonceProvider } from 'react-select';
import SettingToggle from '../../notifications/components/setting_toggle';

const messages = defineMessages({
  placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' },
  noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' },
});

export default @injectIntl
class ColumnSettings extends React.PureComponent {

  static propTypes = {
    settings: ImmutablePropTypes.map.isRequired,
    onChange: PropTypes.func.isRequired,
    onLoad: PropTypes.func.isRequired,
    intl: PropTypes.object.isRequired,
  };

  state = {
    open: this.hasTags(),
  };

  hasTags () {
    return ['all', 'any', 'none'].map(mode => this.tags(mode).length > 0).includes(true);
  }

  tags (mode) {
    let tags = this.props.settings.getIn(['tags', mode]) || [];

    if (tags.toJS) {
      return tags.toJS();
    } else {
      return tags;
    }
  };

  onSelect = mode => value => this.props.onChange(['tags', mode], value);

  onToggle = () => {
    if (this.state.open && this.hasTags()) {
      this.props.onChange('tags', {});
    }

    this.setState({ open: !this.state.open });
  };

  noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions);

  modeSelect (mode) {
    return (

          {this.modeLabel(mode)}

        <NonceProvider nonce={document.querySelector('meta[name=style-nonce]').content} cacheKey='tags'>
          <AsyncSelect
            isMulti
            autoFocus
            value={this.tags(mode)}
            onChange={this.onSelect(mode)}
            loadOptions={this.props.onLoad}
            className='column-select__container'
            classNamePrefix='column-select'
            name='tags'
            placeholder={this.props.intl.formatMessage(messages.placeholder)}
            noOptionsMessage={this.noOptionsMessage}
          />
        </NonceProvider>

    );
  }

  modeLabel (mode) {
    switch(mode) {
    case 'any':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.any' defaultMessage='Any of these' />;
    case 'all':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.all' defaultMessage='All of these' />;
    case 'none':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.none' defaultMessage='None of these' />;
    default:
      return '';
    }
  };

  render () {
    const { settings, onChange } = this.props;

    return (

            <Toggle id='hashtag.column_settings.tag_toggle' onChange={this.onToggle} checked={this.state.open} />

              <FormattedMessage id='hashtag.column_settings.tag_toggle' defaultMessage='Include additional tags in this column' />

        {this.state.open && (

            {this.modeSelect('any')}
            {this.modeSelect('all')}
            {this.modeSelect('none')}

        )}

          <SettingToggle settings={settings} settingPath={['local']} onChange={onChange} label={<FormattedMessage id='community.column_settings.local_only' defaultMessage='Local only' />} />

    );
  }

}
<commit_msg>[Glitch] Fix being able to add more than 4 hashtags to hashtag column in web UI<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Toggle from 'react-toggle';
import AsyncSelect from 'react-select/async';
import { NonceProvider } from 'react-select';
import SettingToggle from '../../notifications/components/setting_toggle';

const messages = defineMessages({
  placeholder: { id: 'hashtag.column_settings.select.placeholder', defaultMessage: 'Enter hashtags…' },
  noOptions: { id: 'hashtag.column_settings.select.no_options_message', defaultMessage: 'No suggestions found' },
});

export default @injectIntl
class ColumnSettings extends React.PureComponent {

  static propTypes = {
    settings: ImmutablePropTypes.map.isRequired,
    onChange: PropTypes.func.isRequired,
    onLoad: PropTypes.func.isRequired,
    intl: PropTypes.object.isRequired,
  };

  state = {
    open: this.hasTags(),
  };

  hasTags () {
    return ['all', 'any', 'none'].map(mode => this.tags(mode).length > 0).includes(true);
  }

  tags (mode) {
    let tags = this.props.settings.getIn(['tags', mode]) || [];

    if (tags.toJS) {
      return tags.toJS();
    } else {
      return tags;
    }
  };

  onSelect = mode => value => {
    const oldValue = this.tags(mode);

    // Prevent changes that add more than 4 tags, but allow removing
    // tags that were already added before
    if ((value.length > 4) && !(value < oldValue)) {
      return;
    }

    this.props.onChange(['tags', mode], value);
  };

  onToggle = () => {
    if (this.state.open && this.hasTags()) {
      this.props.onChange('tags', {});
    }

    this.setState({ open: !this.state.open });
  };

  noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions);

  modeSelect (mode) {
    return (

          {this.modeLabel(mode)}

        <NonceProvider nonce={document.querySelector('meta[name=style-nonce]').content} cacheKey='tags'>
          <AsyncSelect
            isMulti
            autoFocus
            value={this.tags(mode)}
            onChange={this.onSelect(mode)}
            loadOptions={this.props.onLoad}
            className='column-select__container'
            classNamePrefix='column-select'
            name='tags'
            placeholder={this.props.intl.formatMessage(messages.placeholder)}
            noOptionsMessage={this.noOptionsMessage}
          />
        </NonceProvider>

    );
  }

  modeLabel (mode) {
    switch(mode) {
    case 'any':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.any' defaultMessage='Any of these' />;
    case 'all':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.all' defaultMessage='All of these' />;
    case 'none':
      return <FormattedMessage id='hashtag.column_settings.tag_mode.none' defaultMessage='None of these' />;
    default:
      return '';
    }
  };

  render () {
    const { settings, onChange } = this.props;

    return (

            <Toggle id='hashtag.column_settings.tag_toggle' onChange={this.onToggle} checked={this.state.open} />

              <FormattedMessage id='hashtag.column_settings.tag_toggle' defaultMessage='Include additional tags in this column' />

        {this.state.open && (

            {this.modeSelect('any')}
            {this.modeSelect('all')}
            {this.modeSelect('none')}

        )}

          <SettingToggle settings={settings} settingPath={['local']} onChange={onChange} label={<FormattedMessage id='community.column_settings.local_only' defaultMessage='Local only' />} />

    );
  }

}
<|endoftext|>


<commit_before>/*jshint multistr: true */

'use strict';

var $ = require('jquery'),
    PulsarSortableComponent = require('../../../js/PulsarSortableComponent');

describe('PulsarSortableComponent', function () {
    beforeEach(function () {

        this.$html = $('

').appendTo('html');
        this.$body = $('

').appendTo(this.$html);
        this.$markup = $('\

\

\
        <button data-toggle="dropdown" class="btn dropdown__toggle">\
            Actions \
            \
        </button>\

\

 New Filter
\

 Random Option
\

\

 Delete
\

\

\

\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\

\

\
').appendTo(this.$body);

        this.$table = this.$html.find('.table');
        this.$rowOne = this.$html.find('.qa-row-one');
        this.$rowTwo = this.$html.find('.qa-row-two');
        this.$moveUp = this.$html.find('[data-move="up"]');
        this.$moveDown = this.$html.find('[data-move="down"]');

        this.pulsarSortable = new PulsarSortableComponent(this.$html);
    });

    describe('The sortable table', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
        });

        it('should have row one at index 0', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should have row two at index 1', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Clicking a move control in row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$moveUp.click();
        });

        it('should hide the move links', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.true;
        });

        it('should add the success icon', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.icon-ok-sign').length).to.equal(1);
        });

        it('should remove the success icon after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.js-sortable-moved').length).to.equal(0);
            }, 1000);
        });

        it('should show the move links after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.false;
            }, 2250);
        });
    });

    describe('Clicking the move down control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="down"]').click();
        });

        it('should move the row down one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(1);
        });

        it('should move the other row up one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(0);
        });
    });

    describe('Clicking the move up control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="up"]').click();
        });

        it('should move the row up one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should move the other row down one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Selecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.true;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.true;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should add a badge to "Actions" dropdown', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').is(':visible')).to.be.true;
        });

        it('should have the word "item" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("item") > 1).to.be.true;
        });
    });

    describe('Deselecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.addClass('is-selected');
            this.$rowOne.find('.checkbox').first().prop('checked', true);
            this.$rowOne.click();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.false;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.false;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });
    });

    describe('When a row is already selected and another row is selected afterwords,', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
            this.$rowTwo.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should increase the number of selected items in the "Actions" dropdown badges', function () {
            expect(this.$html.find('.has-badges .dropdown__toggle .badge').html()).to.equal(2);
        });

        it('should have the word "items" in the Delete dadge', function () {
            expect(this.$html.find('.has-badges .dropdown__menu li:last-child a').text().indexOf("items") > 1).to.be.true;
        });
    });
});
<commit_msg>Add New Test Suits<commit_after>/*jshint multistr: true */

'use strict';

var $ = require('jquery'),
    PulsarSortableComponent = require('../../../js/PulsarSortableComponent');

describe('PulsarSortableComponent', function () {
    beforeEach(function () {

        this.$html = $('

').appendTo('html');
        this.$body = $('

').appendTo(this.$html);
        this.$markup = $('\

\

\
        <button data-toggle="dropdown" class="btn dropdown__toggle">\
            Actions \
            \
        </button>\

\

 New Filter
\

 Random Option
\

\

 Delete
\

\

\

\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\
                foo	\
                	\
                <input type="checkbox" class="form__control checkbox">	\

\

\

\

\
').appendTo(this.$body);

        this.$table = this.$html.find('.table');
        this.$rowOne = this.$html.find('.qa-row-one');
        this.$rowTwo = this.$html.find('.qa-row-two');
        this.$moveUp = this.$html.find('[data-move="up"]');
        this.$moveDown = this.$html.find('[data-move="down"]');

        this.pulsarSortable = new PulsarSortableComponent(this.$html);
    });

    describe('The sortable table', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
        });

        it('should have row one at index 0', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should have row two at index 1', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Clicking a move control in row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$moveUp.click();
        });

        it('should hide the move links', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.true;
        });

        it('should add the success icon', function () {
            expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.icon-ok-sign').length).to.equal(1);
        });

        it('should remove the success icon after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').parent().find('.js-sortable-moved').length).to.equal(0);
            }, 1000);
        });

        it('should show the move links after a delay', function () {
            setTimeout(function (){
                expect(this.$html.find('.qa-row-one [data-move="up"]').hasClass('hide')).to.be.false;
            }, 2250);
        });
    });

    describe('Clicking the move down control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="down"]').click();
        });

        it('should move the row down one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(1);
        });

        it('should move the other row up one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(0);
        });
    });

    describe('Clicking the move up control on row one', function () {
        beforeEach(function () {
            this.pulsarSortable.init();
            this.$rowOne.find('[data-move="up"]').click();
        });

        it('should move the row up one position', function () {
            expect(this.$html.find('.qa-row-one').index()).to.equal(0);
        });

        it('should move the other row down one position', function () {
            expect(this.$html.find('.qa-row-two').index()).to.equal(1);
        });
    });

    describe('Selecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.true;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.true;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should add a badge to "Actions" dropdown', function () {
            expect($('.has-badges .dropdown__toggle .badge').is(':visible')).to.be.true;
        });

        it('should have the word "item" in the Delete dadge', function () {
            expect($('.has-badges .dropdown__menu li:last-child a').text().indexOf("item") > 1).to.be.true;
        });
    });

    describe('Deselecting a table row', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.addClass('is-selected');
            this.$rowOne.find('.checkbox').first().prop('checked', true);
            this.$rowOne.click();
        });

        it('should add class "is-selected"', function () {
            expect(this.$rowOne.hasClass('is-selected')).to.be.false;
        });

        it('should toggle the row\'s checkbox', function () {
            expect(this.$rowOne.find('.checkbox').first().prop('checked')).to.be.false;
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });
    });

    describe('When a row is already selected and another row is selected afterwords,', function () {
        beforeEach(function () {
            this.actionsBadgeStub = sinon.stub(this.pulsarSortable, 'actionsBadge');
            this.pulsarSortable.init();
            this.$rowOne.click();
            this.$rowTwo.click();
        });

        afterEach(function () {
            this.actionsBadgeStub.restore();
        });

        it('should update "Actions" dropdown badge', function () {
            expect(this.actionsBadgeStub).to.have.been.called;
        });

        it('should increase the number of selected items in the "Actions" dropdown badges', function () {
            expect($('.has-badges .dropdown__toggle .badge').text() != "").to.be.true;
        });

        it('should have the word "items" in the Delete dadge', function () {
            expect($('.has-badges .dropdown__menu li:last-child a').text().indexOf("items") > 1).to.be.true;
        });
    });
});
<|endoftext|>


<commit_before>/**
 * Created by Mauriel on 5/19/2019.
 */

let manageAccessApp = new Vue({
    el: '#manage-access',
    delimiters: ['${', '}'],
    data: {
        users: USERS_JSON.map(function(user) {
            user.loading = false;
            return user;
        }),
        currentUser: CURRENT_USER_PK,
        selfAccessLevel: SELF_ACCESS_LEVEL,
        quotaHolder: USERS_JSON.find(function(user) {
            return user.id === QUOTA_HOLDER_PK;
        }),
        resType: RES_TYPE,
        resShortId: SHORT_ID,
        canChangeResourceFlags: CAN_CHANGE_RESOURCE_FLAGS,
        groupImageDefaultUrl: GROUP_IMAGE_DEFAULT_URL,
        resourceMode: RESOURCE_MODE,
        resAccess: RESOURCE_ACCESS,
        canBePublicDiscoverable: CAN_BE_PUBLIC_OR_DISCOVERABLE,
        isInviteUsers: true,
        selectedAccess: 'view',
        accessStr: {
            view: 'Can view',
            edit: 'Can edit',
            owner: 'Is owner'
        },
        error: "",
        quotaError: "",
        sharingError: "",
        isProcessing: false,
        isProcessingAccess: false,
        isProcessingShareable: false,
    },
    watch: {
        resAccess: function (newAccess, oldAccess) {
            // TODO: move to Highlight's component once it's ready
            $("#publish").toggleClass("disabled", !newAccess.isPublic);
            $("#publish > span").attr("data-original-title", !newAccess.isPublic ?
                "Publish this resource<small class='space-top'>You must make your resource public in the Manage Access Panel before it can be published." : "Publish this resource");
            $("#publish").attr("data-toggle", !newAccess.isPublic ? "" : "modal");   // Disable the agreement modal

            let accessStr = "Private";
            if (newAccess.isPublic && newAccess.isDiscoverable) {
                accessStr = "Public"
            }
            else if (!newAccess.isPublic && newAccess.isDiscoverable) {
                accessStr = "Discoverable"
            }
            $("#hl-sharing-status").text(accessStr);    // Update highlight sharing status
        }
    },
    computed: {
        hasOnlyOneOwner: function() {
            return this.users.filter(function(user) {
                return user.access === "owner";
            }).length === 1;
        },
    },
    methods: {
        onChangeAccess: function (user, index, accessToGrant) {
            if (this.currentUser === user.id && user.access === 'owner') {
                this.showPermissionDialog(user, index, accessToGrant)
            }
            else {
                this.changeAccess(user, index, accessToGrant)
            }
        },
        changeAccess: function (user, index, accessToGrant) {
            let vue = this;

            this.error = "";    // Clear errors
            user.loading = true;
            this.isProcessing = true;
            this.users.splice(index, 1, user);

            $.post('/hsapi/_internal/' + this.resShortId + '/share-resource-with-' + user.user_type + '/'
                + accessToGrant + '/' + user.id + '/', function (result) {
                let resp;
                try {
                    resp = JSON.parse(result)
                }
                catch (error) {
                    console.log(error);
                    vue.isProcessing = false;
                    return;
                }

                if (resp.status == "success") {
                    // Access changes to self can't be undone
                    user.can_undo = !(vue.currentUser === user.id);

                    user.access = resp.privilege_granted;
                    vue.users.splice(index, 1, user);
                    if (vue.currentUser === user.id) {
                        vue.selfAccessLevel = user.access;
                    }
                }
                else {
                    console.log(resp);
                    vue.error = resp.error_msg;
                }

                user.loading = false;
                vue.users.splice(index, 1, user);
                vue.isProcessing = false;
            });
        },
        getUserDropdownItemClass: function (user, accessToGrant) {
            let ddClass = {
                active: false,
                disabled: true,
            };

            if (accessToGrant == 'view') {
                ddClass = {
                    active: user.access === 'view',
                    disabled: user.access === 'none'
                }
            }
            else if (accessToGrant == 'edit') {
                ddClass = {
                    active: user.access === 'edit',
                    disabled: this.selfAccessLevel !== 'owner' && this.selfAccessLevel !== 'edit'
                }
            }
            else if (accessToGrant == 'owner') {
                ddClass = {
                    active: user.access === 'owner',
                    disabled: !this.canChangeResourceFlags || this.selfAccessLevel !== 'owner'
                }
            }

            ddClass.disabled = !ddClass.active && (ddClass.disabled || user.access === 'owner' &&
                this.hasOnlyOneOwner || user.id === this.quotaHolder.id);

            return ddClass;
        },
        showPermissionDialog: function (user, index, accessToGrant){
            // close the manage access panel (modal)
            $("#manage-access").modal('hide');

            let vue = this;
            // display change share permission confirmation dialog
            $("#dialog-confirm-change-share-permission").dialog({
                resizable: false,
                draggable: false,
                height: "auto",
                width: 500,
                modal: true,
                dialogClass: 'noclose',
                buttons: {
                    Cancel: function () {
                        $(this).dialog("close");
                        // show manage access control panel again
                        $("#manage-access").modal('show');
                    },
                    "Confirm": function () {
                        $(this).dialog("close");
                        $("#manage-access").modal('show');
                        vue.changeAccess(user, index, accessToGrant);
                    }
                },
                open: function () {
                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:first") // the first button
                        .addClass("btn btn-default");

                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:nth-child(2)") // the first button
                        .addClass("btn btn-danger");
                }
            });
        },
        showDeleteSelfDialog: function (user, index) {
            // close the manage access panel (modal)
            $("#manage-access ").modal("hide");
            let vue = this;

            // display remove access confirmation dialog
            $("#dialog-confirm-delete-self-access").dialog({
                resizable: false,
                draggable: false,
                height: "auto",
                width: 500,
                modal: true,
                dialogClass: 'noclose',
                buttons: {
                    Cancel: function () {
                        $(this).dialog("close");
                        // show manage access control panel again
                        $("#manage-access").modal('show');
                    },
                    "Remove": function () {
                        $(this).dialog("close");
                        vue.removeAccess(user, index);
                    }
                },
                open: function () {
                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:first") // the first button
                        .addClass("btn btn-default");

                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:nth-child(2)") // the second button
                        .addClass("btn btn-danger");
                }
            });
        },
        undoAccess: function (user, index) {
            let vue = this;
            vue.error = "";
            user.loading = true;
            this.users.splice(index, 1, user);

            $.post('/hsapi/_internal/' + this.resShortId + '/undo-share-resource-with-'
                + user.user_type + '/' + user.id + '/', function (resp) {
                if (resp.status === "success") {
                    user.access = resp['undo_' + user.user_type + '_privilege'];
                    user.can_undo = false;
                    if (user.access === "none") {
                        vue.users.splice(index, 1); // The entry was removed
                        return;
                    }
                    else {
                        vue.users.splice(index, 1, user);
                    }
                }
                else {
                    vue.error = resp.error_msg;
                    console.log(resp);
                }

                user.loading = false;
                vue.users.splice(index, 1, user);
                vue.isProcessing = false;
            });
        },
        grantAccess: function () {
            let targetUserId;

            if (this.isInviteUsers) {
                if ($("#user-deck > .hilight").length > 0) {
                    targetUserId = parseInt($("#user-deck > .hilight")[0].getAttribute("data-value"));
                }
                else {
                    return false;   // No user selected
                }
            }
            else {
                if ($("#id_group-deck > .hilight").length > 0) {
                    targetUserId = parseInt($("#id_group-deck > .hilight")[0].getAttribute("data-value"));
                }
                else {
                    return false;   // No group selected
                }
            }

            $(".hilight > span").click(); // Clear the autocomplete
            this.error = "";
            let vue = this;

            let index = -1;
            let user = this.users.filter(function (u, i) {
                const answer = u.id == targetUserId;
                if (answer) {
                    index = i;
                }
                return u.id == targetUserId;
            })[0];

            if (index >= 0) {
                if (user.access === this.selectedAccess) {
                    return; // The user already has this access
                }

                user.loading = true;
                this.users.splice(index, 1, user);
            }
            this.isProcessing = true;

            $.post('/hsapi/_internal/' + this.resShortId + '/share-resource-with-' +
                (this.isInviteUsers ? 'user' : 'group') + '/' + this.selectedAccess + "/" +
                targetUserId + "/", function (result) {
                let resp;
                try {
                    resp = JSON.parse(result)
                }
                catch (error) {
                    console.log(error);
                    vue.error = "Failed to change permission";
                    vue.isProcessing = false;
                    return;
                }

                if (resp.status === "success") {
                    if (index >= 0) {
                        // An entry was found, update the data
                        user.access = resp.privilege_granted;
                        user.loading = false;
                        vue.users.splice(index, 1, user);
                        if (vue.currentUser === user.id) {
                            vue.selfAccessLevel = user.access;
                        }
                    }
                    else {
                        // No entry found. Push new data

                        let pictureUrl;
                        if (vue.isInviteUsers) {
                            pictureUrl = resp.profile_pic === "None" ? null : resp.profile_pic;
                        }
                        else {
                            pictureUrl = resp.group_pic === "None" ? null : resp.group_pic;
                        }

                        const newUserAccess = {
                            user_type: vue.isInviteUsers ? 'user' : 'group',
                            access: resp.privilege_granted,
                            id: targetUserId,
                            pictureUrl: pictureUrl,
                            best_name: resp.name,
                            user_name: resp.username,
                            loading: false,
                            can_undo: true,
                        };

                        vue.users.push(newUserAccess);
                    }
                }
                else {
                    vue.error = resp.error_msg;
                    user.loading = false;
                    vue.users.splice(index, 1, user);
                }
                vue.isProcessing = false;
            });
        },
        removeAccess: function (user, index) {
            user.loading = true;
            this.users.splice(index, 1, user);
            let vue = this;
            vue.error = "";
            this.isProcessing = true;

            $.post('/hsapi/_internal/' + this.resShortId + '/unshare-resource-with-' +
                user.user_type + '/' + user.id + '/', function (resp) {
                if (resp.status === "success") {
                    vue.users.splice(index, 1);
                    vue.isProcessing = false;
                    if (resp.hasOwnProperty('redirect_to')) {
                        window.location.href = resp.redirect_to;
                    }
                }
                else {
                    user.loading = false;
                    vue.users.splice(index, 1, user);
                    vue.error = resp.message;
                    vue.isProcessing = false;
                    console.log(resp);
                }
            });
        },
        setResourceAccess: function (action) {
            let vue = this;
            vue.isProcessingAccess = true;
            $.post('/hsapi/_internal/' + this.resShortId + '/set-resource-flag/',
                {flag: action, 'resource-mode': this.resourceMode}, function (resp) {
                    if (resp.status === 'success') {
                        if (action === 'make_public') {
                            vue.resAccess = {
                                isPublic: true,
                                isDiscoverable: true,
                                isShareable: vue.resAccess.isShareable,
                            };
                        }
                        else if (action === 'make_discoverable') {
                            vue.resAccess = {
                                isPublic: false,
                                isDiscoverable: true,
                                isShareable: vue.resAccess.isShareable,
                            }
                        }
                        else if (action === 'make_private') {
                            vue.resAccess = {
                                isPublic: false,
                                isDiscoverable: false,
                                isShareable: vue.resAccess.isShareable,
                            }
                        }
                    }

                    vue.isProcessingAccess = false;
                }
            );
        },
        setShareable: function (action) {
            let vue = this;
            vue.isProcessingShareable = true;
            vue.sharingError = "";
            $.post('/hsapi/_internal/' + this.resShortId + '/set-resource-flag/',
                {flag: action, 'resource-mode': this.resourceMode}, function (resp) {
                    if (resp.status === "error") {
                        vue.sharingError = resp.message;
                    }
                    vue.isProcessingShareable = false;
                }
            );
        },
        setQuotaHolder: function (username) {
            let vue = this;
            vue.quotaError = "";

            $.post('/hsapi/_internal/' + this.resShortId + '/change-quota-holder/',
                {new_holder_username: username}, function (resp) {
                    if (resp.status === "success") {
                        let newHolder;
                        let index;

                        for (var i = 0; i < vue.users.length; i++) {
                            if (vue.users[i].user_name === username) {
                                newHolder = vue.users[i];
                                index = i;
                                break;
                            }
                        }

                        newHolder.can_undo = false;
                        vue.users.splice(index, 1, newHolder);

                        // Changing quota holder can't be undone
                        vue.quotaHolder = newHolder;
                    }
                    else {
                        vue.quotaError = resp.message;
                    }
                }
            );
        },
        onMetadataInsufficient: function () {
            // Set the resource access to private
            this.resAccess = {
                isPublic: false,
                isDiscoverable: false,
                isShareable: this.resAccess.isShareable,
            };
            // The metadata is insufficient
            this.canBePublicDiscoverable = false;
        }
    },
});<commit_msg>Code cleanup<commit_after>/**
 * Created by Mauriel on 5/19/2019.
 */

let manageAccessApp = new Vue({
    el: '#manage-access',
    delimiters: ['${', '}'],
    data: {
        users: USERS_JSON.map(function(user) {
            user.loading = false;
            return user;
        }),
        currentUser: CURRENT_USER_PK,
        selfAccessLevel: SELF_ACCESS_LEVEL,
        quotaHolder: USERS_JSON.find(function(user) {
            return user.id === QUOTA_HOLDER_PK;
        }),
        resType: RES_TYPE,
        resShortId: SHORT_ID,
        canChangeResourceFlags: CAN_CHANGE_RESOURCE_FLAGS,
        groupImageDefaultUrl: GROUP_IMAGE_DEFAULT_URL,
        resourceMode: RESOURCE_MODE,
        resAccess: RESOURCE_ACCESS,
        canBePublicDiscoverable: CAN_BE_PUBLIC_OR_DISCOVERABLE,
        isInviteUsers: true,
        selectedAccess: 'view',
        accessStr: {
            view: 'Can view',
            edit: 'Can edit',
            owner: 'Is owner'
        },
        error: "",
        quotaError: "",
        sharingError: "",
        isProcessing: false,
        isProcessingAccess: false,
        isProcessingShareable: false,
    },
    watch: {
        resAccess: function (newAccess, oldAccess) {
            // TODO: move to Highlight's component once it's ready
            $("#publish").toggleClass("disabled", !newAccess.isPublic);
            $("#publish > span").attr("data-original-title", !newAccess.isPublic ?
                "Publish this resource<small class='space-top'>You must make your resource public in the Manage Access Panel before it can be published." : "Publish this resource");
            $("#publish").attr("data-toggle", !newAccess.isPublic ? "" : "modal");   // Disable the agreement modal

            let accessStr = "Private";
            if (newAccess.isPublic && newAccess.isDiscoverable) {
                accessStr = "Public"
            }
            else if (!newAccess.isPublic && newAccess.isDiscoverable) {
                accessStr = "Discoverable"
            }
            $("#hl-sharing-status").text(accessStr);    // Update highlight sharing status
        }
    },
    computed: {
        hasOnlyOneOwner: function() {
            return this.users.filter(function(user) {
                return user.access === "owner";
            }).length === 1;
        },
    },
    methods: {
        onChangeAccess: function (user, index, accessToGrant) {
            if (this.currentUser === user.id && user.access === 'owner') {
                this.showPermissionDialog(user, index, accessToGrant)
            }
            else {
                this.changeAccess(user, index, accessToGrant)
            }
        },
        changeAccess: function (user, index, accessToGrant) {
            let vue = this;

            vue.error = "";    // Clear errors
            user.loading = true;
            vue.isProcessing = true;
            vue.users.splice(index, 1, user);

            $.post('/hsapi/_internal/' + this.resShortId + '/share-resource-with-' + user.user_type + '/'
                + accessToGrant + '/' + user.id + '/', function (result) {
                let resp;
                try {
                    resp = JSON.parse(result)
                }
                catch (error) {
                    console.log(error);
                    vue.isProcessing = false;
                    return;
                }

                if (resp.status == "success") {
                    // Access changes to self can't be undone
                    user.can_undo = !(vue.currentUser === user.id);

                    user.access = resp.privilege_granted;
                    vue.users.splice(index, 1, user);
                    if (vue.currentUser === user.id) {
                        vue.selfAccessLevel = user.access;
                    }
                }
                else {
                    console.log(resp);
                    vue.error = resp.error_msg;
                }

                user.loading = false;
                vue.users.splice(index, 1, user);
                vue.isProcessing = false;
            });
        },
        getUserDropdownItemClass: function (user, accessToGrant) {
            let ddClass = {
                active: false,
                disabled: true,
            };

            if (accessToGrant == 'view') {
                ddClass = {
                    active: user.access === 'view',
                    disabled: user.access === 'none'
                }
            }
            else if (accessToGrant == 'edit') {
                ddClass = {
                    active: user.access === 'edit',
                    disabled: this.selfAccessLevel !== 'owner' && this.selfAccessLevel !== 'edit'
                }
            }
            else if (accessToGrant == 'owner') {
                ddClass = {
                    active: user.access === 'owner',
                    disabled: !this.canChangeResourceFlags || this.selfAccessLevel !== 'owner'
                }
            }

            ddClass.disabled = !ddClass.active && (ddClass.disabled || user.access === 'owner' &&
                this.hasOnlyOneOwner || user.id === this.quotaHolder.id);

            return ddClass;
        },
        showPermissionDialog: function (user, index, accessToGrant){
            // close the manage access panel (modal)
            $("#manage-access").modal('hide');

            let vue = this;
            // display change share permission confirmation dialog
            $("#dialog-confirm-change-share-permission").dialog({
                resizable: false,
                draggable: false,
                height: "auto",
                width: 500,
                modal: true,
                dialogClass: 'noclose',
                buttons: {
                    Cancel: function () {
                        $(this).dialog("close");
                        // show manage access control panel again
                        $("#manage-access").modal('show');
                    },
                    "Confirm": function () {
                        $(this).dialog("close");
                        $("#manage-access").modal('show');
                        vue.changeAccess(user, index, accessToGrant);
                    }
                },
                open: function () {
                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:first") // the first button
                        .addClass("btn btn-default");

                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:nth-child(2)") // the first button
                        .addClass("btn btn-danger");
                }
            });
        },
        showDeleteSelfDialog: function (user, index) {
            // close the manage access panel (modal)
            $("#manage-access ").modal("hide");
            let vue = this;

            // display remove access confirmation dialog
            $("#dialog-confirm-delete-self-access").dialog({
                resizable: false,
                draggable: false,
                height: "auto",
                width: 500,
                modal: true,
                dialogClass: 'noclose',
                buttons: {
                    Cancel: function () {
                        $(this).dialog("close");
                        // show manage access control panel again
                        $("#manage-access").modal('show');
                    },
                    "Remove": function () {
                        $(this).dialog("close");
                        vue.removeAccess(user, index);
                    }
                },
                open: function () {
                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:first") // the first button
                        .addClass("btn btn-default");

                    $(this).closest(".ui-dialog")
                        .find(".ui-dialog-buttonset button:nth-child(2)") // the second button
                        .addClass("btn btn-danger");
                }
            });
        },
        undoAccess: function (user, index) {
            let vue = this;
            vue.error = "";
            user.loading = true;
            vue.users.splice(index, 1, user);

            $.post('/hsapi/_internal/' + this.resShortId + '/undo-share-resource-with-'
                + user.user_type + '/' + user.id + '/', function (resp) {
                if (resp.status === "success") {
                    user.access = resp['undo_' + user.user_type + '_privilege'];
                    user.can_undo = false;
                    if (user.access === "none") {
                        vue.users.splice(index, 1); // The entry was removed
                        return;
                    }
                    else {
                        vue.users.splice(index, 1, user);
                    }
                }
                else {
                    vue.error = resp.error_msg;
                    console.log(resp);
                }

                user.loading = false;
                vue.users.splice(index, 1, user);
                vue.isProcessing = false;
            });
        },
        grantAccess: function () {
            let targetUserId;

            if (this.isInviteUsers) {
                if ($("#user-deck > .hilight").length > 0) {
                    targetUserId = parseInt($("#user-deck > .hilight")[0].getAttribute("data-value"));
                }
                else {
                    return false;   // No user selected
                }
            }
            else {
                if ($("#id_group-deck > .hilight").length > 0) {
                    targetUserId = parseInt($("#id_group-deck > .hilight")[0].getAttribute("data-value"));
                }
                else {
                    return false;   // No group selected
                }
            }

            $(".hilight > span").click(); // Clear the autocomplete
            this.error = "";
            let vue = this;

            let index = -1;
            let user = this.users.filter(function (u, i) {
                const answer = u.id == targetUserId;
                if (answer) {
                    index = i;
                }
                return u.id == targetUserId;
            })[0];

            if (index >= 0) {
                if (user.access === this.selectedAccess) {
                    return; // The user already has this access
                }

                user.loading = true;
                this.users.splice(index, 1, user);
            }
            this.isProcessing = true;

            $.post('/hsapi/_internal/' + this.resShortId + '/share-resource-with-' +
                (this.isInviteUsers ? 'user' : 'group') + '/' + this.selectedAccess + "/" +
                targetUserId + "/", function (result) {
                let resp;
                try {
                    resp = JSON.parse(result)
                }
                catch (error) {
                    console.log(error);
                    vue.error = "Failed to change permission";
                    vue.isProcessing = false;
                    return;
                }

                if (resp.status === "success") {
                    if (index >= 0) {
                        // An entry was found, update the data
                        user.access = resp.privilege_granted;
                        user.loading = false;
                        vue.users.splice(index, 1, user);
                        if (vue.currentUser === user.id) {
                            vue.selfAccessLevel = user.access;
                        }
                    }
                    else {
                        // No entry found. Push new data

                        let pictureUrl;
                        if (vue.isInviteUsers) {
                            pictureUrl = resp.profile_pic === "None" ? null : resp.profile_pic;
                        }
                        else {
                            pictureUrl = resp.group_pic === "None" ? null : resp.group_pic;
                        }

                        const newUserAccess = {
                            user_type: vue.isInviteUsers ? 'user' : 'group',
                            access: resp.privilege_granted,
                            id: targetUserId,
                            pictureUrl: pictureUrl,
                            best_name: resp.name,
                            user_name: resp.username,
                            loading: false,
                            can_undo: true,
                        };

                        vue.users.push(newUserAccess);
                    }
                }
                else {
                    vue.error = resp.error_msg;
                    user.loading = false;
                    vue.users.splice(index, 1, user);
                }
                vue.isProcessing = false;
            });
        },
        removeAccess: function (user, index) {
            user.loading = true;
            this.users.splice(index, 1, user);
            let vue = this;
            vue.error = "";
            this.isProcessing = true;

            $.post('/hsapi/_internal/' + this.resShortId + '/unshare-resource-with-' +
                user.user_type + '/' + user.id + '/', function (resp) {
                if (resp.status === "success") {
                    vue.users.splice(index, 1);
                    vue.isProcessing = false;
                    if (resp.hasOwnProperty('redirect_to')) {
                        window.location.href = resp.redirect_to;
                    }
                }
                else {
                    user.loading = false;
                    vue.users.splice(index, 1, user);
                    vue.error = resp.message;
                    vue.isProcessing = false;
                    console.log(resp);
                }
            });
        },
        setResourceAccess: function (action) {
            let vue = this;
            vue.isProcessingAccess = true;
            $.post('/hsapi/_internal/' + this.resShortId + '/set-resource-flag/',
                {flag: action, 'resource-mode': this.resourceMode}, function (resp) {
                    if (resp.status === 'success') {
                        if (action === 'make_public') {
                            vue.resAccess = {
                                isPublic: true,
                                isDiscoverable: true,
                                isShareable: vue.resAccess.isShareable,
                            };
                        }
                        else if (action === 'make_discoverable') {
                            vue.resAccess = {
                                isPublic: false,
                                isDiscoverable: true,
                                isShareable: vue.resAccess.isShareable,
                            }
                        }
                        else if (action === 'make_private') {
                            vue.resAccess = {
                                isPublic: false,
                                isDiscoverable: false,
                                isShareable: vue.resAccess.isShareable,
                            }
                        }
                    }

                    vue.isProcessingAccess = false;
                }
            );
        },
        setShareable: function (action) {
            let vue = this;
            vue.isProcessingShareable = true;
            vue.sharingError = "";
            $.post('/hsapi/_internal/' + this.resShortId + '/set-resource-flag/',
                {flag: action, 'resource-mode': this.resourceMode}, function (resp) {
                    if (resp.status === "error") {
                        vue.sharingError = resp.message;
                    }
                    vue.isProcessingShareable = false;
                }
            );
        },
        setQuotaHolder: function (username) {
            let vue = this;
            vue.quotaError = "";

            $.post('/hsapi/_internal/' + this.resShortId + '/change-quota-holder/',
                {new_holder_username: username}, function (resp) {
                    if (resp.status === "success") {
                        let newHolder;
                        let index;

                        for (var i = 0; i < vue.users.length; i++) {
                            if (vue.users[i].user_name === username) {
                                newHolder = vue.users[i];
                                index = i;
                                break;
                            }
                        }

                        newHolder.can_undo = false;
                        vue.users.splice(index, 1, newHolder);

                        // Changing quota holder can't be undone
                        vue.quotaHolder = newHolder;
                    }
                    else {
                        vue.quotaError = resp.message;
                    }
                }
            );
        },
        onMetadataInsufficient: function () {
            // Set the resource access to private
            this.resAccess = {
                isPublic: false,
                isDiscoverable: false,
                isShareable: this.resAccess.isShareable,
            };
            // The metadata is insufficient
            this.canBePublicDiscoverable = false;
        }
    },
});<|endoftext|>


<commit_before>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    console.log( 0 - $(event.target).scrollTop(), document.body.scrollTop )
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
})<commit_msg>Remove console.<commit_after>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
})<|endoftext|>


<commit_before>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

import Velocity   from 'velocity';

import Tabs       from 'tabs';
import * as waves from 'waves';

let tabsitemid = 0;

const tabsitem = [{
        name: "共通",
        value: "common",
        active : true,
        route: "#common",
    },{
        name: "聚焦模式",
        value: "focus",
        route: "#focus",
    },{
        name: "阅读模式",
        value: "read",
        route: "#read",
    },{
        name: "稍后读",
        value: "later",
        route: "#later",
}],
    bgColors = [
        "rgba(153, 204, 255, 1)",
        "rgba(204, 204, 255, 1)",
        "rgba(255, 153, 204, 1)",
        "rgba(204, 255, 0, 1)"
];

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
});

/**
 * Waves render
 */
waves.Render({ root: "main", name: "sr-tabs" });

/**
 * Tabs onChange event handler
 *
 * @param {jquery} prev jquery object
 * @param {event} current event
 */
function tabsOnChange( $prev, event ) {
    let $target = $( event.target );
    while ( !$target.is( "tab-label" ) ) { $target = $target.parent(); }
    $target     = $target.find( "a" );

    const idx   = $target.attr( "id" ),
          value = $target.attr( "value" ),
          name  = $target.text();

    Render( idx );
}

/**
 * Tabs render
 *
 * @param {string} header background color
 */
function tabsRender( color ) {
    const tabs = <Tabs waves="sr-tabs waves-effect waves-light"
                    headerStyle={{ transition: 'all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 0ms' }}
                    bgColor={ color }
                    items={ tabsitem }
                    onChange={ ( $p, evt )=>tabsOnChange( $p, evt ) }>

aaa

bbb

ccc

ddd

                </Tabs>;
    ReactDOM.render( tabs, $( ".tabscontainer" )[0] );
}

/**
 * Set banner and tabs.Render()
 *
 * @param {number} bgColors index
 */
function Render( idx ) {
    $( ".banner" ).css( "background-image", `url(../assets/images/banner-${idx}.png)` );
    tabsRender( bgColors[ idx ] );
}

/**
 * Get tabsitemid from window.location.hash exist
 */
window.location.hash && ( tabsitemid = tabsitem.findIndex( item => item.route == window.location.hash ) );
tabsitemid == -1 || tabsitemid == 0 ? tabsitemid = 0 : tabsitem.forEach( ( item, index ) => item.active = tabsitemid == index ? true : false );

/**
 * Entry Render
 */
Render( tabsitemid );<commit_msg>Format source.<commit_after>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

import Velocity   from 'velocity';

import Tabs       from 'tabs';
import * as waves from 'waves';

let tabsItemID = 0;

const tabsItem = [{
        name: "共通",
        value: "common",
        active : true,
        route: "#common",
    },{
        name: "聚焦模式",
        value: "focus",
        route: "#focus",
    },{
        name: "阅读模式",
        value: "read",
        route: "#read",
    },{
        name: "稍后读",
        value: "later",
        route: "#later",
}],
    bgColors = [
        "rgba(153, 204, 255, 1)",
        "rgba(204, 204, 255, 1)",
        "rgba(255, 153, 204, 1)",
        "rgba(204, 255, 0, 1)"
];

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
});

/**
 * Waves render
 */
waves.Render({ root: "main", name: "sr-tabs" });

/**
 * Tabs onChange event handler
 *
 * @param {jquery} prev jquery object
 * @param {event} current event
 */
function tabsOnChange( $prev, event ) {
    let $target = $( event.target );
    while ( !$target.is( "tab-label" ) ) { $target = $target.parent(); }
    $target     = $target.find( "a" );

    const idx   = $target.attr( "id" ),
          value = $target.attr( "value" ),
          name  = $target.text();

    Render( idx );
}

/**
 * Tabs render
 *
 * @param {string} header background color
 */
function tabsRender( color ) {
    const tabs = <Tabs waves="sr-tabs waves-effect waves-light"
                    headerStyle={{ transition: 'all 1000ms cubic-bezier(0.23, 1, 0.32, 1) 0ms' }}
                    bgColor={ color }
                    items={ tabsItem }
                    onChange={ ( $p, evt )=>tabsOnChange( $p, evt ) }>

aaa

bbb

ccc

ddd

                </Tabs>;
    ReactDOM.render( tabs, $( ".tabscontainer" )[0] );
}

/**
 * Set banner and tabs.Render()
 *
 * @param {number} bgColors index
 */
function Render( idx ) {
    $( ".banner" ).css( "background-image", `url(../assets/images/banner-${idx}.png)` );
    tabsRender( bgColors[ idx ] );
}

/**
 * Get tabsItemID from window.location.hash exist
 */
window.location.hash && ( tabsItemID = tabsItem.findIndex( item => item.route == window.location.hash ) );
tabsItemID == -1 || tabsItemID == 0 ? tabsItemID = 0 : tabsItem.forEach( ( item, index ) => item.active = tabsItemID == index ? true : false );

/**
 * Entry Render
 */
Render( tabsItemID );<|endoftext|>


<commit_before>/**
 * @ngdoc function
 * @name fstepApp.controller:WorkspaceCtrl
 * @description
 * # WorkspaceCtrl
 * Controller of the fstepApp
 */
'use strict';

define(['../../../fstepmodules'], function (fstepmodules) {

    fstepmodules.controller('WorkspaceCtrl', [ '$scope', 'JobService', 'SystematicService', 'ProductService', 'SearchService', 'MapService', 'CommonService', function ($scope, JobService, SystematicService, ProductService, SearchService, MapService, CommonService) {

        $scope.serviceParams = ProductService.params.explorer;
        $scope.runModes = ProductService.serviceRunModes;
        $scope.isWorkspaceLoading = false;

        $scope.searchForm = {
            config: {},
            api: {},
            data: {
                catalogue: 'SATELLITE'
            }
        }

        SearchService.getSearchParameters().then(function(data){

            delete data.productDate;
            delete data.catalogue;

            var config = {
                productDateStart: {
                    type: 'date',
                    defaultValue: '0',
                    description: 'UTC',
                    title: 'Processing start'
                },
                productDateEnd: {
                    type: 'date',
                    defaultValue: '0',
                    description: 'UTC',
                    optional: true,
                    format: 'YYYY-MM-DD[T23:59:59Z]',
                    title: 'Processing end'
                }
            }

            delete data.catalogue;

            $scope.searchForm.config = Object.assign(config, data);
        });

        $scope.$on('update.selectedService', function(event, service, inputs, label, parent, systematicParameter) {
            $scope.isWorkspaceLoading = true;
            $scope.serviceParams.inputValues = {};
            $scope.serviceParams.label = label;
            $scope.serviceParams.parent = parent;
            $scope.serviceParams.dropLists = {};
            if(inputs){
                for (var key in inputs) {
                    $scope.serviceParams.inputValues[key] = inputs[key][0]; //First value is the actual input

                    //if value has links in it, add also to dropList to show file chips
                    if(inputs[key][0].indexOf('://') > -1){
                        var list = inputs[key][0].split(',');
                        $scope.serviceParams.dropLists[key] = [];
                        for(var index in list){
                            $scope.serviceParams.dropLists[key].push({ link: list[index] });
                        }
                    }
                }
            }

            ProductService.getService(service).then(function(detailedService){
                $scope.serviceParams.selectedService = detailedService;
                if (detailedService.type !== 'APPLICATION') {
                    if (systematicParameter) {
                        $scope.serviceParams.runMode = $scope.runModes.SYSTEMATIC.id;
                        $scope.serviceParams.systematicParameter = systematicParameter;
                    }
                    else if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                        $scope.serviceParams.systematicParameter = detailedService.serviceDescriptor.dataInputs[0].id;
                    }
                }
                else {
                    $scope.serviceParams.runMode = $scope.runModes.STANDARD.id;
                    delete $scope.serviceParams.systematicParameter;
                }
                $scope.isWorkspaceLoading = false;
            });
        });

        $scope.onRunModeChange = function() {
            if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                $scope.serviceParams.systematicParameter = $scope.serviceParams.selectedService ? $scope.serviceParams.selectedService.serviceDescriptor.dataInputs[0].id : null;
            }
            else {
                delete $scope.serviceParams.systematicParameter;
            }
        }

        $scope.getDefaultValue = function(fieldDesc){
            return $scope.serviceParams.inputValues[fieldDesc.id] ? $scope.serviceParams.inputValues[fieldDesc.id] : fieldDesc.defaultAttrs.value;
        };

        $scope.launchProcessing = function($event) {
            var iparams={};

            for(var key in $scope.serviceParams.inputValues){
                var value = $scope.serviceParams.inputValues[key];
                if(value === undefined){
                    value = '';
                }
                iparams[key] = [value];
            }

            if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                delete iparams[$scope.serviceParams.systematicParameter];

                var searchParams = $scope.searchForm.api.getFormData();
                searchParams.catalogue = 'SATELLITE';

                SystematicService.estimateMonthlyCost($scope.serviceParams.selectedService, $scope.serviceParams.systematicParameter, iparams, searchParams).then(function(estimation) {
                    console.log(iparams);
                    console.log($scope.searchForm.api.getFormData());
                    var currency = ( estimation.estimatedCost === 1 ? 'coin' : 'coins' );
                    CommonService.confirm($event, 'This job will approximatelly cost ' + estimation.estimatedCost + ' ' + currency + ' per month.' +
                            '\nAre you sure you want to continue?').then(function (confirmed) {
                        if (confirmed === false) {
                            return;
                        }
                        $scope.displayTab($scope.bottomNavTabs.JOBS, false);

                        SystematicService.launchSystematicProcessing($scope.serviceParams.selectedService, $scope.serviceParams.systematicParameter, iparams, searchParams, $scope.serviceParams.label).then(function () {
                            JobService.refreshJobs("explorer", "Create");
                        });

                    });
                });

            }
            else {
                JobService.createJobConfig($scope.serviceParams.selectedService, iparams, $scope.serviceParams.label,  $scope.serviceParams.parent).then(function(jobConfig){
                    JobService.estimateJob(jobConfig, $event).then(function(estimation){

                        var currency = ( estimation.estimatedCost === 1 ? 'coin' : 'coins' );
                        CommonService.confirm($event, 'This job will cost ' + estimation.estimatedCost + ' ' + currency + '.' +
                                '\nAre you sure you want to continue?').then(function (confirmed) {
                            if (confirmed === false) {
                                return;
                            }
                            $scope.displayTab($scope.bottomNavTabs.JOBS, false);
                            JobService.launchJob(jobConfig, $scope.serviceParams.selectedService, 'explorer').then(function () {
                                JobService.refreshJobs("explorer", "Create");
                            });
                        });
                    },
                    function (error) {
                        CommonService.infoBulletin($event, 'The cost of this job exceeds your balance. This job cannot be run.' +
                                                '\nYour balance: ' + error.currentWalletBalance + '\nCost estimation: ' + error.estimatedCost);
                    });
                });
            }
        };

        $scope.pastePolygon = function(identifier){
            $scope.serviceParams.inputValues[identifier] = MapService.getPolygonWkt();
        };

        /** DRAG-AND-DROP FILES TO THE INPUT FIELD **/
        $scope.onDrop = function(dropObject, fieldId) {
            if($scope.serviceParams.dropLists[fieldId] === undefined){
                $scope.serviceParams.dropLists[fieldId] = [];
            }

            var file = {};

            if(dropObject && dropObject.type === 'outputs') {
                for(var i = 0; i < dropObject.selectedOutputs.length; i++){
                    file = {
                        name: dropObject.selectedOutputs[i]._links.fstep.href,
                        link: dropObject.selectedOutputs[i]._links.fstep.href,
                        start: dropObject.job.startTime,
                        stop: dropObject.job.endTime
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else if(dropObject && dropObject.type === 'results') {
                for(var j = 0; j < dropObject.selectedItems.length; j++){
                    file = {
                        name: dropObject.selectedItems[j].properties._links.fstep.href,
                        link: dropObject.selectedItems[j].properties._links.fstep.href,
                        start: dropObject.selectedItems[j].properties.extraParams.fstepStartTime,
                        stop: dropObject.selectedItems[j].properties.extraParams.fstepEndTime,
                        bytes: dropObject.selectedItems[j].properties.filesize
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else if(dropObject && dropObject.type === 'databasket') {
                file = {
                    name: "Databasket: " + dropObject.basket.name,
                    link: dropObject.basket._links.fstep.href
                };
                if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                    $scope.serviceParams.dropLists[fieldId].push(file);
                }
                setFilesInputString(fieldId);
                return true;
            }
            else if(dropObject && dropObject.type === 'basketItems') {
                for(var k = 0; k < dropObject.selectedItems.length; k++) {
                    file = {
                        name: dropObject.selectedItems[k]._links.fstep.href,
                        link: dropObject.selectedItems[k]._links.fstep.href
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else {
                return false;
            }
            return true;
        };

        function setFilesInputString(fieldId){
            var pathsStr = '';
            for(var i = 0; i < $scope.serviceParams.dropLists[fieldId].length; i++){
                pathsStr += ',' + $scope.serviceParams.dropLists[fieldId][i].link;
            }
            $scope.serviceParams.inputValues[fieldId] = pathsStr.substring(1);
        }

        $scope.removeSelectedItem = function(fieldId, item){
            var index = $scope.serviceParams.dropLists[fieldId].indexOf(item);
            $scope.serviceParams.dropLists[fieldId].splice(index, 1);
            setFilesInputString(fieldId);
        };

        $scope.updateDropList = function(fieldId){
            if($scope.serviceParams.inputValues[fieldId] && $scope.serviceParams.inputValues[fieldId].indexOf('://') > -1) {
                var csvList = $scope.serviceParams.inputValues[fieldId].split(',');
                if($scope.serviceParams.dropLists[fieldId] === undefined){
                    $scope.serviceParams.dropLists[fieldId] = [];
                }
                var newDropList = [];
                for(var index in csvList){
                    var exists = false;
                    for(var i in $scope.serviceParams.dropLists[fieldId]){
                        if($scope.serviceParams.dropLists[fieldId][i].link === csvList[index]){
                            newDropList.push($scope.serviceParams.dropLists[fieldId][i]);
                            exists = true;
                        }
                    }
                    if(!exists && csvList[index] !== ''){
                        newDropList.push({link: csvList[index]});
                    }
                }
                $scope.serviceParams.dropLists[fieldId] = newDropList;
            } else {
                $scope.serviceParams.dropLists[fieldId] = undefined;
            }
        };

    }]);
});
<commit_msg>Fix label of product start date <commit_after>/**
 * @ngdoc function
 * @name fstepApp.controller:WorkspaceCtrl
 * @description
 * # WorkspaceCtrl
 * Controller of the fstepApp
 */
'use strict';

define(['../../../fstepmodules'], function (fstepmodules) {

    fstepmodules.controller('WorkspaceCtrl', [ '$scope', 'JobService', 'SystematicService', 'ProductService', 'SearchService', 'MapService', 'CommonService', function ($scope, JobService, SystematicService, ProductService, SearchService, MapService, CommonService) {

        $scope.serviceParams = ProductService.params.explorer;
        $scope.runModes = ProductService.serviceRunModes;
        $scope.isWorkspaceLoading = false;

        $scope.searchForm = {
            config: {},
            api: {},
            data: {
                catalogue: 'SATELLITE'
            }
        }

        SearchService.getSearchParameters().then(function(data){

            delete data.productDate;
            delete data.catalogue;

            var config = {
                productDateStart: {
                    type: 'date',
                    defaultValue: '0',
                    description: 'UTC',
                    title: 'Product start date'
                },
                productDateEnd: {
                    type: 'date',
                    defaultValue: '0',
                    description: 'UTC',
                    optional: true,
                    format: 'YYYY-MM-DD[T23:59:59Z]',
                    title: 'Product end date'
                }
            }

            delete data.catalogue;

            $scope.searchForm.config = Object.assign(config, data);
        });

        $scope.$on('update.selectedService', function(event, service, inputs, label, parent, systematicParameter) {
            $scope.isWorkspaceLoading = true;
            $scope.serviceParams.inputValues = {};
            $scope.serviceParams.label = label;
            $scope.serviceParams.parent = parent;
            $scope.serviceParams.dropLists = {};
            if(inputs){
                for (var key in inputs) {
                    $scope.serviceParams.inputValues[key] = inputs[key][0]; //First value is the actual input

                    //if value has links in it, add also to dropList to show file chips
                    if(inputs[key][0].indexOf('://') > -1){
                        var list = inputs[key][0].split(',');
                        $scope.serviceParams.dropLists[key] = [];
                        for(var index in list){
                            $scope.serviceParams.dropLists[key].push({ link: list[index] });
                        }
                    }
                }
            }

            ProductService.getService(service).then(function(detailedService){
                $scope.serviceParams.selectedService = detailedService;
                if (detailedService.type !== 'APPLICATION') {
                    if (systematicParameter) {
                        $scope.serviceParams.runMode = $scope.runModes.SYSTEMATIC.id;
                        $scope.serviceParams.systematicParameter = systematicParameter;
                    }
                    else if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                        $scope.serviceParams.systematicParameter = detailedService.serviceDescriptor.dataInputs[0].id;
                    }
                }
                else {
                    $scope.serviceParams.runMode = $scope.runModes.STANDARD.id;
                    delete $scope.serviceParams.systematicParameter;
                }
                $scope.isWorkspaceLoading = false;
            });
        });

        $scope.onRunModeChange = function() {
            if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                $scope.serviceParams.systematicParameter = $scope.serviceParams.selectedService ? $scope.serviceParams.selectedService.serviceDescriptor.dataInputs[0].id : null;
            }
            else {
                delete $scope.serviceParams.systematicParameter;
            }
        }

        $scope.getDefaultValue = function(fieldDesc){
            return $scope.serviceParams.inputValues[fieldDesc.id] ? $scope.serviceParams.inputValues[fieldDesc.id] : fieldDesc.defaultAttrs.value;
        };

        $scope.launchProcessing = function($event) {
            var iparams={};

            for(var key in $scope.serviceParams.inputValues){
                var value = $scope.serviceParams.inputValues[key];
                if(value === undefined){
                    value = '';
                }
                iparams[key] = [value];
            }

            if ($scope.serviceParams.runMode === $scope.runModes.SYSTEMATIC.id) {
                delete iparams[$scope.serviceParams.systematicParameter];

                var searchParams = $scope.searchForm.api.getFormData();
                searchParams.catalogue = 'SATELLITE';

                SystematicService.estimateMonthlyCost($scope.serviceParams.selectedService, $scope.serviceParams.systematicParameter, iparams, searchParams).then(function(estimation) {
                    console.log(iparams);
                    console.log($scope.searchForm.api.getFormData());
                    var currency = ( estimation.estimatedCost === 1 ? 'coin' : 'coins' );
                    CommonService.confirm($event, 'This job will approximatelly cost ' + estimation.estimatedCost + ' ' + currency + ' per month.' +
                            '\nAre you sure you want to continue?').then(function (confirmed) {
                        if (confirmed === false) {
                            return;
                        }
                        $scope.displayTab($scope.bottomNavTabs.JOBS, false);

                        SystematicService.launchSystematicProcessing($scope.serviceParams.selectedService, $scope.serviceParams.systematicParameter, iparams, searchParams, $scope.serviceParams.label).then(function () {
                            JobService.refreshJobs("explorer", "Create");
                        });

                    });
                });

            }
            else {
                JobService.createJobConfig($scope.serviceParams.selectedService, iparams, $scope.serviceParams.label,  $scope.serviceParams.parent).then(function(jobConfig){
                    JobService.estimateJob(jobConfig, $event).then(function(estimation){

                        var currency = ( estimation.estimatedCost === 1 ? 'coin' : 'coins' );
                        CommonService.confirm($event, 'This job will cost ' + estimation.estimatedCost + ' ' + currency + '.' +
                                '\nAre you sure you want to continue?').then(function (confirmed) {
                            if (confirmed === false) {
                                return;
                            }
                            $scope.displayTab($scope.bottomNavTabs.JOBS, false);
                            JobService.launchJob(jobConfig, $scope.serviceParams.selectedService, 'explorer').then(function () {
                                JobService.refreshJobs("explorer", "Create");
                            });
                        });
                    },
                    function (error) {
                        CommonService.infoBulletin($event, 'The cost of this job exceeds your balance. This job cannot be run.' +
                                                '\nYour balance: ' + error.currentWalletBalance + '\nCost estimation: ' + error.estimatedCost);
                    });
                });
            }
        };

        $scope.pastePolygon = function(identifier){
            $scope.serviceParams.inputValues[identifier] = MapService.getPolygonWkt();
        };

        /** DRAG-AND-DROP FILES TO THE INPUT FIELD **/
        $scope.onDrop = function(dropObject, fieldId) {
            if($scope.serviceParams.dropLists[fieldId] === undefined){
                $scope.serviceParams.dropLists[fieldId] = [];
            }

            var file = {};

            if(dropObject && dropObject.type === 'outputs') {
                for(var i = 0; i < dropObject.selectedOutputs.length; i++){
                    file = {
                        name: dropObject.selectedOutputs[i]._links.fstep.href,
                        link: dropObject.selectedOutputs[i]._links.fstep.href,
                        start: dropObject.job.startTime,
                        stop: dropObject.job.endTime
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else if(dropObject && dropObject.type === 'results') {
                for(var j = 0; j < dropObject.selectedItems.length; j++){
                    file = {
                        name: dropObject.selectedItems[j].properties._links.fstep.href,
                        link: dropObject.selectedItems[j].properties._links.fstep.href,
                        start: dropObject.selectedItems[j].properties.extraParams.fstepStartTime,
                        stop: dropObject.selectedItems[j].properties.extraParams.fstepEndTime,
                        bytes: dropObject.selectedItems[j].properties.filesize
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else if(dropObject && dropObject.type === 'databasket') {
                file = {
                    name: "Databasket: " + dropObject.basket.name,
                    link: dropObject.basket._links.fstep.href
                };
                if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                    $scope.serviceParams.dropLists[fieldId].push(file);
                }
                setFilesInputString(fieldId);
                return true;
            }
            else if(dropObject && dropObject.type === 'basketItems') {
                for(var k = 0; k < dropObject.selectedItems.length; k++) {
                    file = {
                        name: dropObject.selectedItems[k]._links.fstep.href,
                        link: dropObject.selectedItems[k]._links.fstep.href
                    };
                    if($scope.serviceParams.inputValues[fieldId] === undefined || $scope.serviceParams.inputValues[fieldId].indexOf(file.link) < 0){
                        $scope.serviceParams.dropLists[fieldId].push(file);
                    }
                }
                setFilesInputString(fieldId);
            }
            else {
                return false;
            }
            return true;
        };

        function setFilesInputString(fieldId){
            var pathsStr = '';
            for(var i = 0; i < $scope.serviceParams.dropLists[fieldId].length; i++){
                pathsStr += ',' + $scope.serviceParams.dropLists[fieldId][i].link;
            }
            $scope.serviceParams.inputValues[fieldId] = pathsStr.substring(1);
        }

        $scope.removeSelectedItem = function(fieldId, item){
            var index = $scope.serviceParams.dropLists[fieldId].indexOf(item);
            $scope.serviceParams.dropLists[fieldId].splice(index, 1);
            setFilesInputString(fieldId);
        };

        $scope.updateDropList = function(fieldId){
            if($scope.serviceParams.inputValues[fieldId] && $scope.serviceParams.inputValues[fieldId].indexOf('://') > -1) {
                var csvList = $scope.serviceParams.inputValues[fieldId].split(',');
                if($scope.serviceParams.dropLists[fieldId] === undefined){
                    $scope.serviceParams.dropLists[fieldId] = [];
                }
                var newDropList = [];
                for(var index in csvList){
                    var exists = false;
                    for(var i in $scope.serviceParams.dropLists[fieldId]){
                        if($scope.serviceParams.dropLists[fieldId][i].link === csvList[index]){
                            newDropList.push($scope.serviceParams.dropLists[fieldId][i]);
                            exists = true;
                        }
                    }
                    if(!exists && csvList[index] !== ''){
                        newDropList.push({link: csvList[index]});
                    }
                }
                $scope.serviceParams.dropLists[fieldId] = newDropList;
            } else {
                $scope.serviceParams.dropLists[fieldId] = undefined;
            }
        };

    }]);
});
<|endoftext|>