<commit_before>/**
 * Remove all lines breaks and "extra" spaces, when there are more than 1 spaces in a row
 *
 * @returns {string}
 */
String.prototype.removeLineBreaksAnsExtraSpaces = function () {
  return this
    .replace(/\r?\n|\r/g, ' ') // replace line breaks by spaces
    .replace(/ {2,}/g, ' ');   // replace 2 or more spaces by only one
};

/**
 * Create and return an object which contains all elements for which the callback returns true
 *
 * @param object
 * @param callback
 *
 * @return object
 */
function filterObject(object, callback) {
  var filteredObject = {};

  for (var property in object) {
    if (object.hasOwnProperty(property)) {
      if (callback(object[property])) {
        filteredObject[property] = object[property];
      }
    }
  }

  return filteredObject;
}

/**
 * Sort an object by keys
 *
 *
 * @param object
 * @param {[]} [firstKeys] : if the firstKeys param is set, set them at the beginning of the object
 * @param {boolean} [sortAll] : if false, only sort by first keys
 *
 * @returns {{}}
 */
function sortObject(object, firstKeys, sortAll) {
  const ordered = {};

  if (typeof sortAll === 'undefined') {
    sortAll = true;
  }

  if (typeof firstKeys === 'undefined') {
    firstKeys = [];
  }

  for (var i = 0, len = firstKeys.length;  i < len; i++) {
    var key = firstKeys[i];
    ordered[key] = object[key];
  }

  if (sortAll) {
    Object.keys(object).sort().forEach(function(key) {
      if (firstKeys.indexOf(key) === -1) {
        ordered[key] = object[key];
      }
    });
  } else {
    for (var key in object) {
      if (object.hasOwnProperty(key)) {
        if (firstKeys.indexOf(key) === -1) {
          ordered[key] = object[key];
        }
      }
    }
  }

  return ordered;
}

/**
 * Generate a unique id for the fields default names
 *
 * @returns string
 */
function generateUniqueId() {
  return Math.random().toString(36).substr(2, 9);
}

/**
 * Get the last key of an object
 *
 * @param object
 * @returns string
 */
function getLastKey(object) {
  var keys = Object.keys(object);
  var lastElementPosition = keys.length - 1;

  return keys[lastElementPosition];
}

/**
 * Hash a string to a 32 bit integer
 *
 * @param string
 * @returns {number}
 */
function hashCode(string) {
  var hash = 0;
  var chr;

  if (string.length === 0) {
    return hash;
  }

  for (var i = 0; i < string.length; i++) {
    chr   = string.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }

  return hash;
}

/**
 * Create a javascript object to get the map all the attribute of the given element, as well as the value
 *
 * @param element
 *
 * @return object
 */
function createAttributeMapObject(element) {
  var attributes = element.attributes;
  var object = {};

  for (var attribute, i = 0, length = attributes.length; i < length; i++) {
    attribute = attributes[i];
    object[attribute.nodeName] = attribute.nodeValue;
  }

  object.value = element.value;

  return object;
}

/**
 * Create the html for a bootstrap modal
 *
 * @param id
 * @param name
 * @param extraClasses
 * @param title
 * @param body
 * @param [modalFooter]
 *
 * @returns {string}
 */
function createBootstrapModal (id, name, extraClasses, title, body, modalFooter) {
  var footer = modalFooter ? modalFooter : '';

  return '' +
    '
' +
      '
' +
        '
' +
          '
' +
            '<button type="button" class="close" aria-label="Close">' +
              '×' +
            '</button>' +
            '
' + title + '
' +
          '
' +
          '
' +
            body +
          '
' +
          '
' +
            footer +
          '
' +
        '
' +
      '
' +
    '
'
  ;
}

/**
 * Add some colors on empty required inputs
 *
 * @param elementId - the if of the element wrapping the inputs
 * @param parentClass - the class of the parent of the required input, in case we don't want to select every inputs
 */
function colorEmptyRequiredInputs (elementId, parentClass) {
  var inputSelector = '.' + parentClass + ' input[required="required"]';

  /**
   * Color in red when empty, in white when filled
   *
   * @param $input
   */
  function color ($input) {
    if ($input.val()) {
      $input.css({
        'border-color': '#cccccc',
        'background-color': '#ffffff'
      });
    } else {
      $input.css({
        'border-color': '#c9302c',
        'background-color': '#f3d9d9'
      });
    }
  }

  // Color on change when the input is empty
  $(document).on('change', inputSelector, function () {
    color($(this));
  });

  // Color when new children are added to the dom
  // Sometimes they are added but already filled by vuejs, sometimes they are empty
  var target = document.getElementById(elementId);
  var config = { childList: true, characterData: true, subtree: true};

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      var $inputs = [];

      if ($(mutation.target).hasClass(parentClass)) {
        $inputs = $(mutation.target).find('input[required="required"]');
      } else {
        $inputs = $(mutation.target).find(inputSelector);
      }

      $inputs.each(function() {
        color($(this));
      });
    });
  });

  observer.observe(target, config);
}
<commit_msg>Update the hashCode function to return a string<commit_after>/**
 * Remove all lines breaks and "extra" spaces, when there are more than 1 spaces in a row
 *
 * @returns {string}
 */
String.prototype.removeLineBreaksAnsExtraSpaces = function () {
  return this
    .replace(/\r?\n|\r/g, ' ') // replace line breaks by spaces
    .replace(/ {2,}/g, ' ');   // replace 2 or more spaces by only one
};

/**
 * Create and return an object which contains all elements for which the callback returns true
 *
 * @param object
 * @param callback
 *
 * @return object
 */
function filterObject(object, callback) {
  var filteredObject = {};

  for (var property in object) {
    if (object.hasOwnProperty(property)) {
      if (callback(object[property])) {
        filteredObject[property] = object[property];
      }
    }
  }

  return filteredObject;
}

/**
 * Sort an object by keys
 *
 *
 * @param object
 * @param {[]} [firstKeys] : if the firstKeys param is set, set them at the beginning of the object
 * @param {boolean} [sortAll] : if false, only sort by first keys
 *
 * @returns {{}}
 */
function sortObject(object, firstKeys, sortAll) {
  const ordered = {};

  if (typeof sortAll === 'undefined') {
    sortAll = true;
  }

  if (typeof firstKeys === 'undefined') {
    firstKeys = [];
  }

  for (var i = 0, len = firstKeys.length;  i < len; i++) {
    var key = firstKeys[i];
    ordered[key] = object[key];
  }

  if (sortAll) {
    Object.keys(object).sort().forEach(function(key) {
      if (firstKeys.indexOf(key) === -1) {
        ordered[key] = object[key];
      }
    });
  } else {
    for (var key in object) {
      if (object.hasOwnProperty(key)) {
        if (firstKeys.indexOf(key) === -1) {
          ordered[key] = object[key];
        }
      }
    }
  }

  return ordered;
}

/**
 * Generate a unique id for the fields default names
 *
 * @returns string
 */
function generateUniqueId() {
  return Math.random().toString(36).substr(2, 9);
}

/**
 * Get the last key of an object
 *
 * @param object
 * @returns string
 */
function getLastKey(object) {
  var keys = Object.keys(object);
  var lastElementPosition = keys.length - 1;

  return keys[lastElementPosition];
}

/**
 * Hash a string to a 32 bit integer
 *
 * @param {string} string
 * @returns {string}
 */
function hashCode(string) {
  var hash = 0;
  var chr;

  if (string.length === 0) {
    return hash.toString();
  }

  for (var i = 0; i < string.length; i++) {
    chr   = string.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }

  return hash.toString();
}

/**
 * Create a javascript object to get the map all the attribute of the given element, as well as the value
 *
 * @param element
 *
 * @return object
 */
function createAttributeMapObject(element) {
  var attributes = element.attributes;
  var object = {};

  for (var attribute, i = 0, length = attributes.length; i < length; i++) {
    attribute = attributes[i];
    object[attribute.nodeName] = attribute.nodeValue;
  }

  object.value = element.value;

  return object;
}

/**
 * Create the html for a bootstrap modal
 *
 * @param id
 * @param name
 * @param extraClasses
 * @param title
 * @param body
 * @param [modalFooter]
 *
 * @returns {string}
 */
