<commit_before>/*jshint node:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, trailing:true, white:true */
/*global XT:true, XV:true, XM:true, Backbone:true, window:true, enyo:true, _:true */

(function () {

  // ..........................................................
  // ACCOUNT
  //

  enyo.kind({
    name: "XV.AccountWidget",
    kind: "XV.RelationWidget",
    collection: "XM.AccountRelationCollection",
    list: "XV.AccountList"
  });

  // ..........................................................
  // CONTACT
  //

  enyo.kind({
    name: "XV.ContactWidget",
    kind: "XV.RelationWidget",
    label: "_name".loc(),
    collection: "XM.ContactRelationCollection",
    list: "XV.ContactList",
    keyAttribute: "name",
    nameAttribute: "jobTitle",
    descripAttribute: "phone",
    published: {
      showAddress: false
    },
    components: [
      {kind: "FittableColumns", components: [
        {name: "label", content: "", classes: "xv-decorated-label"},
        {kind: "onyx.InputDecorator", name: "decorator",
          classes: "xv-input-decorator", components: [
          {name: 'input', kind: "onyx.Input", classes: "xv-subinput",
            onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
            onfocus: "receiveFocus"
          },
          {kind: "onyx.MenuDecorator", onSelect: "itemSelected", components: [
            {kind: "onyx.IconButton", src: "assets/triangle-down-large.png",
              classes: "xv-relationwidget-icon"},
            {name: 'popupMenu', floating: true, kind: "onyx.Menu",
              components: [
              {kind: "XV.MenuItem", name: 'searchItem', content: "_search".loc()},
              {kind: "XV.MenuItem", name: 'openItem', content: "_open".loc(),
                disabled: true},
              {kind: "XV.MenuItem", name: 'newItem', content: "_new".loc(),
                disabled: true}
            ]}
          ]},
          {name: "completer", kind: "XV.Completer", onSelect: "itemSelected"}
        ]}
      ]},
      {kind: "FittableColumns", components: [
        {name: "labels", classes: "xv-relationwidget-column left",
          components: [
          {name: "jobTitleLabel", content: "_jobTitle".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "phoneLabel", content: "_phone".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "alternateLabel", content: "_alternate".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "faxLabel", content: "_fax".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "primaryEmailLabel", content: "_email".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "webAddressLabel", content: "_web".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false},
          {name: "addressLabel", content: "_address".loc() + ":",
            classes: "xv-relationwidget-description label",
            showing: false}
        ]},
        {name: "data", fit: true, components: [
          {name: "name", classes: "xv-relationwidget-description hasLabel"},
          {name: "description", classes: "xv-relationwidget-description hasLabel"},
          {name: "alternate", classes: "xv-relationwidget-description hasLabel"},
          {name: "fax", classes: "xv-relationwidget-description hasLabel"},
          {name: "primaryEmail", ontap: "sendMail",
            classes: "xv-relationwidget-description hasLabel hyperlink"},
          {name: "webAddress", ontap: "openWindow",
            classes: "xv-relationwidget-description hasLabel hyperlink"},
          {name: "address", classes: "xv-relationwidget-description hasLabel",
            allowHtml: true}
        ]}
      ]}
    ],
    disabledChanged: function () {
      this.inherited(arguments);
      var disabled = this.getDisabled();
      if (this.$.phone) {
        this.$.jobTitle.addRemoveClass("disabled", disabled);
        this.$.phone.addRemoveClass("disabled", disabled);
        this.$.alternate.addRemoveClass("disabled", disabled);
        this.$.fax.addRemoveClass("disabled", disabled);
        this.$.primaryEmail.addRemoveClass("disabled", disabled);
        this.$.webAddress.addRemoveClass("disabled", disabled);
      }
    },
    setValue: function (value, options) {
      this.inherited(arguments);
      var jobTitle = value ? value.get('jobTitle') : "",
        phone = value ? value.get('phone') : "",
        alternate = value ? value.get('alternate') : "",
        fax = value ? value.get('fax') : "",
        primaryEmail = value ? value.get('primaryEmail') : "",
        webAddress = value ? value.get('webAddress') : "",
        address = value ? XM.Address.format(value.get('address')) : "",
        showAddress = this.getShowAddress();
      this.$.jobTitleLabel.setShowing(jobTitle);
      this.$.phoneLabel.setShowing(phone);
      this.$.alternate.setShowing(alternate);
      this.$.alternate.setContent(alternate);
      this.$.alternateLabel.setShowing(alternate);
      this.$.fax.setShowing(fax);
      this.$.fax.setContent(fax);
      this.$.faxLabel.setShowing(fax);
      this.$.primaryEmail.setShowing(primaryEmail);
      this.$.primaryEmail.setContent(primaryEmail);
      this.$.primaryEmailLabel.setShowing(primaryEmail);
      this.$.webAddress.setShowing(webAddress);
      this.$.webAddress.setContent(webAddress);
      this.$.webAddressLabel.setShowing(webAddress);
      this.$.address.setShowing(address && showAddress);
      this.$.addressLabel.setShowing(address && showAddress);
      if (showAddress) { this.$.address.setContent(address); }
    },
    openWindow: function () {
      var address = this.value ? this.value.get('webAddress') : null;
      if (address) { window.open('http://' + address); }
      return true;
    },
    sendMail: function () {
      var email = this.value ? this.value.get('primaryEmail') : null,
        win;
      if (email) {
        win = window.open('mailto:' + email);
        win.close();
      }
      return true;
    }
  });

  // ..........................................................
  // INCIDENT
  //

  enyo.kind({
    name: "XV.IncidentWidget",
    kind: "XV.RelationWidget",
    collection: "XM.IncidentRelationCollection",
    list: "XV.IncidentList",
    nameAttribute: "description"
  });

  // ..........................................................
  // ITEM
  //

  enyo.kind({
    name: "XV.ItemWidget",
    kind: "XV.RelationWidget",
    collection: "XM.ItemRelationCollection",
    list: "XV.ItemList",
    nameAttribute: "description1",
    descripAttribute: "description2"
  });

  // ..........................................................
  // OPPORTUNITY
  //

  enyo.kind({
    name: "XV.OpportunityWidget",
    kind: "XV.RelationWidget",
    collection: "XM.OpportunityRelationCollection",
    list: "XV.OpportunityList"
  });

  // ..........................................................
  // PROJECT
  //

  enyo.kind({
    name: "XV.ProjectWidget",
    kind: "XV.RelationWidget",
    collection: "XM.ProjectRelationCollection",
    list: "XV.ProjectList"
  });

  // ..........................................................
  // USER ACCOUNT
  //

  enyo.kind({
    name: "XV.UserAccountWidget",
    kind: "XV.RelationWidget",
    collection: "XM.UserAccountRelationCollection",
    list: "XV.UserAccountList",
    keyAttribute: "username",
    nameAttribute: "properName"
  });

}());
<commit_msg>oops, got files mixed up in previous commit<commit_after>/*jshint node:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, trailing:true, white:true */
/*global XT:true, XV:true, XM:true, Backbone:true, enyo:true, _:true */