function createBootstrapModal (id, name, extraClasses, title, body, modalFooter) {
  var footer = modalFooter ? modalFooter : '';

  return '' +
    '
' +
      '
' +
        '
' +
          '
' +
            '<button type="button" class="close" aria-label="Close">' +
              '×' +
            '</button>' +
            '
' + title + '
' +
          '
' +
          '
' +
            body +
          '
' +
          '
' +
            footer +
          '
' +
        '
' +
      '
' +
    '
'
  ;
}

/**
 * Add some colors on empty required inputs
 *
 * @param elementId - the if of the element wrapping the inputs
 * @param parentClass - the class of the parent of the required input, in case we don't want to select every inputs
 */
function colorEmptyRequiredInputs (elementId, parentClass) {
  var inputSelector = '.' + parentClass + ' input[required="required"]';

  /**
   * Color in red when empty, in white when filled
   *
   * @param $input
   */
  function color ($input) {
    if ($input.val()) {
      $input.css({
        'border-color': '#cccccc',
        'background-color': '#ffffff'
      });
    } else {
      $input.css({
        'border-color': '#c9302c',
        'background-color': '#f3d9d9'
      });
    }
  }

  // Color on change when the input is empty
  $(document).on('change', inputSelector, function () {
    color($(this));
  });

  // Color when new children are added to the dom
  // Sometimes they are added but already filled by vuejs, sometimes they are empty
  var target = document.getElementById(elementId);
  var config = { childList: true, characterData: true, subtree: true};

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      var $inputs = [];

      if ($(mutation.target).hasClass(parentClass)) {
        $inputs = $(mutation.target).find('input[required="required"]');
      } else {
        $inputs = $(mutation.target).find(inputSelector);
      }

      $inputs.each(function() {
        color($(this));
      });
    });
  });

  observer.observe(target, config);
}
<|endoftext|>


<commit_before>DataGrid.ClientSide = DataGrid.extend({

    init: function(columns, data, options) {
        var options = $.extend({
            inline: true,
            allowEdit: false,
            editRoute: null,
            allowCreate: false,
            createRoute: null,
            allowDelete: false,
            deleteRoute: null,
            sortable: true,
            pageSize: 10,
            page: 1,
            enableFilter: true,
            enablePageSizeSelector: true
        }, options, true);

        this._super(columns, data, options);

        this.currentPage = ko.observable(options.page);

        this.filteredRows = ko.computed(function() {
            if (!this.filter()) {
                return this.existingRows();
            }

            var filteredRows = [];
            for (i in this.existingRows()) {
                var row = this.existingRows()[i];
                for (j in this.columns()) {
                    var column = this.columns()[j];
                    var value = row.textData()[column.name];

                    if (value.toString().indexOf(this.filter()) > -1) {
                        filteredRows.push(row);
                        break;
                    }
                }
            }

            return filteredRows;
        }, this);

        this.pages = ko.computed(function() {
            var pages = [];
            for (a = 1; a <= Math.ceil(this.filteredRows().length / this.pageSize()); a++) {
                pages.push(a);
            }
            return pages;
        }, this);

        this.page = ko.computed({
            read: function() {
                if (this.currentPage() > this.pages().length) {
                    this.currentPage(this.pages().length);
                }
                if (this.currentPage() < 1) {
                    this.currentPage(1);
                }
                if (this.currentPage() * this.pageSize() > this.filteredRows().length) {
                    this.currentPage(Math.ceil(this.filteredRows().length / this.pageSize()));
                }
                return this.currentPage();
            },
            write: function(value) {
                this.currentPage(value);
            },
            owner: this
        });

        this.visibleRows = ko.computed(function() {
            return this.filteredRows().slice((this.page() - 1) * this.pageSize(), (this.page() * this.pageSize()));
        }, this);

        this.resultsText = ko.computed(function() {
            var ret = ((this.page() - 1) * this.pageSize() + 1);
            ret += ' through ';

            var last = (this.page() * this.pageSize());
            if (last > this.filteredRows().length) {
                last = this.filteredRows().length;
            }
            ret += last;

            ret += ' of ';
            ret += this.filteredRows().length;
            ret += ' results displayed (total: ' + this.rows().length + ')';

            return ret;
        }, this);
    },

    setPage: function(page) {
        this.page(page);
    },

    loadCreateForm: function() {
        var data = {};
        for (i in this.columns()) {
            data[this.columns()[i].name] = "";
        }
        var row = new Row(data);
        row.setGrid(this);
        row.isNew(true);
        $.get(row.getSaveUrl(), function(data) {
            row.createForm(data);
        });

        this.rows.push(row);
    },

    sort: function(column) {
        if (!this.sortable || !column.sortable) {
            return;
        }

        this.sorting({ column: column, inverse: this.sorting().column === column ? !this.sorting().inverse : false });

        var self = this;
        this.rows.sort(function(a, b) {
            var ret = 0;

            if (a.textData()[self.sorting().column.name] > b.textData()[self.sorting().column.name]) {
                ret = 1;
            } else if (a.textData()[self.sorting().column.name] < b.textData()[self.sorting().column.name]) {
                ret = -1;
            }

            if (self.sorting().inverse) {
                ret *= -1;
            }

            return ret;
        });
    }
});<commit_msg>bugfixes in filtering<commit_after>DataGrid.ClientSide = DataGrid.extend({

    init: function(columns, data, options) {
        var options = $.extend({
            inline: true,
            allowEdit: false,
            editRoute: null,
            allowCreate: false,
            createRoute: null,
            allowDelete: false,
            deleteRoute: null,
            sortable: true,
            pageSize: 10,
            page: 1,
            enableFilter: true,
            enablePageSizeSelector: true
        }, options, true);

        this._super(columns, data, options);

        this.currentPage = ko.observable(options.page);

        this.filteredRows = ko.computed(function() {
            if (!this.filter()) {
                return this.existingRows();
            }

            var filteredRows = [];
            for (i in this.existingRows()) {
                var row = this.existingRows()[i];
                for (j in this.columns()) {
                    var column = this.columns()[j];
                    var value = row.textData()[column.name];
                    if (!value) {
                        continue;
                    }

                    if (value.toString().toLowerCase().indexOf(this.filter().toLowerCase()) > -1) {
                        filteredRows.push(row);
                        break;
                    }
                }
            }

            return filteredRows;
        }, this);

        this.pages = ko.computed(function() {
            var pages = [];
            for (a = 1; a <= Math.ceil(this.filteredRows().length / this.pageSize()); a++) {
                pages.push(a);
            }
            return pages;
        }, this);

        this.page = ko.computed({
            read: function() {
                if (this.currentPage() > this.pages().length) {
                    this.currentPage(this.pages().length);
                }
                if (this.currentPage() < 1) {
                    this.currentPage(1);
                }
                if (this.currentPage() * this.pageSize() > this.filteredRows().length) {
                    this.currentPage(Math.ceil(this.filteredRows().length / this.pageSize()));
                }
                return this.currentPage();
            },
            write: function(value) {
                this.currentPage(value);
            },
            owner: this
        });

        this.visibleRows = ko.computed(function() {
            return this.filteredRows().slice((this.page() - 1) * this.pageSize(), (this.page() * this.pageSize()));
        }, this);

        this.resultsText = ko.computed(function() {
            var ret = ((this.page() - 1) * this.pageSize() + 1);
            ret += ' through ';

            var last = (this.page() * this.pageSize());
            if (last > this.filteredRows().length) {
                last = this.filteredRows().length;
            }
            ret += last;

            ret += ' of ';
            ret += this.filteredRows().length;
            ret += ' results displayed (total: ' + this.rows().length + ')';

            return ret;
        }, this);
    },

    setPage: function(page) {
        this.page(page);
    },

    loadCreateForm: function() {
        var data = {};
        for (i in this.columns()) {
            data[this.columns()[i].name] = "";
        }
        var row = new Row(data);
        row.setGrid(this);
        row.isNew(true);
        $.get(row.getSaveUrl(), function(data) {
            row.createForm(data);
        });

        this.rows.push(row);
    },

    sort: function(column) {
        if (!this.sortable || !column.sortable) {
            return;
        }

        this.sorting({ column: column, inverse: this.sorting().column === column ? !this.sorting().inverse : false });

        var self = this;
        this.rows.sort(function(a, b) {
            var ret = 0;

            if (a.textData()[self.sorting().column.name] > b.textData()[self.sorting().column.name]) {
                ret = 1;
            } else if (a.textData()[self.sorting().column.name] < b.textData()[self.sorting().column.name]) {
                ret = -1;
            }

            if (self.sorting().inverse) {
                ret *= -1;
            }

            return ret;
        });
    }
});<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Route.extend({
    queryParams: {
        page: { refreshModel: true },
        sort: { refreshModel: true },
    },
    data: {},

    setupController(controller, model) {
        this._super(controller, model);

        controller.set('fetchingFeed', true);
        controller.set('crates', this.get('data.crates'));
    },

    model(params) {
        const { user_id } = params;
        return this.store.find('user', user_id).then(
            (user) => {
                params.user_id = user.get('id');
                return Ember.RSVP.hash({
                    crates: this.store.query('crate', params),
                    user
                });
            },
            (e) => {
                if (e.errors.any(e => e.detail === 'Not Found')) {
                    this
                        .controllerFor('application')
                        .set('nextFlashError', `User '${params.user_id}' does not exist`);
                    return this.replaceWith('index');
                }
            }
        );
    },
});
<commit_msg>Reorder setupController and model for consistency<commit_after>import Ember from 'ember';

export default Ember.Route.extend({
    queryParams: {
        page: { refreshModel: true },
        sort: { refreshModel: true },
    },

    data: {},

    model(params) {
        const { user_id } = params;
        return this.store.find('user', user_id).then(
            (user) => {
                params.user_id = user.get('id');
                return Ember.RSVP.hash({
                    crates: this.store.query('crate', params),
                    user
                });
            },
            (e) => {
                if (e.errors.any(e => e.detail === 'Not Found')) {
                    this
                        .controllerFor('application')
                        .set('nextFlashError', `User '${params.user_id}' does not exist`);
                    return this.replaceWith('index');
                }
            }
        );
    },

    setupController(controller, model) {
        this._super(controller, model);

        controller.set('fetchingFeed', true);
        controller.set('crates', this.get('data.crates'));
    },
});
<|endoftext|>


<commit_before>var passport = require('passport');
var SteamStrategy = require('passport-steam').Strategy;
var cfg = require('config');

// http://steamcommunity.com/dev

// Passport session setup.
passport.serializeUser(function (user, done) {
    done(null, user);
});

passport.deserializeUser(function (obj, done) {
    done(null, obj);
});

passport.use(
    new SteamStrategy({
            returnURL: 'http://' + cfg.get('http.host') + ':' + cfg.get('http.port') + '/auth/return',
            realm: 'http://' + cfg.get('http.host') + ':' + cfg.get('http.port') + '/',
            apiKey: cfg.get('steam.api.key')
        },
        function (identifier, profile, done) {
            profile.url = identifier;
            return done(null, profile);
        }
    )
);

module.exports = passport;
<commit_msg>fixed reference to steam properties<commit_after>var passport = require('passport');
var SteamStrategy = require('passport-steam').Strategy;
var cfg = require('config');

// http://steamcommunity.com/dev

// Passport session setup.
passport.serializeUser(function (user, done) {
    done(null, user);
});

passport.deserializeUser(function (obj, done) {
    done(null, obj);
});

passport.use(
    new SteamStrategy({
            returnURL: 'http://' + cfg.get('http.host') + ':' + cfg.get('http.port') + '/auth/return',
            realm: 'http://' + cfg.get('http.host') + ':' + cfg.get('http.port') + '/',
            apiKey: cfg.get('Steam.api.key')
        },
        function (identifier, profile, done) {
            profile.url = identifier;
            return done(null, profile);
        }
    )
);

module.exports = passport;
<|endoftext|>


<commit_before>import key from './keys';

class MatrixTableController {

  static defaultValueParser(inputValue) {
    return inputValue;
  }

  constructor($element, $timeout) {
    'ngInject';

    this.$element = $element;
    this.$timeout = $timeout;

    this.valueParser = this.valueParser || MatrixTableController.defaultValueParser;
    this.inputNamePrefix = this.inputNamePrefix || 'matrix-table';
  }

  keyListener($event, scope) {
    let element = $event.target;
    let preventDefault = true;

    if ($event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey) {
      return;
    }

    switch ($event.keyCode) {
      case key.BACKSPACE:
      case key.LEFT:
        if (MatrixTableController._hasCaretAtStart(element)) {
          this._focusRelativeInput(scope, 0, -1);
        }
        break;
      case key.UP:
        this._focusRelativeInput(scope, -1, 0);
        break;
      case key.SPACE:
      case key.RIGHT:
        if (MatrixTableController._hasCaretAtEnd(element)) {
          if (this._isLastColumn(scope)) {
            this.addColumn();
            this.$timeout(() => {
              this._focusRelativeInput(scope, 0, 1);
            });
          } else {
            this._focusRelativeInput(scope, 0, 1);
          }
        }
        break;
      case key.DOWN:
        if (this._isLastRow(scope)) {
          this.addRow();
          this.$timeout(() => {
            this._focusRelativeInput(scope, 1, 0);
          });
        } else {
          this._focusRelativeInput(scope, 1, 0);
        }
        break;
      case key.ENTER:
        if (this._isLastRow(scope)) {
          this.addRow();
          this.$timeout(() => {
            this._focusNextRowFirstInput(scope);
          });
        } else {
          this._focusNextRowFirstInput(scope);
        }
        break;
      default:
        preventDefault = false;
    }

    if (preventDefault) {
      $event.preventDefault();
    }
  }

  addColumn() {
    this.matrix.forEach(row => {
      row.push({value: ''});
    });
  }

  addRow() {
    let rowLength = this.matrix[0].length;
    let row = [];
    for (let i = 0; i < rowLength; i++) {
      row.push({value: ''});
    }
    this.matrix.push(row);
  }

  popColumn() {
    this.matrix.forEach(row => {
      row.pop();
    });
  }

  popRow() {
    this.matrix.pop();
  }

  isValueValid(inputValue) {
    try {
      this.valueParser(inputValue);
      return true;
    } catch (err) {
      return false;
    }
  }

  _focusRelativeInput(scope, rowDiff, columnDiff) {
    let rowIndex = scope.rowScope.$index + rowDiff;
    let columnIndex = scope.$index + columnDiff;

    let row = this.$element.find('tr').eq(rowIndex);
    let input = row.find('input').eq(columnIndex);

    input[0].focus();
  }

  _focusNextRowFirstInput(scope) {
    let rowIndex = scope.rowScope.$index + 1;
    let row = this.$element.find('tr').eq(rowIndex);
    let input = row.find('input').eq(0);

    input[0].focus();
  }

  static _hasCaretAtStart(element) {
    let caretPosition = element.selectionStart;

    return caretPosition === element.selectionEnd &&
      caretPosition === 0;
  }

  static _hasCaretAtEnd(element) {
    let caretPosition = element.selectionStart;

    return caretPosition === element.selectionEnd &&
        caretPosition === element.value.length;
  }

  _isLastColumn(scope) {
    let index = scope.$index;
    let matrixRow = this.matrix[0];

    return index === matrixRow.length - 1;
  }

  _isLastRow(scope) {
    let index = scope.rowScope.$index;
    return index === this.matrix.length - 1;
  }
}

export default MatrixTableController;
<commit_msg>Fix arrow keys in matrix table inputs<commit_after>import key from './keys';

class MatrixTableController {

  static defaultValueParser(inputValue) {
    return inputValue;
  }

  constructor($element, $timeout) {
    'ngInject';

    this.$element = $element;
    this.$timeout = $timeout;

    this.valueParser = this.valueParser || MatrixTableController.defaultValueParser;
    this.inputNamePrefix = this.inputNamePrefix || 'matrix-table';
  }

  keyListener($event, scope) {
    let element = $event.target;
    let preventDefault = false;

    if ($event.ctrlKey || $event.shiftKey || $event.altKey || $event.metaKey) {
      return;
    }

    switch ($event.keyCode) {
      case key.BACKSPACE:
      case key.LEFT:
        if (MatrixTableController._hasCaretAtStart(element)) {
          this._focusRelativeInput(scope, 0, -1);
          preventDefault = true;
        }
        break;
      case key.UP:
        this._focusRelativeInput(scope, -1, 0);
        preventDefault = true;
        break;
      case key.SPACE:
      case key.RIGHT:
        if (MatrixTableController._hasCaretAtEnd(element)) {
          if (this._isLastColumn(scope)) {
            this.addColumn();
            this.$timeout(() => {
              this._focusRelativeInput(scope, 0, 1);
            });
          } else {
            this._focusRelativeInput(scope, 0, 1);
          }
          preventDefault = true;
        }
        break;
      case key.DOWN:
        if (this._isLastRow(scope)) {
          this.addRow();
          this.$timeout(() => {
            this._focusRelativeInput(scope, 1, 0);
          });
        } else {
          this._focusRelativeInput(scope, 1, 0);
        }
        preventDefault = true;
        break;
      case key.ENTER:
        if (this._isLastRow(scope)) {
          this.addRow();
          this.$timeout(() => {
            this._focusNextRowFirstInput(scope);
          });
        } else {
          this._focusNextRowFirstInput(scope);
        }
        preventDefault = true;
    }

    if (preventDefault) {
      $event.preventDefault();
    }
  }