(function () {

  enyo.kind({
    name: "XV.RelationWidget",
    kind: enyo.Control,
    classes: "xv-inputwidget xv-relationwidget",
    published: {
      attr: null,
      label: "",
      placeholder: "",
      value: null,
      list: "",
      collection: "",
      disabled: false,
      keyAttribute: "number",
      nameAttribute: "name",
      descripAttribute: ""
    },
    events: {
      onSearch: "",
      onValueChange: "",
      onWorkspace: ""
    },
    handlers: {
      onModelChange: "modelChanged",
      onSelect: "itemSelected"
    },
    components: [
      {kind: "FittableColumns", components: [
        {name: "label", content: "", classes: "xv-decorated-label"},
        {kind: "onyx.InputDecorator", name: "decorator",
          classes: "xv-input-decorator", components: [
          {name: 'input', kind: "onyx.Input", classes: "xv-subinput",
            onkeyup: "keyUp", onkeydown: "keyDown", onblur: "receiveBlur",
            onfocus: "receiveFocus"
          },
          {kind: "onyx.MenuDecorator", components: [
            {kind: "onyx.IconButton", src: "assets/triangle-down-large.png",
              classes: "xv-relationwidget-icon"},
            {name: 'popupMenu', floating: true, kind: "onyx.Menu",
              components: [
              {kind: "XV.MenuItem", name: 'searchItem', content: "_search".loc()},
              {kind: "XV.MenuItem", name: 'openItem', content: "_open".loc(),
                disabled: true},
              {kind: "XV.MenuItem", name: 'newItem', content: "_new".loc(),
                disabled: true}
            ]}
          ]},
          {name: "completer", kind: "XV.Completer"}
        ]}
      ]},
      {name: "name", classes: "xv-relationwidget-description"},
      {name: "description", classes: "xv-relationwidget-description"}
    ],
    autocomplete: function () {
      var key = this.getKeyAttribute(),
        attr = this.getValue() ? this.getValue().get(key) : "",
        value = this.$.input.getValue(),
        query;

      if (value && value !== attr) {
        query = {
          parameters: [{
            attribute: key,
            operator: "BEGINS_WITH",
            value: value
          }],
          rowLimit: 1,
          orderBy: [{
            attribute: key
          }]
        };
        this._collection.fetch({
          success: enyo.bind(this, "_fetchSuccess"),
          query: query
        });
      } else if (!value) {
        this.setValue(null);
      }
    },
    clear: function (options) {
      this.setValue(null, options);
    },
    create: function () {
      this.inherited(arguments);
      this.listChanged();
      this.labelChanged();
      this.disabledChanged();
    },
    disabledChanged: function () {
      var disabled = this.getDisabled();
      this.$.input.setDisabled(disabled);
      this.$.name.addRemoveClass("disabled", disabled);
      this.$.description.addRemoveClass("disabled", disabled);
    },
    focus: function () {
      this.$.input.focus();
    },
    getValueToString: function () {
      return this.value.get(this.getKeyAttribute());
    },
    keyDown: function (inSender, inEvent) {
      // If tabbed out...
      inEvent.activator = this.$.decorator;
      if (inEvent.keyCode === 9) {
        this.$.completer.waterfall("onRequestHideMenu", inEvent);
        this.autocomplete();
      }
    },
    keyUp: function (inSender, inEvent) {
      var query,
        key = this.getKeyAttribute(),
        attr = this.getValue() ? this.getValue().get(key) : "",
        value = this.$.input.getValue(),
        completer = this.$.completer;
      inEvent.activator = this.$.decorator;

      // Look up if value changed
      if (value && value !== attr &&
          inEvent.keyCode !== 9) {
        query = {
          parameters: [{
            attribute: key,
            operator: "BEGINS_WITH",
            value: value
          }],
          rowLimit: 10,
          orderBy: [{
            attribute: key
          }]
        };
        this._collection.fetch({
          success: enyo.bind(this, "_collectionFetchSuccess"),
          query: query
        });
      } else {
        completer.waterfall("onRequestHideMenu", inEvent);
      }
    },
    itemSelected: function (inSender, inEvent) {
      if (inEvent.originator.kind === 'onyx.MenuItem') {
        this.relationSelected(inSender, inEvent);
      } else {
        this.menuItemSelected(inSender, inEvent);
      }
      return true;
    },
    labelChanged: function () {
      var label = (this.getLabel() || ("_" + this.attr || "").loc());
      this.$.label.setContent(label + ":");
    },
    listChanged: function () {
      var list = this.getList(),
        Collection,
        workspace;
      delete this._List;
      delete this._Workspace;

      // Get List class
      if (!list) { return; }
      this._List = XT.getObjectByName(list);

      // Get Workspace class
      workspace = this._List.prototype.getWorkspace();
      this._Workspace = workspace ? XT.getObjectByName(workspace) : null;

      // Setup collection instance
      Collection = this.getCollection() ?
        XT.getObjectByName(this.getCollection()) : null;
      if (!Collection) { return; }
      this._collection = new Collection();
    },
    menuItemSelected: function (inSender, inEvent) {
      var that = this,
        menuItem = inEvent.originator,
        list = this.getList(),
        model = this.getValue(),
        id = model ? model.id : null,
        workspace = this._List ? this._List.prototype.getWorkspace() : null,
        callback;
      switch (menuItem.name)
      {
      case 'searchItem':
        callback = function (value) {
          that.setValue(value);
        };
        this.doSearch({
          list: list,
          searchText: this.$.input.getValue(),
          callback: callback
        });
        break;
      case 'openItem':
        this.doWorkspace({
          workspace: workspace,
          id: id,
          allowNew: false
        });
        break;
      case 'newItem':
        // Callback options on commit of the workspace
        // Find the model with matching id, fetch and set it.
        callback = function (model) {
          var Model = that._collection.model,
            value = new Model({id: model.id}),
            options = {};
          options.success = function () {
            that.setValue(value);
          };
          value.fetch(options);
        };
        this.doWorkspace({
          workspace: workspace,
          callback: callback,
          allowNew: false
        });
        break;
      }
    },
    modelChanged: function (inSender, inEvent) {
      var that = this,
        List = this._List,
        workspace = List.prototype.getWorkspace(),
        Workspace = workspace ? XT.getObjectByName(workspace) : null,
        options = {},
        model = this.getValue();
      // If the model that changed was related to and exists on this widget
      // refresh the local model.
      if (!List || !Workspace || !model) { return; }
      if (Workspace.prototype.model === inEvent.model &&
        model.id === inEvent.id) {
        options.success = function () {
          that.setValue(model);
        };
        model.fetch(options);
      }
    },
    placeholderChanged: function () {
      var placeholder = this.getPlaceholder();
      this.$.input.setPlaceholder(placeholder);
    },
    receiveBlur: function (inSender, inEvent) {
      this.autocomplete();
      this._hasFocus = false;
    },
    receiveFocus: function (inSender, inEvent) {
      this._hasFocus = true;
      this._relationSelected = false;
    },
    relationSelected: function (inSender, inEvent) {
      this._relationSelected = true;
      inEvent.activator = this.$.decorator;
      this.setValue(inEvent.originator.model);
      this.$.completer.waterfall("onRequestHideMenu", inEvent);
      return true;
    },
    /**
      Programatically sets the value of this widget.

      @param value Can be a model or the id of a model (String or Number).
        If it is an ID, then the correct model will be fetched and this
        function will be called again recursively with the model.
      @param options {Object}
     */
    setValue: function (value, options) {
      options = options || {};
      var that = this,
        newId = value ? value.id : null,
        oldId = this.value ? this.value.id : null,
        key = this.getKeyAttribute(),
        name = this.getNameAttribute(),
        descrip = this.getDescripAttribute(),
        inEvent = { value: value, originator: this },
        keyValue = "",
        nameValue = "",
        descripValue = "",
        Workspace = this._Workspace,
        Model = Workspace && Workspace.prototype.model ?
          XT.getObjectByName(Workspace.prototype.model)  : null,
        couldNotCreate = Model ? !Model.canCreate() : true,
        setPrivileges = function () {
          if (value && newId) {
            that.$.openItem.setDisabled(!value.couldRead());
          }
        };

      // Here is where we find the model and re-call this method if we're given
      // an id instead of a whole model.
      if (_.isNumber(value) || _.isString(value)) {
        if (this.value === value || oldId === value) { return; }
        Model = XT.getObjectByName(this._collection.model.prototype.recordType);
        value = new Model({id: value});
        options = {
          success: function () {
            that.setValue(value);
          }
        };
        this.value = value;
        // XXX shouldn't we pass the options in here?
        value.fetch(/*options*/);
        return;
      }

      this.value = value;
      if (value && value.get) {
        keyValue = value.get(key) || "";
        nameValue = value.get(name) || "";
        descripValue = value.get(descrip) || "";
      }
      this.$.input.setValue(keyValue);
      this.$.name.setShowing(nameValue);
      this.$.name.setContent(nameValue);
      this.$.description.setShowing(descripValue);
      this.$.description.setContent(descripValue);

      // Only notify if selection actually changed
      if (newId !== oldId && !options.silent) { this.doValueChange(inEvent); }

      // Handle menu actions
      that.$.openItem.setShowing(Workspace);
      that.$.newItem.setShowing(Workspace);
      that.$.openItem.setDisabled(true);
      that.$.newItem.setDisabled(couldNotCreate);
      if (Model && Workspace) {
        if (XT.session) {
          setPrivileges();
        } else {
          XT.getStartupManager().registerCallback(setPrivileges);
        }
      }
    },
    /** @private */
    _collectionFetchSuccess: function () {
      if (!this._hasFocus) { return; }
      var key = this.getKeyAttribute(),
        value = this.$.input.getValue(),
        models = this._collection.models,
        inEvent = { activator: this.$.decorator };
      if (models.length) {
        this.$.completer.buildList(key, value, models);
        if (!this.$.completer.showing) {
          this.$.completer.waterfall("onRequestShowMenu", inEvent);
        }
        this.$.completer.adjustPosition();
      } else {
        this.$.completer.waterfall("onRequestHideMenu", inEvent);
      }
    },
    /** @private */
    _fetchSuccess: function () {
      if (this._relationSelected) { return; }
      var value = this._collection.length ? this._collection.models[0] : null,
        target = enyo.dispatcher.captureTarget;
      this.setValue(value);
      enyo.dispatcher.captureTarget = target;
    }

  });
}());<|endoftext|>


<commit_before>import Controller from '@ember/controller';
import boundOneWay from 'ghost-admin/utils/bound-one-way';
import {empty} from '@ember/object/computed';
import {isInvalidError} from 'ember-ajax/errors';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