  addColumn() {
    this.matrix.forEach(row => {
      row.push({value: ''});
    });
  }

  addRow() {
    let rowLength = this.matrix[0].length;
    let row = [];
    for (let i = 0; i < rowLength; i++) {
      row.push({value: ''});
    }
    this.matrix.push(row);
  }

  popColumn() {
    this.matrix.forEach(row => {
      row.pop();
    });
  }

  popRow() {
    this.matrix.pop();
  }

  isValueValid(inputValue) {
    try {
      this.valueParser(inputValue);
      return true;
    } catch (err) {
      return false;
    }
  }

  _focusRelativeInput(scope, rowDiff, columnDiff) {
    let rowIndex = scope.rowScope.$index + rowDiff;
    let columnIndex = scope.$index + columnDiff;

    let row = this.$element.find('tr').eq(rowIndex);
    let input = row.find('input').eq(columnIndex);

    input[0].focus();
  }

  _focusNextRowFirstInput(scope) {
    let rowIndex = scope.rowScope.$index + 1;
    let row = this.$element.find('tr').eq(rowIndex);
    let input = row.find('input').eq(0);

    input[0].focus();
  }

  static _hasCaretAtStart(element) {
    let caretPosition = element.selectionStart;

    return caretPosition === element.selectionEnd &&
      caretPosition === 0;
  }

  static _hasCaretAtEnd(element) {
    let caretPosition = element.selectionStart;

    return caretPosition === element.selectionEnd &&
        caretPosition === element.value.length;
  }

  _isLastColumn(scope) {
    let index = scope.$index;
    let matrixRow = this.matrix[0];

    return index === matrixRow.length - 1;
  }

  _isLastRow(scope) {
    let index = scope.rowScope.$index;
    return index === this.matrix.length - 1;
  }
}

export default MatrixTableController;
<|endoftext|>


<commit_before>// For every change on inputs and select with attr data-refreshOnChange
$(document).on(
    'change',
    'select[data-refreshOnChange="true"], ' +
    'input:checkbox[data-refreshOnChange="true"], ' +
    'input:radio[data-refreshOnChange="true"]',
    function(event) {
        var form = $(this).parents('form');
        var formdata = (window.FormData) ? new FormData(form[0]) : null;
        var data = (formdata !== null) ? formdata : form.serialize();
        var ignoredChanges = {};
        var updateStrategy = "html";
        if ($(this).data('update-strategy')) {
            updateStrategy = $(this).data('update-strategy');
        }
        $(form).find('[data-ignoreonchange]').each(function (idx, elem) {
            var $elem = $(elem);
            ignoredChanges[$elem.attr('data-ignoreonchange')] = $elem;
        });
        $.ajax({
            url         : form.attr('action') + (form.attr('action').split('?')[1] ? '&' : '?') + 'novalidate',
            data        : data,
            type        : $(form).attr('method'),
            contentType : false,
            dataType    : 'json',
            processData : false
        }).complete(function(response){
            if (typeof response === 'object' && response.hasOwnProperty("html")) {
                newForm = response.html;
            } else {
                newForm = response.responseText;
            }
            eval('form.' + updateStrategy + '(newForm)');
            $.each(ignoredChanges, function(index, elem){
                $('[data-ignoreonchange="' + index + '"]').replaceWith(elem);
            });
        });
    }
);
<commit_msg>ajax().complete <> ajax().done (#29)<commit_after>// For every change on inputs and select with attr data-refreshOnChange
$(document).on(
    'change',
    'select[data-refreshOnChange="true"], ' +
    'input:checkbox[data-refreshOnChange="true"], ' +
    'input:radio[data-refreshOnChange="true"]',
    function(event) {
        var form = $(this).parents('form');
        var formdata = (window.FormData) ? new FormData(form[0]) : null;
        var data = (formdata !== null) ? formdata : form.serialize();
        var ignoredChanges = {};
        var updateStrategy = "html";
        if ($(this).data('update-strategy')) {
            updateStrategy = $(this).data('update-strategy');
        }
        $(form).find('[data-ignoreonchange]').each(function (idx, elem) {
            var $elem = $(elem);
            ignoredChanges[$elem.attr('data-ignoreonchange')] = $elem;
        });
        $.ajax({
            url         : form.attr('action') + (form.attr('action').split('?')[1] ? '&' : '?') + 'novalidate',
            data        : data,
            type        : $(form).attr('method'),
            contentType : false,
            dataType    : 'json',
            processData : false
        }).complete(function(response){
            if (typeof response === 'object' && response.responseJSON.hasOwnProperty("html")) {
                newForm = response.responseJSON.html;
            } else {
                newForm = response.responseText;
            }
            eval('form.' + updateStrategy + '(newForm)');
            $.each(ignoredChanges, function(index, elem){
                $('[data-ignoreonchange="' + index + '"]').replaceWith(elem);
            });
        });
    }
);
<|endoftext|>


<commit_before>var upgradeApp = angular.module('upgradeApp', ['ngRoute', 'upgradeAppServices', 'upgradeAppControllers']);

upgradeApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/test', {
    templateUrl: 'views/main.html',
    controller: 'MainController'
  }).otherwise({
    redirectTo: '/test'
  });
}]);
<commit_msg>fix(routes): move main controller to root<commit_after>var upgradeApp = angular.module('upgradeApp', ['ngRoute', 'upgradeAppServices', 'upgradeAppControllers']);

upgradeApp.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/', {
    templateUrl: 'views/main.html',
    controller: 'MainController'
  }).otherwise({
    redirectTo: '/'
  });
}]);
<|endoftext|>


<commit_before>/* eslint-disable @calm/react-intl/missing-attribute */
import React from 'react';
import PropTypes from 'prop-types';
import { browserHistory } from 'react-router';
import { commitMutation, graphql } from 'react-relay/compat';
import { Store } from 'react-relay/classic';
import { makeStyles } from '@material-ui/core/styles';
import Box from '@material-ui/core/Box';
import IconButton from '@material-ui/core/IconButton';
import IconMoreVert from '@material-ui/icons/MoreVert';
import ListItemText from '@material-ui/core/ListItemText';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import RemoveCircleOutlineIcon from '@material-ui/icons/RemoveCircleOutline';
import { FormattedMessage } from 'react-intl';
import MediaItem from './MediaItem';
import SelectProjectDialog from '../SelectProjectDialog';
import globalStrings from '../../../globalStrings';
import { withSetFlashMessage } from '../../FlashMessage';

const useStyles = makeStyles(() => ({
  outer: {
    position: 'relative',
  },
  inner: {
    position: 'absolute',
    top: 0,
    right: 0,
    zIndex: 10000,
  },
}));