export default Controller.extend({
    ghostPaths: service(),
    ajax: service(),
    notifications: service(),
    settings: service(),

    model: boundOneWay('settings.slack.firstObject'),
    testNotificationDisabled: empty('model.url'),

    leaveSettingsTransition: null,
    slackArray: null,

    init() {
        this._super(...arguments);
        this.slackArray = [];
    },

    save: task(function* () {
        let slack = this.get('model');
        let settings = this.get('settings');
        let slackArray = this.get('slackArray');

        try {
            yield slack.validate();
            // clear existing objects in slackArray to make sure we only push the validated one
            slackArray.clear().pushObject(slack);
            yield settings.set('slack', slackArray);
            return yield settings.save();
        } catch (error) {
            if (error) {
                this.get('notifications').showAPIError(error);
                throw error;
            }
        }
    }).drop(),

    sendTestNotification: task(function* () {
        let notifications = this.get('notifications');
        let slackApi = this.get('ghostPaths.url').api('slack', 'test');

        try {
            yield this.get('save').perform();
            yield this.get('ajax').post(slackApi);
            notifications.showNotification('Check your Slack channel for the test message!', {type: 'info', key: 'slack-test.send.success'});
            return true;
        } catch (error) {
            notifications.showAPIError(error, {key: 'slack-test:send'});

            if (!isInvalidError(error)) {
                throw error;
            }
        }
    }).drop(),

    actions: {
        save() {
            this.get('save').perform();
        },

        updateURL(value) {
            this.set('model.url', value);
            this.get('model.errors').clear();
        },

        triggerDirtyState() {
            let slack = this.get('model');
            let slackArray = this.get('slackArray');
            let settings = this.get('settings');

            // Hack to trigger the `isDirty` state on the settings model by setting a new Array
            // for slack rather that replacing the existing one which would still point to the
            // same reference and therfore not setting the model into a dirty state
            slackArray.clear().pushObject(slack);
            settings.set('slack', slackArray);
        },

        toggleLeaveSettingsModal(transition) {
            let leaveTransition = this.get('leaveSettingsTransition');

            if (!transition && this.get('showLeaveSettingsModal')) {
                this.set('leaveSettingsTransition', null);
                this.set('showLeaveSettingsModal', false);
                return;
            }

            if (!leaveTransition || transition.targetName === leaveTransition.targetName) {
                this.set('leaveSettingsTransition', transition);

                // if a save is running, wait for it to finish then transition
                if (this.get('save.isRunning')) {
                    return this.get('save.last').then(() => {
                        transition.retry();
                    });
                }

                // we genuinely have unsaved data, show the modal
                this.set('showLeaveSettingsModal', true);
            }
        },

        leaveSettings() {
            let transition = this.get('leaveSettingsTransition');
            let settings = this.get('settings');
            let slackArray = this.get('slackArray');

            if (!transition) {
                this.get('notifications').showAlert('Sorry, there was an error in the application. Please let the Ghost team know what happened.', {type: 'error'});
                return;
            }

            // roll back changes on model props
            settings.rollbackAttributes();
            slackArray.clear();

            return transition.retry();
        }
    }
});
<commit_msg>Prevent "Invalid URL" errors due to trailing spaces when editing Slack Webhook URL (#925)<commit_after>import Controller from '@ember/controller';
import boundOneWay from 'ghost-admin/utils/bound-one-way';
import {empty} from '@ember/object/computed';
import {isInvalidError} from 'ember-ajax/errors';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

export default Controller.extend({
    ghostPaths: service(),
    ajax: service(),
    notifications: service(),
    settings: service(),

    model: boundOneWay('settings.slack.firstObject'),
    testNotificationDisabled: empty('model.url'),

    leaveSettingsTransition: null,
    slackArray: null,

    init() {
        this._super(...arguments);
        this.slackArray = [];
    },

    save: task(function* () {
        let slack = this.get('model');
        let settings = this.get('settings');
        let slackArray = this.get('slackArray');

        try {
            yield slack.validate();
            // clear existing objects in slackArray to make sure we only push the validated one
            slackArray.clear().pushObject(slack);
            yield settings.set('slack', slackArray);
            return yield settings.save();
        } catch (error) {
            if (error) {
                this.get('notifications').showAPIError(error);
                throw error;
            }
        }
    }).drop(),

    sendTestNotification: task(function* () {
        let notifications = this.get('notifications');
        let slackApi = this.get('ghostPaths.url').api('slack', 'test');

        try {
            yield this.get('save').perform();
            yield this.get('ajax').post(slackApi);
            notifications.showNotification('Check your Slack channel for the test message!', {type: 'info', key: 'slack-test.send.success'});
            return true;
        } catch (error) {
            notifications.showAPIError(error, {key: 'slack-test:send'});

            if (!isInvalidError(error)) {
                throw error;
            }
        }
    }).drop(),

    actions: {
        save() {
            this.get('save').perform();
        },

        updateURL(value) {
            value = typeof value === 'string' ? value.trim() : value;
            this.set('model.url', value);
            this.get('model.errors').clear();
        },

        triggerDirtyState() {
            let slack = this.get('model');
            let slackArray = this.get('slackArray');
            let settings = this.get('settings');

            // Hack to trigger the `isDirty` state on the settings model by setting a new Array
            // for slack rather that replacing the existing one which would still point to the
            // same reference and therfore not setting the model into a dirty state
            slackArray.clear().pushObject(slack);
            settings.set('slack', slackArray);
        },

        toggleLeaveSettingsModal(transition) {
            let leaveTransition = this.get('leaveSettingsTransition');

            if (!transition && this.get('showLeaveSettingsModal')) {
                this.set('leaveSettingsTransition', null);
                this.set('showLeaveSettingsModal', false);
                return;
            }

            if (!leaveTransition || transition.targetName === leaveTransition.targetName) {
                this.set('leaveSettingsTransition', transition);

                // if a save is running, wait for it to finish then transition
                if (this.get('save.isRunning')) {
                    return this.get('save.last').then(() => {
                        transition.retry();
                    });
                }

                // we genuinely have unsaved data, show the modal
                this.set('showLeaveSettingsModal', true);
            }
        },

        leaveSettings() {
            let transition = this.get('leaveSettingsTransition');
            let settings = this.get('settings');
            let slackArray = this.get('slackArray');

            if (!transition) {
                this.get('notifications').showAlert('Sorry, there was an error in the application. Please let the Ghost team know what happened.', {type: 'error'});
                return;
            }

            // roll back changes on model props
            settings.rollbackAttributes();
            slackArray.clear();

            return transition.retry();
        }
    }
});
<|endoftext|>


<commit_before>const rewire = require('rewire');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const nock = require('nock');
const fs = require('fs-extra');
const Promise = require('bluebird');
const TARGET_FOLDER = './target/';
const TOKEN_DIR = TARGET_FOLDER + '.credentials/';
const TOKEN_PATH = TOKEN_DIR + 'gcal-leave-scraper.json';
const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
const SECRET_FILE = TARGET_FOLDER + 'secret.json';
const AUTH_URL = '/auth-url';
let expect;

chai.use(chaiAsPromised);
chai.should();
expect = chai.expect;

function createCredentials() {
  const secrets = {
    'installed': {
      'client_secret': 'secret',
      'client_id': 'id',
      'redirect_uris': ['a', 'b', 'c'],
    },
  };

  fs.writeFileSync(SECRET_FILE, JSON.stringify(secrets));
}

function rewirePromptAsync(factory, flags) {
  const promptAsync = (questions) => {
    return new Promise((resolve) => {
      expect(questions[0]).to.not.be.undefined;
      expect(questions[0].name).to.equal('code');
      flags.promptAsyncCalled = true;
      resolve({'code': 'code12345'});
    });
  };
  factory.__set__('promptAsync', promptAsync);
}

function createOathClient() {
  return {
    'generateAuthUrl': (config) => {
      expect(config.access_type).to.equal('offline');
      expect(config.scope).to.equal(SCOPES);
      return AUTH_URL;
    },
    'credentials': 'nope',
    'getToken': (code, cb) => {
      expect(code).to.equal('code12345');
      cb(null, ['authToken']);
    },
  };
}

function rewireGoogleAuth(factory) {
  const GA = class GoogleAuth {
    constructor() {
    }

    OAuth2(clientId, clientSecret, redirectUrl) {
      expect(clientId).to.equal('id');
      expect(clientSecret).to.equal('secret');
      expect(redirectUrl).to.equal('a');

      return createOathClient();
    }
  };

  factory.__set__('GoogleAuth', GA);
}

function createAuthTokenFile() {
  fs.ensureDirSync(TOKEN_DIR);
  fs.outputJsonSync(TOKEN_PATH, 'authToken2');
}

describe('The GoogleAuthFactory', () => {
  const factory = rewire('./GoogleAuthFactory.js');
  nock.disableNetConnect();

  beforeEach(() => {
    factory.__set__('TOKEN_DIR', TOKEN_DIR);
    factory.__set__('TOKEN_PATH', TOKEN_PATH);

    fs.removeSync(TOKEN_DIR);
    fs.removeSync(SECRET_FILE);
    fs.ensureDirSync(TARGET_FOLDER);
  });

  afterEach(() => {
    fs.removeSync(TOKEN_DIR);
    fs.removeSync(SECRET_FILE);
  });

  it('throws error when secrets file does not exist', () => {
    expect(() => {
      factory({
        'secretsFile': SECRET_FILE,
        'scopes': SCOPES,
      });
    }).to.throw(Error, 'Could not find secrets file located in: ' + SECRET_FILE);
  });

  it('prompts for code when token does not exist', (done) => {
    const flags = {};
    let execute;
    let validate;

    createCredentials();
    rewirePromptAsync(factory, flags);
    rewireGoogleAuth(factory);

    validate = (auth) => {
      expect(auth).to.not.be.undefined;
      expect(auth.credentials).to.equal('authToken');
    };
    execute = () => {
      factory({
        'secretsFile': SECRET_FILE,
        'scopes': SCOPES,
      }).should.be.fulfilled.then(validate).should.notify(done);
    };

    new Promise(execute).then(() => {
      expect(flags.promptAsyncCalled).to.equal(true);
      expect(fs.existsSync(TOKEN_PATH)).to.equal(true);
      expect(fs.readJson(TOKEN_PATH)).to.equal('authToken');
    });
  });

  it('uses existing code when token exists', (done) => {
    let validate;

    createCredentials();
    createAuthTokenFile();
    rewireGoogleAuth(factory);

    validate = (auth) => {
      expect(auth).to.not.be.undefined;
      expect(auth.credentials).to.equal('authToken2');
    };

    factory({
      'secretsFile': SECRET_FILE,
      'scopes': SCOPES,
    }).should.be.fulfilled.then(validate).should.notify(done);
  });
});
<commit_msg>Removed test no longer valid with config changes to the application. Added TODO to come back and fix test, secret_file config now located in config/local.coffee.<commit_after>const rewire = require('rewire');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const nock = require('nock');
const fs = require('fs-extra');
const Promise = require('bluebird');
const TARGET_FOLDER = './target/';
const TOKEN_DIR = TARGET_FOLDER + '.credentials/';
const TOKEN_PATH = TOKEN_DIR + 'gcal-leave-scraper.json';
const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
const SECRET_FILE = TARGET_FOLDER + 'secret.json';
const AUTH_URL = '/auth-url';
let expect;

chai.use(chaiAsPromised);
chai.should();
expect = chai.expect;

function createCredentials() {
  const secrets = {
    'installed': {
      'client_secret': 'secret',
      'client_id': 'id',
      'redirect_uris': ['a', 'b', 'c'],
    },
  };

  fs.writeFileSync(SECRET_FILE, JSON.stringify(secrets));
}

function rewirePromptAsync(factory, flags) {
  const promptAsync = (questions) => {
    return new Promise((resolve) => {
      expect(questions[0]).to.not.be.undefined;
      expect(questions[0].name).to.equal('code');
      flags.promptAsyncCalled = true;
      resolve({'code': 'code12345'});
    });
  };
  factory.__set__('promptAsync', promptAsync);
}

function createOathClient() {
  return {
    'generateAuthUrl': (config) => {
      expect(config.access_type).to.equal('offline');
      expect(config.scope).to.equal(SCOPES);
      return AUTH_URL;
    },
    'credentials': 'nope',
    'getToken': (code, cb) => {
      expect(code).to.equal('code12345');
      cb(null, ['authToken']);
    },
  };
}

function rewireGoogleAuth(factory) {
  const GA = class GoogleAuth {
    constructor() {
    }

    OAuth2(clientId, clientSecret, redirectUrl) {
      expect(clientId).to.equal('id');
      expect(clientSecret).to.equal('secret');
      expect(redirectUrl).to.equal('a');

      return createOathClient();
    }
  };

  factory.__set__('GoogleAuth', GA);
}

function createAuthTokenFile() {
  fs.ensureDirSync(TOKEN_DIR);
  fs.outputJsonSync(TOKEN_PATH, 'authToken2');
}

describe('The GoogleAuthFactory', () => {
  const factory = rewire('./GoogleAuthFactory.js');
  nock.disableNetConnect();

  beforeEach(() => {
    factory.__set__('TOKEN_DIR', TOKEN_DIR);
    factory.__set__('TOKEN_PATH', TOKEN_PATH);

    fs.removeSync(TOKEN_DIR);
    fs.removeSync(SECRET_FILE);
    fs.ensureDirSync(TARGET_FOLDER);
  });

  afterEach(() => {
    fs.removeSync(TOKEN_DIR);
    fs.removeSync(SECRET_FILE);
  });

  it('throws error when secrets file does not exist', () => {
    expect(() => {
      factory({
        'secretsFile': SECRET_FILE,
        'scopes': SCOPES,
      });
    }).to.throw(Error, 'Could not find secrets file located in: ' + SECRET_FILE);
  });

  // TODO: Removed this due to expectation for google auth config has changed, now found in config/local.coffee
  // it('prompts for code when token does not exist', (done) => {
  //   const flags = {};
  //   let execute;
  //   let validate;

  //   createCredentials();
  //   rewirePromptAsync(factory, flags);
  //   rewireGoogleAuth(factory);

  //   validate = (auth) => {
  //     expect(auth).to.not.be.undefined;
  //     expect(auth.credentials).to.equal('authToken');
  //   };
  //   execute = () => {
  //     factory({
  //       'secretsFile': SECRET_FILE,
  //       'scopes': SCOPES,
  //     }).should.be.fulfilled.then(validate).should.notify(done);
  //   };

  //   new Promise(execute).then(() => {
  //     expect(flags.promptAsyncCalled).to.equal(true);
  //     expect(fs.existsSync(TOKEN_PATH)).to.equal(true);
  //     expect(fs.readJson(TOKEN_PATH)).to.equal('authToken');
  //   });
  // });

  it('uses existing code when token exists', (done) => {
    let validate;

    createCredentials();
    createAuthTokenFile();
    rewireGoogleAuth(factory);

    validate = (auth) => {
      expect(auth).to.not.be.undefined;
      expect(auth.credentials).to.equal('authToken2');
    };

    factory({
      'secretsFile': SECRET_FILE,
      'scopes': SCOPES,
    }).should.be.fulfilled.then(validate).should.notify(done);
  });
});
<|endoftext|>


<commit_before>import Dashboard from "../support/elements/geode-dashboard/dashboard";
import {
  getAnswerByQuestionType,
  getPageQuestionData,
  getActivityData,
  getPageData,
  getActivityQuestionData
 } from "../utils";

context("Geode Dashboard Smoke Test", () => {

    const dashboard = new Dashboard();
    const studentsToTest = ["", "", ""];

    beforeEach(() => {
        cy.visit("/?dashboard=true");
        cy.fixture("small-class-data.json").as("classData");
        cy.fixture("sequence-structure.json").as("sequenceStructure");
    });

    function getStudentName(classData, id) {
        let students = classData.students;

        for (let i = 0; i < students.length; i++) {
            if (students[i].id === id) {
                let student = students[i];
                return student.name;
            } else {
                cy.log("No student with this ID found in class");
            }
        }
    }

    function getStudentAnswer(answerData, studentID) {
        for (let i = 0; i < answerData.length; i++) {
            let answer;

            let studentAnswerData = answerData[i];
            if (studentAnswerData.student_id === studentID) {
                answer = getAnswerByQuestionType(studentAnswerData);
                return answer;
            }
        }
    }

    describe("Verifies setting functionality", () => {
        it("can sort by least progress", () => {
            dashboard.getSortDropdown()
                .select("Least Progress")
                .should("be.visible");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Crosby, Kate" );
            dashboard.getStudentAnswersRow().eq(1)
                .within(() => {
                    dashboard.getProgressBar().eq(0)
                        .should("not.be.visible");
                });
        });
        it("can sort by most progress", () => {
            dashboard.getSortDropdown()
                .select("Most Progress")
                .should("be.visible");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Jenkins, John");
            dashboard.getStudentAnswersRow().eq(0)
                .within(() => {
                    dashboard.getProgressBar().eq(0)
                        .should("be.visible")
                        .and("have.attr", "style", "width: 85.7143%;");
                });
        });
        it("can sort by student name", () => {
            dashboard.getSortDropdown()
                .should("be.visible")
                .select("Student Name");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Armstrong, Jenna");
        });
        it("can open and close student list", () => {
            dashboard.getStudentAnswersRow()
                .should("not.have.class", dashboard.answersOpen);
            dashboard.getOpenCloseStudents()
                .should("exist")
                .and("be.visible")
                .click({ force: true });
            dashboard.getStudentAnswersRow()
                .should("have.class", dashboard.answersOpen);
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getStudentAnswersRow()
                .should("not.have.class", dashboard.answersOpen);
        });
        it("can scroll across the different activities", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getActivityNames().last()
                .scrollIntoView({ duration: 2000 });
        });
    });

    describe("Verifies for Activity/Seq data", function() {
        beforeEach(() => {
            cy.get("@sequenceStructure").its("children").as("activities");
        });

        it("Checks for activity names", () => {
            cy.get("@activities").then(activities => {
                dashboard.getActivityNames()
                    .should("have.length", activities.length);

                for (let i = 0; i < activities.length; i++) {
                    let activity = activities[i];
                    dashboard.getActivityNames()
                        .should("contain", activity.name);
                }
            });
        });
        it("can expand activity questions", () => {
            cy.get("@activities").then(activities => {
                let firstActivity = activities[0];
                let questionData = getActivityQuestionData(firstActivity);
                let questionTotal = questionData.length;
                let currentQuestionPrompt;

                dashboard.getExpandQuestionDetails()
                    .should("not.exist");
                dashboard.getOpenCloseStudents()
                    .click({ force: true });
                dashboard.getExpandQuestionDetails()
                    .should("exist")
                    .and("be.visible")
                    .and("have.length", questionTotal);

                for (let i = 0; i < questionTotal; i++) {
                    // strip html chars from the prompt
                    currentQuestionPrompt = Cypress.$(questionData[i].prompt).text();
                    dashboard.getActivityQuestionsText()
                        .should("contain", currentQuestionPrompt);
                }

                dashboard.getExpandedMCAnswerDetails()
                    .should("not.exist");

                // This is assuming the 2nd question is a multiple choice question
                dashboard.getExpandQuestionDetails().eq(1)
                    .click({ force: true });
                dashboard.getExpandedQuestionPanel()
                    .should("be.visible");
                dashboard.getExpandedMCAnswerDetails()
                    .should("be.visible")
                    .and("exist");
                dashboard.getCloseExpandedQuestion()
                    .should("exist")
                    .click({ force: true });
                dashboard.getExpandedQuestionPanel()
                    .should("not.exist");
            });
        });
        it("can expand activities to show questions", () => {
            dashboard.getActivityNames().eq(0)
                .click({ force: true });
            cy.get("@activities").then((activities) => {
                const questionData = getActivityQuestionData(activities[0]);

                dashboard.getActivityQuestions().eq(0).within(() => {
                  dashboard.getActivityQuestionToggle()
                  .should("exist")
                  .and("have.length", questionData.length);
                });
            });
            dashboard.getActivityQuestionsText()
                .should("not.exist");
            dashboard.getActivityQuestionToggle().eq(0)
                .click({ force: true });
            dashboard.getActivityQuestionsText()
                .should("be.visible");
            dashboard.getActivityQuestionsText().eq(0)
                .click({ force: true });
            dashboard.getActivityQuestionsText()
                .should("not.exist");
        });

        // it.only('Checks for one students data', () => {
        //     cy.get('@classData').then((classData) => {
        //         const activities = classData.report.children
        //         const students = classData.class.students
        //         let studentID;
        //         let activityAnswers;
        //         let answerText;
        //         let answerID;

        //         // for (let i=0; i<students.length;i++) {
        //         //     studentID = students[i].id
        //         //     dashboard.getStudentNames().eq(i)
        //         //         .click({force:true}) make sure this block is commented out after I put it back

        //         studentID = 14//students[0].id
        //         dashboard.getStudentNames().eq(0)
        //             .click({force:true})

        //         for (let j=0; j<activities.length;j++) {
        //             activityAnswers = activities[j].children[0].children[0].children[0].answers
        //             cy.log(activityAnswers)
        //             for (let k=0; k<activityAnswers.length;k++) {
        //                 answerID = activityAnswers[k].student_id

        //                 if(answerID === studentID) {
        //                     if (activityAnswers[k].answer) {
        //                         answerText = activityAnswers[k].answer
        //                     }
        //                     dashboard.getStudentAnswersRow().eq(0)
        //                         .should('contain', answerText)
        //                     }
        //                 }

        //             dashboard.getStudentNames().eq(0)
        //                 .click({force:true})
        //         }
        //     })
        // })
    });

    describe("Student Data", () => {

        it("Checks for student names", () => {
            cy.get("@classData").then((classData) => {
                const students = classData.students;

                dashboard.getStudentNames()
                    .should("have.length", students.length);

                for (let i = 0; i < students.length; i++) {
                    let student = students[i];
                    dashboard.getStudentNames()
                        .should("contain", student.last_name + ", " + student.first_name);
                }
            });
        });
        it("show responses", () => {
            const multipleChoiceQuestionIndex = 1;

            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandQuestionDetails().eq(multipleChoiceQuestionIndex)
                .click({ force: true });
            cy.get("@sequenceStructure")
              .its("children")
              .then((activities) => {
                const questionData = getActivityQuestionData(activities[0])[multipleChoiceQuestionIndex];

                dashboard.getExpandedMCAnswerDetails()
                    .should("exist")
                    .and("contain", questionData.choices[0].content)
                    .and("contain", "No response");

                dashboard.getExpandedMCAnswers()
                    .should("not.exist");
                dashboard.getShowHideResponse()
                    .should("exist")
                    .click({ force: true })
                    .then(() => {
                        dashboard.getExpandedMCAnswers()
                            .should("exist")
                            .and("contain", "Jenna Armstrong");
                    });
            });
            dashboard.getCloseExpandedQuestion()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedQuestionPanel()
                .should("not.exist");
        });
        it("hide responses", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
            dashboard.getExpandQuestionDetails().eq(1)
                .click({ force: true });
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("exist")
                // Student 1 has an answer of b
                .and("contain", "b");
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
        });
        it("shows MC question response", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandQuestionDetails().eq(1)
                .click({ force: true });
            dashboard.getExpandedMCAnswerDetails()
                .should("exist")
                .and("contain", "b")
                .and("contain", "No response");
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("exist")
                .and("contain", "Jenna Armstrong");
            dashboard.getCloseExpandedQuestion()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedQuestionPanel()
                .should("not.exist");
        });

    });

});
<commit_msg>missed one more cypress test change<commit_after>import Dashboard from "../support/elements/geode-dashboard/dashboard";
import {
  getAnswerByQuestionType,
  getPageQuestionData,
  getActivityData,
  getPageData,
  getActivityQuestionData
 } from "../utils";

context("Geode Dashboard Smoke Test", () => {

    const dashboard = new Dashboard();
    const studentsToTest = ["", "", ""];

    beforeEach(() => {
        cy.visit("/?dashboard=true");
        cy.fixture("small-class-data.json").as("classData");
        cy.fixture("sequence-structure.json").as("sequenceStructure");
    });

    function getStudentName(classData, id) {
        let students = classData.students;

        for (let i = 0; i < students.length; i++) {
            if (students[i].id === id) {
                let student = students[i];
                return student.name;
            } else {
                cy.log("No student with this ID found in class");
            }
        }
    }

    function getStudentAnswer(answerData, studentID) {
        for (let i = 0; i < answerData.length; i++) {
            let answer;

            let studentAnswerData = answerData[i];
            if (studentAnswerData.student_id === studentID) {
                answer = getAnswerByQuestionType(studentAnswerData);
                return answer;
            }
        }
    }

    describe("Verifies setting functionality", () => {
        it("can sort by least progress", () => {
            dashboard.getSortDropdown()
                .select("Least Progress")
                .should("be.visible");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Crosby, Kate" );
            dashboard.getStudentAnswersRow().eq(0)
                .within(() => {
                    dashboard.getProgressBar().eq(0)
                        .should("not.be.visible");
                });
        });
        it("can sort by most progress", () => {
            dashboard.getSortDropdown()
                .select("Most Progress")
                .should("be.visible");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Jenkins, John");
            dashboard.getStudentAnswersRow().eq(0)
                .within(() => {
                    dashboard.getProgressBar().eq(0)
                        .should("be.visible")
                        .and("have.attr", "style", "width: 85.7143%;");
                });
        });
        it("can sort by student name", () => {
            dashboard.getSortDropdown()
                .should("be.visible")
                .select("Student Name");
            dashboard.getStudentNames().eq(0)
                .should("contain", "Armstrong, Jenna");
        });
        it("can open and close student list", () => {
            dashboard.getStudentAnswersRow()
                .should("not.have.class", dashboard.answersOpen);
            dashboard.getOpenCloseStudents()
                .should("exist")
                .and("be.visible")
                .click({ force: true });
            dashboard.getStudentAnswersRow()
                .should("have.class", dashboard.answersOpen);
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getStudentAnswersRow()
                .should("not.have.class", dashboard.answersOpen);
        });
        it("can scroll across the different activities", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getActivityNames().last()
                .scrollIntoView({ duration: 2000 });
        });
    });

    describe("Verifies for Activity/Seq data", function() {
        beforeEach(() => {
            cy.get("@sequenceStructure").its("children").as("activities");
        });

        it("Checks for activity names", () => {
            cy.get("@activities").then(activities => {
                dashboard.getActivityNames()
                    .should("have.length", activities.length);

                for (let i = 0; i < activities.length; i++) {
                    let activity = activities[i];
                    dashboard.getActivityNames()
                        .should("contain", activity.name);
                }
            });
        });
        it("can expand activity questions", () => {
            cy.get("@activities").then(activities => {
                let firstActivity = activities[0];
                let questionData = getActivityQuestionData(firstActivity);
                let questionTotal = questionData.length;
                let currentQuestionPrompt;

                dashboard.getExpandQuestionDetails()
                    .should("not.exist");
                dashboard.getOpenCloseStudents()
                    .click({ force: true });
                dashboard.getExpandQuestionDetails()
                    .should("exist")
                    .and("be.visible")
                    .and("have.length", questionTotal);

                for (let i = 0; i < questionTotal; i++) {
                    // strip html chars from the prompt
                    currentQuestionPrompt = Cypress.$(questionData[i].prompt).text();
                    dashboard.getActivityQuestionsText()
                        .should("contain", currentQuestionPrompt);
                }

                dashboard.getExpandedMCAnswerDetails()
                    .should("not.exist");

                // This is assuming the 2nd question is a multiple choice question
                dashboard.getExpandQuestionDetails().eq(1)
                    .click({ force: true });
                dashboard.getExpandedQuestionPanel()
                    .should("be.visible");
                dashboard.getExpandedMCAnswerDetails()
                    .should("be.visible")
                    .and("exist");
                dashboard.getCloseExpandedQuestion()
                    .should("exist")
                    .click({ force: true });
                dashboard.getExpandedQuestionPanel()
                    .should("not.exist");
            });
        });
        it("can expand activities to show questions", () => {
            dashboard.getActivityNames().eq(0)
                .click({ force: true });
            cy.get("@activities").then((activities) => {
                const questionData = getActivityQuestionData(activities[0]);

                dashboard.getActivityQuestions().eq(0).within(() => {
                  dashboard.getActivityQuestionToggle()
                  .should("exist")
                  .and("have.length", questionData.length);
                });
            });
            dashboard.getActivityQuestionsText()
                .should("not.exist");
            dashboard.getActivityQuestionToggle().eq(0)
                .click({ force: true });
            dashboard.getActivityQuestionsText()
                .should("be.visible");
            dashboard.getActivityQuestionsText().eq(0)
                .click({ force: true });
            dashboard.getActivityQuestionsText()
                .should("not.exist");
        });

        // it.only('Checks for one students data', () => {
        //     cy.get('@classData').then((classData) => {
        //         const activities = classData.report.children
        //         const students = classData.class.students
        //         let studentID;
        //         let activityAnswers;
        //         let answerText;
        //         let answerID;

        //         // for (let i=0; i<students.length;i++) {
        //         //     studentID = students[i].id
        //         //     dashboard.getStudentNames().eq(i)
        //         //         .click({force:true}) make sure this block is commented out after I put it back

        //         studentID = 14//students[0].id
        //         dashboard.getStudentNames().eq(0)
        //             .click({force:true})

        //         for (let j=0; j<activities.length;j++) {
        //             activityAnswers = activities[j].children[0].children[0].children[0].answers
        //             cy.log(activityAnswers)
        //             for (let k=0; k<activityAnswers.length;k++) {
        //                 answerID = activityAnswers[k].student_id

        //                 if(answerID === studentID) {
        //                     if (activityAnswers[k].answer) {
        //                         answerText = activityAnswers[k].answer
        //                     }
        //                     dashboard.getStudentAnswersRow().eq(0)
        //                         .should('contain', answerText)
        //                     }
        //                 }

        //             dashboard.getStudentNames().eq(0)
        //                 .click({force:true})
        //         }
        //     })
        // })
    });

    describe("Student Data", () => {

        it("Checks for student names", () => {
            cy.get("@classData").then((classData) => {
                const students = classData.students;

                dashboard.getStudentNames()
                    .should("have.length", students.length);

                for (let i = 0; i < students.length; i++) {
                    let student = students[i];
                    dashboard.getStudentNames()
                        .should("contain", student.last_name + ", " + student.first_name);
                }
            });
        });
        it("show responses", () => {
            const multipleChoiceQuestionIndex = 1;

            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandQuestionDetails().eq(multipleChoiceQuestionIndex)
                .click({ force: true });
            cy.get("@sequenceStructure")
              .its("children")
              .then((activities) => {
                const questionData = getActivityQuestionData(activities[0])[multipleChoiceQuestionIndex];

                dashboard.getExpandedMCAnswerDetails()
                    .should("exist")
                    .and("contain", questionData.choices[0].content)
                    .and("contain", "No response");

                dashboard.getExpandedMCAnswers()
                    .should("not.exist");
                dashboard.getShowHideResponse()
                    .should("exist")
                    .click({ force: true })
                    .then(() => {
                        dashboard.getExpandedMCAnswers()
                            .should("exist")
                            .and("contain", "Jenna Armstrong");
                    });
            });
            dashboard.getCloseExpandedQuestion()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedQuestionPanel()
                .should("not.exist");
        });
        it("hide responses", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
            dashboard.getExpandQuestionDetails().eq(1)
                .click({ force: true });
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("exist")
                // Student 1 has an answer of b
                .and("contain", "b");
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
        });
        it("shows MC question response", () => {
            dashboard.getOpenCloseStudents()
                .click({ force: true });
            dashboard.getExpandQuestionDetails().eq(1)
                .click({ force: true });
            dashboard.getExpandedMCAnswerDetails()
                .should("exist")
                .and("contain", "b")
                .and("contain", "No response");
            dashboard.getExpandedMCAnswers()
                .should("not.exist");
            dashboard.getShowHideResponse()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedMCAnswers()
                .should("exist")
                .and("contain", "Jenna Armstrong");
            dashboard.getCloseExpandedQuestion()
                .should("exist")
                .click({ force: true });
            dashboard.getExpandedQuestionPanel()
                .should("not.exist");
        });

    });

});
<|endoftext|>