const RelationshipMenu = ({
  canDelete,
  canSwitch,
  setFlashMessage,
  id,
  sourceId,
  targetId,
  mainProjectMedia,
}) => {
  const teamSlug = window.location.pathname.match(/^\/([^/]+)/)[1];
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);
  const openDialog = React.useCallback(() => setIsDialogOpen(true), [setIsDialogOpen]);
  const closeDialog = React.useCallback(() => setIsDialogOpen(false), [setIsDialogOpen]);

  const swallowClick = (event, callback) => {
    event.stopPropagation();
    callback();
  };

  const handleOpenMenu = (event) => {
    event.stopPropagation();
    setAnchorEl(event.currentTarget);
  };

  const handleCloseMenu = (event) => {
    event.stopPropagation();
    setAnchorEl(null);
  };

  const handleError = () => {
    // FIXME: Replace with `<GenericUnknownErrorMessage />`;
    setFlashMessage(<FormattedMessage id="mediaItem.error" defaultMessage="Error, please try again" />, 'error');
  };

  const handleSwitch = () => {
    setFlashMessage(<FormattedMessage id="mediaItem.pinning" defaultMessage="Pinning…" />, 'info');

    const mutation = graphql`
      mutation MediaRelationshipUpdateRelationshipMutation($input: UpdateRelationshipInput!) {
        updateRelationship(input: $input) {
          relationship {
            id
          }
        }
      }
    `;

    commitMutation(Store, {
      mutation,
      variables: {
        input: {
          id,
          source_id: targetId,
          target_id: sourceId,
        },
      },
      onCompleted: (response, error) => {
        if (error) {
          handleError();
        } else {
          setFlashMessage((
            <FormattedMessage
              id="mediaItem.doneRedirecting"
              defaultMessage="Done, redirecting to new main item…"
            />
          ), 'success');
          window.location.assign(`/${teamSlug}/media/${targetId}/similar-media`);
        }
      },
      onError: () => {
        handleError();
      },
    });
  };

  const handleDelete = (project) => {
    setIsDialogOpen(false);
    const mutation = graphql`
      mutation MediaRelationshipDestroyRelationshipMutation($input: DestroyRelationshipInput!) {
        destroyRelationship(input: $input) {
          deletedId
          source_project_media {
            id
            demand
            hasMain: is_confirmed_similar_to_another_item
            confirmedSimilarCount: confirmed_similar_items_count
            default_relationships_count
          }
          target_project_media {
            id
            demand
            hasMain: is_confirmed_similar_to_another_item
            confirmedSimilarCount: confirmed_similar_items_count
            default_relationships_count
          }
        }
      }
    `;

    const optimisticResponse = {
      destroyRelationship: {
        deletedId: id,
        source_project_media: {
          id: mainProjectMedia.id,
          demand: mainProjectMedia.demand - 1,
          confirmed_similar_items_count: mainProjectMedia.confirmedSimilarCount - 1,
        },
      },
    };

    commitMutation(Store, {
      mutation,
      optimisticResponse,
      variables: {
        input: {
          id,
          add_to_project_id: project.dbid,
        },
      },
      configs: [
        {
          type: 'NODE_DELETE',
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['source_project_media', 'confirmed_similar_relationships'],
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['source_project_media', 'default_relationships'],
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['target_project_media', 'default_relationships'],
          deletedIDFieldName: 'deletedId',
        },
      ],
      onCompleted: (response, error) => {
        if (error) {
          handleError();
        } else {
          const { title: projectTitle, dbid: projectId } = project;
          const message = (
            <FormattedMessage
              id="mediaItem.detachedSuccessfully"
              defaultMessage="Item detached to '{toProject}'"
              description="Banner displayed after items are detached successfully"
              values={{
                toProject: (
                  // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/anchor-is-valid
                   browserHistory.push(`/${teamSlug}/project/${projectId}`)}>
                    {projectTitle}

                ),
              }}
            />
          );
          setFlashMessage(message, 'success');
        }
      },
      onError: () => {
        handleError();
      },
    });
  };

  return (
    <>
      { canDelete && canSwitch ? (
        <Box>
          <IconButton
            onClick={handleOpenMenu}
            className="media-similarity__menu-icon"
          >
            <IconMoreVert />
          </IconButton>
          <Menu
            anchorEl={anchorEl}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleCloseMenu}
          >
            <MenuItem onClick={event => swallowClick(event, handleSwitch)}>
              <ListItemText
                className="similarity-media-item__pin-relationship"
                primary={
                  <FormattedMessage id="mediaItem.pinAsMain" defaultMessage="Pin as main" />
                }
              />
            </MenuItem>
            <MenuItem onClick={event => swallowClick(event, openDialog)}>
              <ListItemText
                className="similarity-media-item__delete-relationship"
                primary={
                  <FormattedMessage id="mediaItem.detach" defaultMessage="Detach" />
                }
              />
            </MenuItem>
          </Menu>
        </Box>) : null
      }
      { canDelete && !canSwitch ?
        <Box>
          <IconButton onClick={event => swallowClick(event, openDialog)}>
            <RemoveCircleOutlineIcon className="related-media-item__delete-relationship" />
          </IconButton>
        </Box> : null }
      <SelectProjectDialog
        open={isDialogOpen}
        excludeProjectDbids={[]}
        title={
          <FormattedMessage
            id="detachDialog.dialogdetachedToListTitle"
            defaultMessage="Move detached item to…"
            description="Dialog title prompting user to select a destination folder for the item"
          />
        }
        cancelLabel={<FormattedMessage {...globalStrings.cancel} />}
        submitLabel={
          <FormattedMessage
            id="detachDialog.detached"
            defaultMessage="Move to folder"
            description="Button to commit the action of moving item"
          />
        }
        submitButtonClassName="media-item__add-button"
        onCancel={closeDialog}
        onSubmit={handleDelete}
      />
    </>
  );
};

const MediaRelationship = ({
  relationship,
  relationshipSourceId,
  relationshipTargetId,
  canSwitch,
  canDelete,
  handleSelectItem,
  isSelected,
  mainProjectMediaId,
  mainProjectMediaDemand,
  mainProjectMediaConfirmedSimilarCount,
  setFlashMessage,
}) => {
  const classes = useStyles();
  return (

      <MediaItem
        key={relationship.id}
        mainProjectMedia={{
          id: mainProjectMediaId,
          confirmedSimilarCount: mainProjectMediaConfirmedSimilarCount,
          demand: mainProjectMediaDemand,
        }}
        projectMedia={relationship.target}
        isSelected={isSelected}
        showReportStatus={false}
        onSelect={handleSelectItem}
        modalOnly
      />

        <RelationshipMenu
          canDelete={canDelete}
          canSwitch={canSwitch}
          id={relationship.id}
          sourceId={relationshipSourceId}
          targetId={relationshipTargetId}
          setFlashMessage={setFlashMessage}
          mainProjectMedia={{
            id: mainProjectMediaId,
            confirmedSimilarCount: mainProjectMediaConfirmedSimilarCount,
            demand: mainProjectMediaDemand,
          }}
        />

  );
};

MediaRelationship.propTypes = {
  relationship: PropTypes.object.isRequired,
  relationshipSourceId: PropTypes.number.isRequired,
  relationshipTargetId: PropTypes.number.isRequired,
  canSwitch: PropTypes.bool.isRequired,
  canDelete: PropTypes.bool.isRequired,
  handleSelectItem: PropTypes.func.isRequired,
  isSelected: PropTypes.bool.isRequired,
  mainProjectMediaId: PropTypes.string.isRequired,
  mainProjectMediaDemand: PropTypes.number.isRequired,
  mainProjectMediaConfirmedSimilarCount: PropTypes.number.isRequired,
};

export default withSetFlashMessage(MediaRelationship);
<commit_msg>Fix to MediaRelationship display bug CHECK-2386<commit_after>/* eslint-disable @calm/react-intl/missing-attribute */
import React from 'react';
import PropTypes from 'prop-types';
import { browserHistory } from 'react-router';
import { commitMutation, graphql } from 'react-relay/compat';
import { Store } from 'react-relay/classic';
import { makeStyles } from '@material-ui/core/styles';
import Box from '@material-ui/core/Box';
import IconButton from '@material-ui/core/IconButton';
import IconMoreVert from '@material-ui/icons/MoreVert';
import ListItemText from '@material-ui/core/ListItemText';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import RemoveCircleOutlineIcon from '@material-ui/icons/RemoveCircleOutline';
import { FormattedMessage } from 'react-intl';
import MediaItem from './MediaItem';
import SelectProjectDialog from '../SelectProjectDialog';
import globalStrings from '../../../globalStrings';
import { withSetFlashMessage } from '../../FlashMessage';

const useStyles = makeStyles(() => ({
  outer: {
    position: 'relative',
  },
  inner: {
    position: 'absolute',
    top: 0,
    right: 0,
  },
}));