<commit_before>// --
// Core.Form.js - provides functions for form handling
// Copyright (C) 2001-2010 OTRS AG, http://otrs.org/\n";
// --
// $Id: Core.Form.js,v 1.3 2010-07-16 08:01:14 cg Exp $
// --
// This software comes with ABSOLUTELY NO WARRANTY. For details, see
// the enclosed file COPYING for license information (AGPL). If you
// did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
// --

"use strict";

var Core = Core || {};

/**
 * @namespace
 * @exports TargetNS as Core.Form
 * @description
 *      This namespace contains all form functions.
 */
Core.Form = (function (TargetNS) {

    /*
     * check dependencies first
     */
    if (!Core.Debug.CheckDependency('Core.Form', 'Core.Data', 'Core.Data')) {
        return;
    }
    /**
     * @function
     * @description
     *      This function initializes the wrap attribute
     *      for use with textarea elements. It is not inside the HTML because
     *      these attributes are not part of the XHTML standard.
     * @return nothing
     */
    TargetNS.Init = function () {
        /* set wrap attribute to physical for browsers that need it */
        $('.Wrap_physical')
            .attr('wrap', 'physical');
        /* set wrap attribute to hard for browsers that need it */
        $('.Wrap_hard')
            .attr('wrap', 'hard');
    };

    /**
     * @function
     * @param {jQueryObject} $Form All elements of this form will be disabled
     * @description
     *      This function disables all elements of the given form. If no form given, it disables all form elements on the site.
     * @return nothing
     */
    TargetNS.DisableForm = function ($Form) {
        // If no form is given, disable all form elements on the complete site
        if (!isJQueryObject($Form)) {
            $Form = $('body');
        }

        // save action data to the given element
        $Form
            .find("input:not([type='hidden']), textarea, select")
            .bind('savereadonly', function () {
                var readonlyValue = $(this).attr('readonly');
                if (readonlyValue == true) {
                    readonlyValue = 'readonly';
                }
                else {
                    readonlyValue = '';
                }
                Core.Data.Set( $(this), 'OldReadonlyStatus', readonlyValue )
            })
            .trigger('savereadonly')
            .attr('readonly', 'readonly')
            .trigger('readonly')
            .end()
            .find('button')
            .bind('savedisabled', function () {
                var disabledValue = $(this).attr('disabled');
                if (disabledValue == true) {
                    disabledValue = 'disabled';
                }
                else {
                    disabledValue = '';
                }
                Core.Data.Set( $(this), 'OldDisabledStatus', disabledValue )
            })
            .trigger('savedisabled')
            .attr('disabled', 'disabled');

    };

    /**
     * @function
     * @param {jQueryObject} $Form All elements of this form will be enabled
     * @description
     *      This function enables all elements of the given form. If no form given, it enables all form elements on the site.
     * @return nothing
     */
    TargetNS.EnableForm = function ($Form) {
        // If no form is given, enable all form elements on the complete site
        if (!isJQueryObject($Form)) {
            $Form = $('body');
        }

        $Form
            .find("input:not([type=hidden]), textarea, select")
            .removeAttr('readonly')
            .trigger('readonly')
            .bind('retrievereadonly', function () {
                var readonlyValue = Core.Data.Get($(this), 'OldReadonlyStatus');
                $(this).attr('readonly',readonlyValue);
            })
            .trigger('retrievereadonly')
            .end()
            .find('button')
            .removeAttr('disabled')
            .bind('retrievedisabled', function () {
                var disabledValue = Core.Data.Get($(this), 'OldDisabledStatus');
                $(this).attr('disabled',disabledValue);
            })
            .trigger('retrievedisabled');
    };

    /**
     * @function
     * @description
     *      This function selects or deselects all checkboxes given by the ElementName.
     * @param {jQueryObject} $ClickedBox The clicked checkbox in the DOM
     * @param {jQueryObject} $SelectAllCheckbox The object with the SelectAll checkbox
     * @return nothing
     */
    TargetNS.SelectAllCheckboxes = function ($ClickedBox, $SelectAllCheckbox) {
        if (isJQueryObject($ClickedBox, $SelectAllCheckbox)) {
            var ElementName = $ClickedBox.attr('name'),
                SelectAllID = $SelectAllCheckbox.attr('id'),
                $Elements = $('input:checkbox[name=' + ElementName + ']').filter('[id!=' + SelectAllID + ']'),
                Status = $ClickedBox.attr('checked'),
                CountCheckboxes,
                CountSelectedCheckboxes;
            if ($ClickedBox.attr('id') && $ClickedBox.attr('id') === SelectAllID) {
                $Elements.attr('checked', Status).triggerHandler('click');
            }
            else {
                CountCheckboxes = $Elements.length;
                CountSelectedCheckboxes = $Elements.filter(':checked').length;
                if (CountCheckboxes === CountSelectedCheckboxes) {
                    $SelectAllCheckbox.attr('checked', 'checked');
                }
                else {
                    $SelectAllCheckbox.removeAttr('checked');
                }
            }
        }
    };

    /**
     * @function
     * @description
     *      This function marks the "SelectAll checkbox" as checked if all depending checkboxes are already marked checked.
     * @param {jQueryObject} $Checkboxes The jquery object with all dependent checkboxes
     * @param {jQueryObject} $SelectAllCheckbox The object with the SelectAll checkbox
     * @return nothing
     */
    TargetNS.InitSelectAllCheckboxes = function ($Checkboxes, $SelectAllCheckbox) {
        if (isJQueryObject($Checkboxes, $SelectAllCheckbox)) {
            if ($Checkboxes.length === $Checkboxes.filter(':checked').length) {
                $SelectAllCheckbox.attr('checked', 'checked');
            }
        }
    };

    return TargetNS;
}(Core.Form || {}));<commit_msg>Modified behavior for retrieve old values in Readonly and Disabled attributes.<commit_after>// --
// Core.Form.js - provides functions for form handling
// Copyright (C) 2001-2010 OTRS AG, http://otrs.org/\n";
// --
// $Id: Core.Form.js,v 1.4 2010-07-18 20:58:37 cg Exp $
// --
// This software comes with ABSOLUTELY NO WARRANTY. For details, see
// the enclosed file COPYING for license information (AGPL). If you
// did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
// --

"use strict";

var Core = Core || {};

/**
 * @namespace
 * @exports TargetNS as Core.Form
 * @description
 *      This namespace contains all form functions.
 */
Core.Form = (function (TargetNS) {

    /*
     * check dependencies first
     */
    if (!Core.Debug.CheckDependency('Core.Form', 'Core.Data', 'Core.Data')) {
        return;
    }
    /**
     * @function
     * @description
     *      This function initializes the wrap attribute
     *      for use with textarea elements. It is not inside the HTML because
     *      these attributes are not part of the XHTML standard.
     * @return nothing
     */
    TargetNS.Init = function () {
        /* set wrap attribute to physical for browsers that need it */
        $('.Wrap_physical')
            .attr('wrap', 'physical');
        /* set wrap attribute to hard for browsers that need it */
        $('.Wrap_hard')
            .attr('wrap', 'hard');
    };

    /**
     * @function
     * @param {jQueryObject} $Form All elements of this form will be disabled
     * @description
     *      This function disables all elements of the given form. If no form given, it disables all form elements on the site.
     * @return nothing
     */
    TargetNS.DisableForm = function ($Form) {
        // If no form is given, disable all form elements on the complete site
        if (!isJQueryObject($Form)) {
            $Form = $('body');
        }

        // save action data to the given element
        if (!$Form.hasClass("AlreadyDisabled")) {
            $.each($Form.find("input:not([type='hidden']), textarea, select, button"), function(key, value) {
                var readonlyValue = $(this).attr('readonly');
                var tagnameValue  = $(this).attr('tagName');
                var disabledValue = $(this).attr('disabled');

                if (tagnameValue == "BUTTON") {
                    if (disabledValue == true) {
                        Core.Data.Set( $(this), 'oldDisabledStatus', 'disabled' );
                    }
                }
                else {
                    if (readonlyValue == true) {
                        Core.Data.Set( $(this), 'oldReadonlyStatus', 'readonly' );
                    }
                }
            });

        $Form
            .find("input:not([type='hidden']), textarea, select")
            .attr('readonly', 'readonly')
            // trigger custom "readonly" event for Core.UI.IE7Fixes
            .trigger('readonly')
            .end()
            .find('button')
            .attr('disabled', 'disabled');

            // Add a speaking class to the form on DisableForm
            $Form.addClass('AlreadyDisabled');
        }

    };

    /**
     * @function
     * @param {jQueryObject} $Form All elements of this form will be enabled
     * @description
     *      This function enables all elements of the given form. If no form given, it enables all form elements on the site.
     * @return nothing
     */
    TargetNS.EnableForm = function ($Form) {
        // If no form is given, enable all form elements on the complete site
        if (!isJQueryObject($Form)) {
            $Form = $('body');
        }

        $Form
            .find("input:not([type=hidden]), textarea, select")
            .removeAttr('readonly')
            // trigger custom "readonly" event for Core.UI.IE7Fixes
            .trigger('readonly')
            .end()
            .find('button')
            .removeAttr('disabled');

        $.each($Form.find("input:not([type='hidden']), textarea, select, button"), function(key, value) {
            var tagnameValue  = $(this).attr('tagName');
            var readonlyValue = Core.Data.Get($(this), 'oldReadonlyStatus');
            var disabledValue = Core.Data.Get($(this), 'oldDisabledStatus');

            if (tagnameValue == "BUTTON") {
                if (disabledValue == 'disabled') {
                    $(this).attr('disabled', 'disabled');
                }
            }
            else {
                if (readonlyValue == 'readonly') {
                    $(this).attr('readonly', 'readonly');
                }
            }
        });

        // Remove the speaking class to the form on DisableForm
        $Form.removeClass('AlreadyDisabled');
    };

    /**
     * @function
     * @description
     *      This function selects or deselects all checkboxes given by the ElementName.
     * @param {jQueryObject} $ClickedBox The clicked checkbox in the DOM
     * @param {jQueryObject} $SelectAllCheckbox The object with the SelectAll checkbox
     * @return nothing
     */
    TargetNS.SelectAllCheckboxes = function ($ClickedBox, $SelectAllCheckbox) {
        if (isJQueryObject($ClickedBox, $SelectAllCheckbox)) {
            var ElementName = $ClickedBox.attr('name'),
                SelectAllID = $SelectAllCheckbox.attr('id'),
                $Elements = $('input:checkbox[name=' + ElementName + ']').filter('[id!=' + SelectAllID + ']'),
                Status = $ClickedBox.attr('checked'),
                CountCheckboxes,
                CountSelectedCheckboxes;
            if ($ClickedBox.attr('id') && $ClickedBox.attr('id') === SelectAllID) {
                $Elements.attr('checked', Status).triggerHandler('click');
            }
            else {
                CountCheckboxes = $Elements.length;
                CountSelectedCheckboxes = $Elements.filter(':checked').length;
                if (CountCheckboxes === CountSelectedCheckboxes) {
                    $SelectAllCheckbox.attr('checked', 'checked');
                }
                else {
                    $SelectAllCheckbox.removeAttr('checked');
                }
            }
        }
    };

    /**
     * @function
     * @description
     *      This function marks the "SelectAll checkbox" as checked if all depending checkboxes are already marked checked.
     * @param {jQueryObject} $Checkboxes The jquery object with all dependent checkboxes
     * @param {jQueryObject} $SelectAllCheckbox The object with the SelectAll checkbox
     * @return nothing
     */
    TargetNS.InitSelectAllCheckboxes = function ($Checkboxes, $SelectAllCheckbox) {
        if (isJQueryObject($Checkboxes, $SelectAllCheckbox)) {
            if ($Checkboxes.length === $Checkboxes.filter(':checked').length) {
                $SelectAllCheckbox.attr('checked', 'checked');
            }
        }
    };

    return TargetNS;
}(Core.Form || {}));<|endoftext|>