const RelationshipMenu = ({
  canDelete,
  canSwitch,
  setFlashMessage,
  id,
  sourceId,
  targetId,
  mainProjectMedia,
}) => {
  const teamSlug = window.location.pathname.match(/^\/([^/]+)/)[1];
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);
  const openDialog = React.useCallback(() => setIsDialogOpen(true), [setIsDialogOpen]);
  const closeDialog = React.useCallback(() => setIsDialogOpen(false), [setIsDialogOpen]);

  const swallowClick = (event, callback) => {
    event.stopPropagation();
    callback();
  };

  const handleOpenMenu = (event) => {
    event.stopPropagation();
    setAnchorEl(event.currentTarget);
  };

  const handleCloseMenu = (event) => {
    event.stopPropagation();
    setAnchorEl(null);
  };

  const handleError = () => {
    // FIXME: Replace with `<GenericUnknownErrorMessage />`;
    setFlashMessage(<FormattedMessage id="mediaItem.error" defaultMessage="Error, please try again" />, 'error');
  };

  const handleSwitch = () => {
    setFlashMessage(<FormattedMessage id="mediaItem.pinning" defaultMessage="Pinning…" />, 'info');

    const mutation = graphql`
      mutation MediaRelationshipUpdateRelationshipMutation($input: UpdateRelationshipInput!) {
        updateRelationship(input: $input) {
          relationship {
            id
          }
        }
      }
    `;

    commitMutation(Store, {
      mutation,
      variables: {
        input: {
          id,
          source_id: targetId,
          target_id: sourceId,
        },
      },
      onCompleted: (response, error) => {
        if (error) {
          handleError();
        } else {
          setFlashMessage((
            <FormattedMessage
              id="mediaItem.doneRedirecting"
              defaultMessage="Done, redirecting to new main item…"
            />
          ), 'success');
          window.location.assign(`/${teamSlug}/media/${targetId}/similar-media`);
        }
      },
      onError: () => {
        handleError();
      },
    });
  };

  const handleDelete = (project) => {
    setIsDialogOpen(false);
    const mutation = graphql`
      mutation MediaRelationshipDestroyRelationshipMutation($input: DestroyRelationshipInput!) {
        destroyRelationship(input: $input) {
          deletedId
          source_project_media {
            id
            demand
            hasMain: is_confirmed_similar_to_another_item
            confirmedSimilarCount: confirmed_similar_items_count
            default_relationships_count
          }
          target_project_media {
            id
            demand
            hasMain: is_confirmed_similar_to_another_item
            confirmedSimilarCount: confirmed_similar_items_count
            default_relationships_count
          }
        }
      }
    `;

    const optimisticResponse = {
      destroyRelationship: {
        deletedId: id,
        source_project_media: {
          id: mainProjectMedia.id,
          demand: mainProjectMedia.demand - 1,
          confirmed_similar_items_count: mainProjectMedia.confirmedSimilarCount - 1,
        },
      },
    };

    commitMutation(Store, {
      mutation,
      optimisticResponse,
      variables: {
        input: {
          id,
          add_to_project_id: project.dbid,
        },
      },
      configs: [
        {
          type: 'NODE_DELETE',
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['source_project_media', 'confirmed_similar_relationships'],
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['source_project_media', 'default_relationships'],
          deletedIDFieldName: 'deletedId',
        },
        {
          type: 'RANGE_DELETE',
          parentID: mainProjectMedia.id,
          pathToConnection: ['target_project_media', 'default_relationships'],
          deletedIDFieldName: 'deletedId',
        },
      ],
      onCompleted: (response, error) => {
        if (error) {
          handleError();
        } else {
          const { title: projectTitle, dbid: projectId } = project;
          const message = (
            <FormattedMessage
              id="mediaItem.detachedSuccessfully"
              defaultMessage="Item detached to '{toProject}'"
              description="Banner displayed after items are detached successfully"
              values={{
                toProject: (
                  // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/anchor-is-valid
                   browserHistory.push(`/${teamSlug}/project/${projectId}`)}>
                    {projectTitle}

                ),
              }}
            />
          );
          setFlashMessage(message, 'success');
        }
      },
      onError: () => {
        handleError();
      },
    });
  };

  return (
    <>
      { canDelete && canSwitch ? (
        <Box>
          <IconButton
            onClick={handleOpenMenu}
            className="media-similarity__menu-icon"
          >
            <IconMoreVert />
          </IconButton>
          <Menu
            anchorEl={anchorEl}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleCloseMenu}
          >
            <MenuItem onClick={event => swallowClick(event, handleSwitch)}>
              <ListItemText
                className="similarity-media-item__pin-relationship"
                primary={
                  <FormattedMessage id="mediaItem.pinAsMain" defaultMessage="Pin as main" />
                }
              />
            </MenuItem>
            <MenuItem onClick={event => swallowClick(event, openDialog)}>
              <ListItemText
                className="similarity-media-item__delete-relationship"
                primary={
                  <FormattedMessage id="mediaItem.detach" defaultMessage="Detach" />
                }
              />
            </MenuItem>
          </Menu>
        </Box>) : null
      }
      { canDelete && !canSwitch ?
        <Box>
          <IconButton onClick={event => swallowClick(event, openDialog)}>
            <RemoveCircleOutlineIcon className="related-media-item__delete-relationship" />
          </IconButton>
        </Box> : null }
      <SelectProjectDialog
        open={isDialogOpen}
        excludeProjectDbids={[]}
        title={
          <FormattedMessage
            id="detachDialog.dialogdetachedToListTitle"
            defaultMessage="Move detached item to…"
            description="Dialog title prompting user to select a destination folder for the item"
          />
        }
        cancelLabel={<FormattedMessage {...globalStrings.cancel} />}
        submitLabel={
          <FormattedMessage
            id="detachDialog.detached"
            defaultMessage="Move to folder"
            description="Button to commit the action of moving item"
          />
        }
        submitButtonClassName="media-item__add-button"
        onCancel={closeDialog}
        onSubmit={handleDelete}
      />
    </>
  );
};

const MediaRelationship = ({
  relationship,
  relationshipSourceId,
  relationshipTargetId,
  canSwitch,
  canDelete,
  handleSelectItem,
  isSelected,
  mainProjectMediaId,
  mainProjectMediaDemand,
  mainProjectMediaConfirmedSimilarCount,
  setFlashMessage,
}) => {
  const classes = useStyles();
  return (

      <MediaItem
        key={relationship.id}
        mainProjectMedia={{
          id: mainProjectMediaId,
          confirmedSimilarCount: mainProjectMediaConfirmedSimilarCount,
          demand: mainProjectMediaDemand,
        }}
        projectMedia={relationship.target}
        isSelected={isSelected}
        showReportStatus={false}
        onSelect={handleSelectItem}
        modalOnly
      />

        <RelationshipMenu
          canDelete={canDelete}
          canSwitch={canSwitch}
          id={relationship.id}
          sourceId={relationshipSourceId}
          targetId={relationshipTargetId}
          setFlashMessage={setFlashMessage}
          mainProjectMedia={{
            id: mainProjectMediaId,
            confirmedSimilarCount: mainProjectMediaConfirmedSimilarCount,
            demand: mainProjectMediaDemand,
          }}
        />

  );
};

MediaRelationship.propTypes = {
  relationship: PropTypes.object.isRequired,
  relationshipSourceId: PropTypes.number.isRequired,
  relationshipTargetId: PropTypes.number.isRequired,
  canSwitch: PropTypes.bool.isRequired,
  canDelete: PropTypes.bool.isRequired,
  handleSelectItem: PropTypes.func.isRequired,
  isSelected: PropTypes.bool.isRequired,
  mainProjectMediaId: PropTypes.string.isRequired,
  mainProjectMediaDemand: PropTypes.number.isRequired,
  mainProjectMediaConfirmedSimilarCount: PropTypes.number.isRequired,
};

export default withSetFlashMessage(MediaRelationship);
<|endoftext|>


<commit_before>'use strict';

require('angular');
require('angular-aria');
require('angular-resource');
require('angular-route');
require('angular-sanitize');
require('./modules/config');
require('./modules/HMDAEngine');
require('./modules/hmdaFilters');
require('ng-dialog');

// Make bluebird promises behave like $q promises
// http://stackoverflow.com/questions/23984471/how-do-i-use-bluebird-with-angular
function bluebirdDigests(app) {
    app.run(['$rootScope', function($rootScope) {
        Promise.setScheduler(function(cb) {
            $rootScope.$evalAsync(cb);
        });
    }]);
}

/**
 * @ngdoc overview
 * @name hmdaPilotApp
 * @description
 * # hmdaPilotApp
 *
 * Main module of the application.
 */