<commit_before>import * as path from 'path';

import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import SystemBellPlugin from 'system-bell-webpack-plugin';
import CleanWebpackPlugin from 'clean-webpack-plugin';
import merge from 'webpack-merge';

const pkg = require('./package.json');

const ROOT_PATH = __dirname;
const config = {
  paths: {
    dist: path.join(ROOT_PATH, 'dist'),
    src: path.join(ROOT_PATH, 'src'),
    docs: path.join(ROOT_PATH, 'docs')
  },
  filename: 'boilerplate',
  library: 'Boilerplate'
};

const common = {
  resolve: {
    extensions: ['.js', '.jsx', '.css', '.png', '.jpg']
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        enforce: 'pre',
        use: 'eslint-loader',
        include: [
          config.paths.docs,
          config.paths.src
        ]
      },
      {
        test: /\.md$/,
        use: ['catalog/lib/loader', 'raw-loader']
      },
      {
        test: /\.(jpg|png)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10000
          }
        }
      }
    ]
  },
  plugins: [
    new SystemBellPlugin()
  ]
};

const siteCommon = {
  plugins: [
    new HtmlWebpackPlugin({
      template: require('html-webpack-template'), // eslint-disable-line global-require
      inject: false,
      mobile: true,
      title: pkg.name,
      appMountId: 'app'
    }),
    new webpack.DefinePlugin({
      NAME: JSON.stringify(pkg.name),
      USER: JSON.stringify(pkg.user),
      VERSION: JSON.stringify(pkg.version)
    })
  ]
};

const dev = merge(common, siteCommon, {
  devtool: 'eval-source-map',
  entry: {
    docs: [config.paths.docs]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"development"'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(js|jsx)$/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true
          }
        },
        include: [
          config.paths.docs,
          config.paths.src
        ]
      }
    ]
  },
  devServer: {
    historyApiFallback: true,
    hot: true,
    inline: true,
    host: process.env.HOST,
    port: process.env.PORT,
    stats: 'errors-only'
  }
});

const ghPages = merge(common, siteCommon, {
  entry: {
    app: config.paths.docs
  },
  output: {
    path: './gh-pages',
    filename: '[name].[chunkhash].js',
    chunkFilename: '[chunkhash].js'
  },
  plugins: [
    new CleanWebpackPlugin(['gh-pages'], {
      verbose: false
    }),
    new ExtractTextPlugin('[name].[chunkhash].css'),
    new webpack.DefinePlugin({
        // This affects the react lib size
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: ({ resource }) => (
        resource &&
        resource.indexOf('node_modules') >= 0 &&
        resource.match(/\.js$/)
      )
    })
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        include: [
          config.paths.docs,
          config.paths.src
        ]
      }
    ]
  }
});

const distCommon = {
  devtool: 'source-map',
  output: {
    path: config.paths.dist,
    libraryTarget: 'umd',
    library: config.library
  },
  entry: config.paths.src,
  externals: {
    react: {
      commonjs: 'react',
      commonjs2: 'react',
      amd: 'React',
      root: 'React'
    }
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        include: config.paths.src
      }
    ]
  },
  plugins: [
    new SystemBellPlugin()
  ]
};

const dist = merge(distCommon, {
  output: {
    filename: `${config.filename}.js`
  }
});

const distMin = merge(distCommon, {
  output: {
    filename: `${config.filename}.min.js`
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
});

module.exports = (env) => {
  process.env.BABEL_ENV = env;

  const targets = {
    dev,
    dist,
    distMin,
    ghPages
  };

  return targets[env] ? targets[env] : common;
};
<commit_msg>fix: Fix gh-pages output path<commit_after>import * as path from 'path';

import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import SystemBellPlugin from 'system-bell-webpack-plugin';
import CleanWebpackPlugin from 'clean-webpack-plugin';
import merge from 'webpack-merge';

const pkg = require('./package.json');

const ROOT_PATH = __dirname;
const config = {
  paths: {
    dist: path.join(ROOT_PATH, 'dist'),
    src: path.join(ROOT_PATH, 'src'),
    docs: path.join(ROOT_PATH, 'docs'),
    ghPages: path.join(ROOT_PATH, 'gh-pages')
  },
  filename: 'boilerplate',
  library: 'Boilerplate'
};

const common = {
  resolve: {
    extensions: ['.js', '.jsx', '.css', '.png', '.jpg']
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        enforce: 'pre',
        use: 'eslint-loader',
        include: [
          config.paths.docs,
          config.paths.src
        ]
      },
      {
        test: /\.md$/,
        use: ['catalog/lib/loader', 'raw-loader']
      },
      {
        test: /\.(jpg|png)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10000
          }
        }
      }
    ]
  },
  plugins: [
    new SystemBellPlugin()
  ]
};

const siteCommon = {
  plugins: [
    new HtmlWebpackPlugin({
      template: require('html-webpack-template'), // eslint-disable-line global-require
      inject: false,
      mobile: true,
      title: pkg.name,
      appMountId: 'app'
    }),
    new webpack.DefinePlugin({
      NAME: JSON.stringify(pkg.name),
      USER: JSON.stringify(pkg.user),
      VERSION: JSON.stringify(pkg.version)
    })
  ]
};

const dev = merge(common, siteCommon, {
  devtool: 'eval-source-map',
  entry: {
    docs: [config.paths.docs]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"development"'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(js|jsx)$/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true
          }
        },
        include: [
          config.paths.docs,
          config.paths.src
        ]
      }
    ]
  },
  devServer: {
    historyApiFallback: true,
    hot: true,
    inline: true,
    host: process.env.HOST,
    port: process.env.PORT,
    stats: 'errors-only'
  }
});

const ghPages = merge(common, siteCommon, {
  entry: {
    app: config.paths.docs
  },
  output: {
    path: config.paths.ghPages,
    filename: '[name].[chunkhash].js',
    chunkFilename: '[chunkhash].js'
  },
  plugins: [
    new CleanWebpackPlugin(['gh-pages'], {
      verbose: false
    }),
    new ExtractTextPlugin('[name].[chunkhash].css'),
    new webpack.DefinePlugin({
        // This affects the react lib size
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: ({ resource }) => (
        resource &&
        resource.indexOf('node_modules') >= 0 &&
        resource.match(/\.js$/)
      )
    })
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        include: [
          config.paths.docs,
          config.paths.src
        ]
      }
    ]
  }
});

const distCommon = {
  devtool: 'source-map',
  output: {
    path: config.paths.dist,
    libraryTarget: 'umd',
    library: config.library
  },
  entry: config.paths.src,
  externals: {
    react: {
      commonjs: 'react',
      commonjs2: 'react',
      amd: 'React',
      root: 'React'
    }
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        include: config.paths.src
      }
    ]
  },
  plugins: [
    new SystemBellPlugin()
  ]
};

const dist = merge(distCommon, {
  output: {
    filename: `${config.filename}.js`
  }
});