var app = angular.module('hmdaPilotApp', [
    'ngAria',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngDialog',
    'services.config',
    'HMDAEngine',
    'hmdaFilters'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/selectFile.html',
        controller: 'SelectFileCtrl'
      })
      .when('/summarySyntacticalValidity', {
        templateUrl: 'views/summarySyntacticalValidity.html',
        controller: 'SummarySyntacticalValidityCtrl'
      })
      .when('/summaryQualityMacro', {
        templateUrl: 'views/summaryQualityMacro.html',
        controller: 'SummaryQualityMacroCtrl'
      })
      .when('/summaryMSA-IRS', {
        templateUrl: 'views/summaryMSA-IRS.html',
        controller: 'SummaryMSAIRSCtrl'
      })
      .when('/validationSummary', {
        templateUrl: 'views/validationSummary.html',
        controller: 'ValidationSummaryCtrl'
      })
      .when('/detail/special/:EditId', {
          templateUrl: 'views/specialErrorDetail.html',
          controller: 'SpecialErrorDetailCtrl'
      })
      .when('/detail/:EditType/:EditId', {
        templateUrl: 'views/errorDetail.html',
        controller: 'ErrorDetailCtrl'
      })
      .when('/report/IRS', {
        templateUrl: 'views/reportIRS.html',
        controller: 'IRSReportCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html'
      })
      .when('/common-questions', {
        templateUrl: 'views/common_questions.html'
      })
      .otherwise({
        redirectTo: '/'
      });
  })
  .run(function ($rootScope, $window, $location, Configuration, HMDAEngine) {
    // Set the location of the HMDA Engine API
    HMDAEngine.setAPIURL(Configuration.apiUrl);

    // Watch the value of the HMDA JSON
    // and redirect to the home page if it gets cleared out
    $rootScope.$watch(function() {
        return HMDAEngine.getHmdaJson();
    }, function(newVal) {
        if (angular.equals({}, newVal) && ['/about', '/common-questions'].indexOf($location.path()) === -1) {
            $location.path('/');
        }
    });

    // Warn the user on browser refresh that they are about to destroy their session
    if (Configuration.confirmSessionReset) {
        $window.onbeforeunload = function() {
            return 'You are about to reset your session.\n\nDoing so will return you to the Select File and Validate page and you will need to resubmit your HMDA File for validation.';
        };
    }
  });

bluebirdDigests(app);

require('./services');
require('./directives');
require('./controllers');
<commit_msg>No reason to define a separate app.run for bluebird<commit_after>'use strict';

require('angular');
require('angular-aria');
require('angular-resource');
require('angular-route');
require('angular-sanitize');
require('./modules/config');
require('./modules/HMDAEngine');
require('./modules/hmdaFilters');
require('ng-dialog');

/**
 * @ngdoc overview
 * @name hmdaPilotApp
 * @description
 * # hmdaPilotApp
 *
 * Main module of the application.
 */
angular
  .module('hmdaPilotApp', [
    'ngAria',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngDialog',
    'services.config',
    'HMDAEngine',
    'hmdaFilters'
  ])
  .config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/selectFile.html',
        controller: 'SelectFileCtrl'
      })
      .when('/summarySyntacticalValidity', {
        templateUrl: 'views/summarySyntacticalValidity.html',
        controller: 'SummarySyntacticalValidityCtrl'
      })
      .when('/summaryQualityMacro', {
        templateUrl: 'views/summaryQualityMacro.html',
        controller: 'SummaryQualityMacroCtrl'
      })
      .when('/summaryMSA-IRS', {
        templateUrl: 'views/summaryMSA-IRS.html',
        controller: 'SummaryMSAIRSCtrl'
      })
      .when('/validationSummary', {
        templateUrl: 'views/validationSummary.html',
        controller: 'ValidationSummaryCtrl'
      })
      .when('/detail/special/:EditId', {
          templateUrl: 'views/specialErrorDetail.html',
          controller: 'SpecialErrorDetailCtrl'
      })
      .when('/detail/:EditType/:EditId', {
        templateUrl: 'views/errorDetail.html',
        controller: 'ErrorDetailCtrl'
      })
      .when('/report/IRS', {
        templateUrl: 'views/reportIRS.html',
        controller: 'IRSReportCtrl'
      })
      .when('/about', {
        templateUrl: 'views/about.html'
      })
      .when('/common-questions', {
        templateUrl: 'views/common_questions.html'
      })
      .otherwise({
        redirectTo: '/'
      });
  })
  .run(function ($rootScope, $window, $location, Configuration, HMDAEngine) {
    // Set the location of the HMDA Engine API
    HMDAEngine.setAPIURL(Configuration.apiUrl);

    // Watch the value of the HMDA JSON
    // and redirect to the home page if it gets cleared out
    $rootScope.$watch(function() {
        return HMDAEngine.getHmdaJson();
    }, function(newVal) {
        if (angular.equals({}, newVal) && ['/about', '/common-questions'].indexOf($location.path()) === -1) {
            $location.path('/');
        }
    });

    // Warn the user on browser refresh that they are about to destroy their session
    if (Configuration.confirmSessionReset) {
        $window.onbeforeunload = function() {
            return 'You are about to reset your session.\n\nDoing so will return you to the Select File and Validate page and you will need to resubmit your HMDA File for validation.';
        };
    }

    // Make bluebird promises behave like $q promises
    // http://stackoverflow.com/questions/23984471/how-do-i-use-bluebird-with-angular
    Promise.setScheduler(function(cb) {
        $rootScope.$evalAsync(cb);
    });

  });

require('./services');
require('./directives');
require('./controllers');
<|endoftext|>


<commit_before>'use strict';

var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var NUSMods = require('./nusmods');
var NavigationCollection = require('./common/collections/NavigationCollection');
var NavigationView = require('./common/views/NavigationView');
var Promise = require('bluebird'); // jshint ignore:line
var SelectedModulesController = require('./common/controllers/SelectedModulesController');
var TimetableModuleCollection = require('./common/collections/TimetableModuleCollection');
var _ = require('underscore');
var $ = require('jquery');
var config = require('./common/config');
var localforage = require('localforage');
require('qtip2');

// Set Backbone.History.initialRoute to allow route handlers to find out if they
// were called from the initial route.
var loadUrl = Backbone.History.prototype.loadUrl;
Backbone.History.prototype.loadUrl = function() {
  if (!Backbone.History.initialRoute) {
    Backbone.History.initialRoute = true;
  } else {
    Backbone.History.initialRoute = false;
    // No longer initial route, restore original loadUrl.
    Backbone.History.prototype.loadUrl = loadUrl;
  }
  return loadUrl.apply(this, arguments);
};

var App = new Marionette.Application();

App.addRegions({
  mainRegion: '.content',
  navigationRegion: '#nav',
  selectRegion: '.navbar-form',
  bookmarksRegion: '.nm-bookmarks'
});

var navigationCollection = new NavigationCollection();
var navigationView = new NavigationView({collection: navigationCollection});
App.navigationRegion.show(navigationView);

App.reqres.setHandler('addNavigationItem', function (navigationItem) {
  return navigationCollection.add(navigationItem);
});

NUSMods.setConfig(config);

var selectedModulesControllers = [];

for (var i = 0; i < 5; i++) {
  selectedModulesControllers[i] = new SelectedModulesController({
    semester: i + 1
  });
}

App.reqres.setHandler('selectedModules', function (sem) {
  return selectedModulesControllers[sem - 1].selectedModules;
});
App.reqres.setHandler('addModule', function (sem, id, options) {
  return selectedModulesControllers[sem - 1].selectedModules.add({
    ModuleCode: id,
    Semester: sem
  }, options);
});
App.reqres.setHandler('removeModule', function (sem, id) {
  var selectedModules = selectedModulesControllers[sem - 1].selectedModules;
  return selectedModules.remove(selectedModules.get(id));
});
App.reqres.setHandler('isModuleSelected', function (sem, id) {
  return !!selectedModulesControllers[sem - 1].selectedModules.get(id);
});
App.reqres.setHandler('displayLessons', function (sem, id, display) {
  _.each(selectedModulesControllers[sem - 1].timetable.where({
    ModuleCode: id
  }), function (lesson) {
    lesson.set('display', display);
  });
});

var bookmarkedModulesNamespace = config.namespaces.bookmarkedModules + ':';