const distMin = merge(distCommon, {
  output: {
    filename: `${config.filename}.min.js`
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
});

module.exports = (env) => {
  process.env.BABEL_ENV = env;

  const targets = {
    dev,
    dist,
    distMin,
    ghPages
  };

  return targets[env] ? targets[env] : common;
};
<|endoftext|>


<commit_before>///<reference path="FusionCalculator.ts"/>
///<reference path="../data/PersonaData.ts"/>
///<reference path="../data/SkillData.ts"/>
/**
 * Created by Chin on 08-Apr-17.
 */
var PersonaController = (function () {
    function PersonaController($scope, $routeParams, $filter) {
        var personaName = $routeParams.persona_name;
        this.$filter = $filter;
        this.$scope = $scope;
        this.$scope.Math = Math;
        this.$scope.personaName = personaName;
        this.$scope.persona = personaMap[personaName];
        if (!this.$scope.persona)
            return;
        var calc = new FusionCalculator(customPersonaeByArcana);
        this.$scope.perPage = 20;
        // fusion to
        var fusionToRecipes = calc.getRecipes(this.$scope.persona);
        fusionToRecipes.sort(function (a, b) { return a.cost - b.cost; });
        for (var i = 0, recipe = null; recipe = fusionToRecipes[i]; i++) {
            recipe.num = i;
        }
        var fusionTo = {
            allRecipes: fusionToRecipes,
            recipes: fusionToRecipes,
            numRecipes: fusionToRecipes.length,
            lastPage: Math.floor(fusionToRecipes.length / this.$scope.perPage),
            pageNum: 0,
            filterStr: ""
        };
        this.$scope.fusionTo = fusionTo;
        this.$scope.$watch('fusionTo.filterStr', this.getPaginateAndFilterFunc(false).bind(this));
        this.$scope.$watch('fusionTo.filterStr', this.getResetPageFunc(false).bind(this));
        this.$scope.$watch('fusionTo.pageNum', this.getPaginateAndFilterFunc(false).bind(this));
        // fusion from
        var fusionFromRecipes = calc.getAllResultingRecipesFrom(this.$scope.persona);
        fusionFromRecipes.sort(function (a, b) { return a.cost - b.cost; });
        for (var i = 0, recipe = null; recipe = fusionFromRecipes[i]; i++) {
            recipe.num = i;
        }
        var fusionFrom = {
            allRecipes: fusionFromRecipes,
            recipes: fusionFromRecipes,
            numRecipes: fusionFromRecipes.length,
            lastPage: Math.floor(fusionFromRecipes.length / this.$scope.perPage),
            pageNum: 0,
            filterStr: ""
        };
        this.$scope.fusionFrom = fusionFrom;
        this.$scope.$watch('fusionFrom.filterStr', this.getPaginateAndFilterFunc(true).bind(this));
        this.$scope.$watch('fusionFrom.filterStr', this.getResetPageFunc(true).bind(this));
        this.$scope.$watch('fusionFrom.pageNum', this.getPaginateAndFilterFunc(true).bind(this));
        // stats
        var compediumEntry = personaMap[personaName];
        this.$scope.persona.stats = compediumEntry.stats;
        this.$scope.persona.statsHeader = ["Strength", "Magic", "Endurance", "Agility", "Luck"];
        // elements
        // split the table into 2 for mobile
        var elems = getElems(personaName);
        this.$scope.persona.elems = elems;
        this.$scope.persona.elems1 = elems.slice(0, 5);
        this.$scope.persona.elems2 = elems.slice(5);
        // split the table into 2 for mobile
        var elemsHeader = ["Physical", "Gun", "Fire", "Ice", "Electric", "Wind", "Psychic", "Nuclear", "Bless", "Curse"];
        this.$scope.persona.elemsHeader = elemsHeader;
        this.$scope.persona.elemsHeader1 = elemsHeader.slice(0, 5);
        this.$scope.persona.elemsHeader2 = elemsHeader.slice(5);
        // Note: skillList are skills in a sorted list for displaying with Angular.
        // It's different from the existing skills property which is a map.
        this.$scope.persona.skillList = getSkills(personaName);
    }
    PersonaController.prototype.paginateAndFilter = function (fusionFromTo, filterFunc) {
        if (fusionFromTo.pageNum < 0)
            fusionFromTo.pageNum = 0;
        if (fusionFromTo.pageNum > fusionFromTo.lastPage)
            fusionFromTo.pageNum = fusionFromTo.lastPage;
        if (fusionFromTo.filterStr) {
            fusionFromTo.recipes = this.$filter('filter')(fusionFromTo.allRecipes, filterFunc(fusionFromTo.filterStr));
        }
        else {
            fusionFromTo.recipes = fusionFromTo.allRecipes;
        }
        fusionFromTo.lastPage = Math.floor(fusionFromTo.recipes.length / this.$scope.perPage);
        fusionFromTo.numRecipes = fusionFromTo.recipes.length;
        fusionFromTo.recipes = fusionFromTo.recipes.slice(fusionFromTo.pageNum * this.$scope.perPage, fusionFromTo.pageNum * this.$scope.perPage + this.$scope.perPage);
    };
    PersonaController.prototype.getPaginateAndFilterFunc = function (isFusionFrom) {
        var _this = this;
        return function (newVal, oldVal, scope) { return _this.paginateAndFilter(isFusionFrom ? scope.fusionFrom : scope.fusionTo, _this.getRecipeFilterFunc(isFusionFrom)); };
    };
    PersonaController.prototype.getRecipeFilterFunc = function (isFusionFrom) {
        var containsIgnoreCase = function (str, filter) { return str.toLowerCase().indexOf(filter.toLowerCase()) !== -1; };
        if (isFusionFrom) {
            return function (filterString) { return function (recipe, index, array) {
                return containsIgnoreCase(recipe.sources[1].name, filterString) || containsIgnoreCase(recipe.result.name, filterString);
            }; };
        }
        else {
            return function (filterString) { return function (recipe, index, array) {
                for (var i = 0; i < recipe.sources.length; i++) {
                    if (containsIgnoreCase(recipe.sources[i].name, filterString)) {
                        return true;
                    }
                }
                return false;
            }; };
        }
    };
    PersonaController.prototype.resetPage = function (fusionFromTo) {
        fusionFromTo.pageNum = 0;
    };
    PersonaController.prototype.getResetPageFunc = function (isFusionFrom) {
        var _this = this;
        return function (newVal, oldVal, scope) { return _this.resetPage(isFusionFrom ? scope.fusionFrom : scope.fusionTo); };
    };
    return PersonaController;
}());
<commit_msg>Update PersonaController.js<commit_after>///<reference path="FusionCalculator.ts"/>
///<reference path="../data/PersonaData.ts"/>
///<reference path="../data/SkillData.ts"/>
/**
 * Created by Chin on 08-Apr-17.
 */
var PersonaController = (function () {
    function PersonaController($scope, $routeParams, $filter) {
        var personaName = $routeParams.persona_name;
        this.$filter = $filter;
        this.$scope = $scope;
        this.$scope.Math = Math;
        this.$scope.personaName = personaName;
        this.$scope.persona = personaMap[personaName];
        if (!this.$scope.persona)
            return;
        var calc = new FusionCalculator(customPersonaeByArcana);
        this.$scope.perPage = 20;
        // fusion to
        var fusionToRecipes = calc.getRecipes(this.$scope.persona);
        fusionToRecipes.sort(function (a, b) { return a.cost - b.cost; });
        for (var i = 0, recipe = null; recipe = fusionToRecipes[i]; i++) {
            recipe.num = i;
        }
        var fusionTo = {
            allRecipes: fusionToRecipes,
            recipes: fusionToRecipes,
            numRecipes: fusionToRecipes.length,
            lastPage: Math.floor(fusionToRecipes.length / this.$scope.perPage),
            pageNum: 0,
            filterStr: ""
        };
        this.$scope.fusionTo = fusionTo;
        this.$scope.$watch('fusionTo.filterStr', this.getPaginateAndFilterFunc(false).bind(this));
        this.$scope.$watch('fusionTo.filterStr', this.getResetPageFunc(false).bind(this));
        this.$scope.$watch('fusionTo.pageNum', this.getPaginateAndFilterFunc(false).bind(this));
        // fusion from
        var fusionFromRecipes = calc.getAllResultingRecipesFrom(this.$scope.persona);
        fusionFromRecipes.sort(function (a, b) { return a.cost - b.cost; });
        for (var i = 0, recipe = null; recipe = fusionFromRecipes[i]; i++) {
            recipe.num = i;
        }
        var fusionFrom = {
            allRecipes: fusionFromRecipes,
            recipes: fusionFromRecipes,
            numRecipes: fusionFromRecipes.length,
            lastPage: Math.floor(fusionFromRecipes.length / this.$scope.perPage),
            pageNum: 0,
            filterStr: ""
        };
        this.$scope.fusionFrom = fusionFrom;
        this.$scope.$watch('fusionFrom.filterStr', this.getPaginateAndFilterFunc(true).bind(this));
        this.$scope.$watch('fusionFrom.filterStr', this.getResetPageFunc(true).bind(this));
        this.$scope.$watch('fusionFrom.pageNum', this.getPaginateAndFilterFunc(true).bind(this));
        // stats
        var compediumEntry = personaMap[personaName];
        this.$scope.persona.stats = compediumEntry.stats;
        this.$scope.persona.statsHeader = ["St", "Ma", "En", "Ag", "Lu"];
        // elements
        // split the table into 2 for mobile
        var elems = getElems(personaName);
        this.$scope.persona.elems = elems;
        this.$scope.persona.elems1 = elems.slice(0, 5);
        this.$scope.persona.elems2 = elems.slice(5);
        // split the table into 2 for mobile
        var elemsHeader = ["Phys", "Gun", "Fire", "Ice", "Elec", "Wind", "Psy", "Nuke", "Bless", "Curse"];
        this.$scope.persona.elemsHeader = elemsHeader;
        this.$scope.persona.elemsHeader1 = elemsHeader.slice(0, 5);
        this.$scope.persona.elemsHeader2 = elemsHeader.slice(5);
        // Note: skillList are skills in a sorted list for displaying with Angular.
        // It's different from the existing skills property which is a map.
        this.$scope.persona.skillList = getSkills(personaName);
    }
    PersonaController.prototype.paginateAndFilter = function (fusionFromTo, filterFunc) {
        if (fusionFromTo.pageNum < 0)
            fusionFromTo.pageNum = 0;
        if (fusionFromTo.pageNum > fusionFromTo.lastPage)
            fusionFromTo.pageNum = fusionFromTo.lastPage;
        if (fusionFromTo.filterStr) {
            fusionFromTo.recipes = this.$filter('filter')(fusionFromTo.allRecipes, filterFunc(fusionFromTo.filterStr));
        }
        else {
            fusionFromTo.recipes = fusionFromTo.allRecipes;
        }
        fusionFromTo.lastPage = Math.floor(fusionFromTo.recipes.length / this.$scope.perPage);
        fusionFromTo.numRecipes = fusionFromTo.recipes.length;
        fusionFromTo.recipes = fusionFromTo.recipes.slice(fusionFromTo.pageNum * this.$scope.perPage, fusionFromTo.pageNum * this.$scope.perPage + this.$scope.perPage);
    };
    PersonaController.prototype.getPaginateAndFilterFunc = function (isFusionFrom) {
        var _this = this;
        return function (newVal, oldVal, scope) { return _this.paginateAndFilter(isFusionFrom ? scope.fusionFrom : scope.fusionTo, _this.getRecipeFilterFunc(isFusionFrom)); };
    };
    PersonaController.prototype.getRecipeFilterFunc = function (isFusionFrom) {
        var containsIgnoreCase = function (str, filter) { return str.toLowerCase().indexOf(filter.toLowerCase()) !== -1; };
        if (isFusionFrom) {
            return function (filterString) { return function (recipe, index, array) {
                return containsIgnoreCase(recipe.sources[1].name, filterString) || containsIgnoreCase(recipe.result.name, filterString);
            }; };
        }
        else {
            return function (filterString) { return function (recipe, index, array) {
                for (var i = 0; i < recipe.sources.length; i++) {
                    if (containsIgnoreCase(recipe.sources[i].name, filterString)) {
                        return true;
                    }
                }
                return false;
            }; };
        }
    };
    PersonaController.prototype.resetPage = function (fusionFromTo) {
        fusionFromTo.pageNum = 0;
    };
    PersonaController.prototype.getResetPageFunc = function (isFusionFrom) {
        var _this = this;
        return function (newVal, oldVal, scope) { return _this.resetPage(isFusionFrom ? scope.fusionFrom : scope.fusionTo); };
    };
    return PersonaController;
}());
<|endoftext|>