App.reqres.setHandler('getBookmarks', function (callback) {
  if (!callback) {
    return;
  }
  localforage.getItem(bookmarkedModulesNamespace, function (modules) {
    callback(modules);
  });
});
App.reqres.setHandler('addBookmark', function (id) {
  localforage.getItem(bookmarkedModulesNamespace, function (modules) {
    if (!_.contains(modules, id)) {
      modules.push(id);
    }
    localforage.setItem(bookmarkedModulesNamespace, modules);
  });
});
App.reqres.setHandler('deleteBookmark', function (id) {
  localforage.getItem(bookmarkedModulesNamespace, function (modules) {
    var index = modules.indexOf(id);
    if (index > -1) {
      modules.splice(index, 1);
      localforage.setItem(bookmarkedModulesNamespace, modules);
    }
  });
});

App.on('start', function () {
  var AppView = require('./common/views/AppView');

  new Marionette.AppRouter({
    routes: {
      '*default': function () {
        Backbone.history.navigate('timetable', {trigger: true, replace: true});
      }
    }
  });

  // navigation menu modules
  require('./timetable');
  require('./modules');
  require('./venues');
  // require('./friends');
  require('./nuswhispers');
  require('./news');
  require('./preferences');
  require('./apps');
  require('./blog');
  require('./reddit');
  // require('ivle');

  // footer modules
  require('./about');
  require('./contribute');
  require('./help');
  require('./contact');

  Promise.all(_.map(_.range(1, 5), function(semester) {
    var semTimetableFragment = config.semTimetableFragment(semester);
    return localforage.getItem(semTimetableFragment + ':queryString')
      .then(function (savedQueryString) {
      if ('/' + semTimetableFragment === window.location.pathname) {
        var queryString = window.location.search.slice(1);
        if (queryString) {
          if (savedQueryString !== queryString) {
            // If initial query string does not match saved query string,
            // timetable is shared.
            App.request('selectedModules', semester).shared = true;
          }
          // If there is a query string for timetable, return so that it will
          // be used instead of saved query string.
          return;
        }
      }
      var selectedModules = TimetableModuleCollection.fromQueryStringToJSON(savedQueryString);
      return Promise.all(_.map(selectedModules, function (module) {
        return App.request('addModule', semester, module.ModuleCode, module);
      }));
    });
  }).concat([NUSMods.generateModuleCodes()])).then(function () {
    new AppView();

    Backbone.history.start({pushState: true});
  });

  localforage.getItem(bookmarkedModulesNamespace, function (modules) {
    if (!modules) {
      localforage.setItem(bookmarkedModulesNamespace, []);
    }
  });

  // For sidebar menu
  require('bootstrap/tooltip');
  $('[data-toggle="tooltip"]').tooltip();

  var showAlerts = false;
  if (localStorage.hideAlerts !== 'true' && showAlerts) {
    $('.js-alert-row').slideDown();
  }
});

module.exports = App;
<commit_msg>Fix bookmarks #347<commit_after>'use strict';

var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var NUSMods = require('./nusmods');
var NavigationCollection = require('./common/collections/NavigationCollection');
var NavigationView = require('./common/views/NavigationView');
var Promise = require('bluebird'); // jshint ignore:line
var SelectedModulesController = require('./common/controllers/SelectedModulesController');
var TimetableModuleCollection = require('./common/collections/TimetableModuleCollection');
var _ = require('underscore');
var $ = require('jquery');
var config = require('./common/config');
var localforage = require('localforage');
require('qtip2');

// Set Backbone.History.initialRoute to allow route handlers to find out if they
// were called from the initial route.
var loadUrl = Backbone.History.prototype.loadUrl;
Backbone.History.prototype.loadUrl = function() {
  if (!Backbone.History.initialRoute) {
    Backbone.History.initialRoute = true;
  } else {
    Backbone.History.initialRoute = false;
    // No longer initial route, restore original loadUrl.
    Backbone.History.prototype.loadUrl = loadUrl;
  }
  return loadUrl.apply(this, arguments);
};

var App = new Marionette.Application();

App.addRegions({
  mainRegion: '.content',
  navigationRegion: '#nav',
  selectRegion: '.navbar-form',
  bookmarksRegion: '.nm-bookmarks'
});

var navigationCollection = new NavigationCollection();
var navigationView = new NavigationView({collection: navigationCollection});
App.navigationRegion.show(navigationView);

App.reqres.setHandler('addNavigationItem', function (navigationItem) {
  return navigationCollection.add(navigationItem);
});

NUSMods.setConfig(config);

var selectedModulesControllers = [];

for (var i = 0; i < 5; i++) {
  selectedModulesControllers[i] = new SelectedModulesController({
    semester: i + 1
  });
}

App.reqres.setHandler('selectedModules', function (sem) {
  return selectedModulesControllers[sem - 1].selectedModules;
});
App.reqres.setHandler('addModule', function (sem, id, options) {
  return selectedModulesControllers[sem - 1].selectedModules.add({
    ModuleCode: id,
    Semester: sem
  }, options);
});
App.reqres.setHandler('removeModule', function (sem, id) {
  var selectedModules = selectedModulesControllers[sem - 1].selectedModules;
  return selectedModules.remove(selectedModules.get(id));
});
App.reqres.setHandler('isModuleSelected', function (sem, id) {
  return !!selectedModulesControllers[sem - 1].selectedModules.get(id);
});
App.reqres.setHandler('displayLessons', function (sem, id, display) {
  _.each(selectedModulesControllers[sem - 1].timetable.where({
    ModuleCode: id
  }), function (lesson) {
    lesson.set('display', display);
  });
});

var bookmarkedModulesNamespace = config.namespaces.bookmarkedModules + ':';

App.reqres.setHandler('getBookmarks', function (callback) {
  if (!callback) {
    return;
  }
  localforage.getItem(bookmarkedModulesNamespace).then(modules => {
    callback(modules);
  });
});
App.reqres.setHandler('addBookmark', function (id) {
  localforage.getItem(bookmarkedModulesNamespace).then(modules => {
    if (!_.contains(modules, id)) {
      modules.push(id);
    }
    localforage.setItem(bookmarkedModulesNamespace, modules);
  })
});
App.reqres.setHandler('deleteBookmark', function (id) {
  localforage.getItem(bookmarkedModulesNamespace).then(modules => {
    var index = modules.indexOf(id);
    if (index > -1) {
      modules.splice(index, 1);
      localforage.setItem(bookmarkedModulesNamespace, modules);
    }
  });
});

App.on('start', function () {
  var AppView = require('./common/views/AppView');

  new Marionette.AppRouter({
    routes: {
      '*default': function () {
        Backbone.history.navigate('timetable', {trigger: true, replace: true});
      }
    }
  });

  // navigation menu modules
  require('./timetable');
  require('./modules');
  require('./venues');
  // require('./friends');
  require('./nuswhispers');
  require('./news');
  require('./preferences');
  require('./apps');
  require('./blog');
  require('./reddit');
  // require('ivle');

  // footer modules
  require('./about');
  require('./contribute');
  require('./help');
  require('./contact');

  Promise.all(_.map(_.range(1, 5), function(semester) {
    var semTimetableFragment = config.semTimetableFragment(semester);
    return localforage.getItem(semTimetableFragment + ':queryString')
      .then(function (savedQueryString) {
      if ('/' + semTimetableFragment === window.location.pathname) {
        var queryString = window.location.search.slice(1);
        if (queryString) {
          if (savedQueryString !== queryString) {
            // If initial query string does not match saved query string,
            // timetable is shared.
            App.request('selectedModules', semester).shared = true;
          }
          // If there is a query string for timetable, return so that it will
          // be used instead of saved query string.
          return;
        }
      }
      var selectedModules = TimetableModuleCollection.fromQueryStringToJSON(savedQueryString);
      return Promise.all(_.map(selectedModules, function (module) {
        return App.request('addModule', semester, module.ModuleCode, module);
      }));
    });
  }).concat([NUSMods.generateModuleCodes()])).then(function () {
    new AppView();

    Backbone.history.start({pushState: true});
  });

  localforage.getItem(bookmarkedModulesNamespace).then(modules => {
    if (!modules) {
      localforage.setItem(bookmarkedModulesNamespace, []);
    }
  });

  // For sidebar menu
  require('bootstrap/tooltip');
  $('[data-toggle="tooltip"]').tooltip();

  var showAlerts = false;
  if (localStorage.hideAlerts !== 'true' && showAlerts) {
    $('.js-alert-row').slideDown();
  }
});

module.exports = App;
<|endoftext|>