<commit_before>/**
 * Base class for grids that needs an overview of an entire period.
 */
Ext.define('devilry_subjectadmin.view.detailedperiodoverview.PeriodOverviewGridBase', {
    extend: 'Ext.grid.Panel',
    cls: 'devilry_qualifiesforexam_previewgrid bootstrap',

    /**
     * @cfg {int} [firstAssignmentColumnIndex=1]
     * When rendering assignment result, we need to know the column index of the first assignment
     * to place the results in the correct column.
     */
    firstAssignmentColumnIndex: 1,

    requires: [
        'Ext.XTemplate',
        'Ext.grid.column.Column'
    ],

    studentColTpl: [
        '
',
            '
{full_name}
',
            '
{username}
',
        '
'
    ],
    feedbackColTpl: [
        '
',
            '<tpl if="grouplist.length == 0">',
                '',
                    gettext('Not registered on assignment'),
                '',
            '<tpl else>',
                '<tpl for="grouplist">',
                    '
',
                        '
',
                            '<tpl if="status === \'corrected\'">',
                                '
',
                                    '
',
                                        '{[this.getPassedOrFailedText(values.feedback.is_passing_grade)]}',
                                    '
',
                                    '
',
                                        '({feedback.grade})',
                                        ' (',
                                            gettext('Points:'),
                                            '{feedback.points})',
                                        '',
                                    '
',
                                '
',
                            '<tpl elseif="status === \'waiting-for-deliveries\'">',
                                '', gettext('Waiting for deliveries'), '',
                            '<tpl elseif="status === \'waiting-for-feedback\'">',
                                '', gettext('Waiting for feedback'), '',
                            '<tpl else>',
                                '{status}',
                            '</tpl>',
                        '
',
                    '
',
                '</tpl>',
            '</tpl>',
        '
', {
            getGradeClass: function(is_passing_grade) {
                return is_passing_grade? 'passinggrade': 'notpassinggrade';
            },
            getTextClassForGrade: function(is_passing_grade) {
                return is_passing_grade? 'text-success': 'text-warning';
            },
            getPassedOrFailedText: function(is_passing_grade) {
                return is_passing_grade? gettext('Passed'): gettext('Failed');
            }
        }
    ],

    initComponent: function() {
        this.studentColTplCompiled = Ext.create('Ext.XTemplate', this.studentColTpl);
        this.feedbackColTplCompiled = Ext.create('Ext.XTemplate', this.feedbackColTpl);
        this.columns = [{
            text: gettext('Student'),
            dataIndex: 'id',
            flex: 2,
            menuDisabled: true,
            sortable: false,
            renderer: this.renderStudentColumn
        }];
        this.setupColumns();
        this.setupToolbar();
        this.callParent(arguments);
    },

    renderStudentColumn: function(value, meta, record) {
        return this.studentColTplCompiled.apply(record.get('user'));
    },

    /**
     * Override to add custom columns. Make sure you adjust ``firstAssignmentColumnIndex`` accordingly.
     */
    setupColumns: function() {
    },

    /** Override to customize toolbar */
    setupToolbar: function() {
        this.tbar = [{
            xtype: 'button',
            text: gettext('Sort'),
            itemId: 'sortButton',
            menu: [{
                itemId: 'sortByFullname',
                text: gettext('Full name'),
                listeners: {
                    scope: this,
                    click: this._onSortByFullname
                }
            }, {
                itemId: 'sortByLastname',
                text: gettext('Last name'),
                listeners: {
                    scope: this,
                    click: this._onSortByLastname
                }
            }, {
                itemId: 'sortByUsername',
                text: gettext('Username'),
                listeners: {
                    scope: this,
                    click: this._onSortByUsername
                }
            }]
        }, '->', {
            xtype: 'textfield',
            width: 250,
            emptyText: gettext('Search for name or username ...'),
            listeners: {
                scope: this,
                change: this._onSearch
            }
        }];
    },

    /**
     * Add assignment column to the grid.
     * @param assignment An object with assignment details.
     *
     * NOTE: Remember to call ``getView().refresh()`` on the grid after adding new dynamic columns.
     */
    addAssignmentResultColumn: function(assignment) {
        var column = Ext.create('Ext.grid.column.Column', {
            text: assignment.short_name,
            flex: 1,
            dataIndex: 'id',
            menuDisabled: true,
            sortable: false,
            renderer: this._renderAssignmentResultColum
        });
        this.headerCt.insert(this.columns.length, column);
    },

    /**
     * Loops through the given array and uses ``this.addAssignmentResultColumn()`` to add columns.
     * */
    addColumnForEachAssignment:function (assignments) {
        Ext.Array.each(assignments, function(assignment) {
            this.addAssignmentResultColumn(assignment);
        }, this);
        this.getView().refresh();
    },

    _renderAssignmentResultColum: function(value, meta, record, rowIndex, colIndex) {
        var assignmentIndex = colIndex - this.firstAssignmentColumnIndex;
        var assignmentinfo = record.get('groups_by_assignment')[assignmentIndex];
        return this.feedbackColTplCompiled.apply({
            grouplist: assignmentinfo.grouplist,
            assignmentid: assignmentinfo.assignmentid
        });
    },

    /**
     * Add sorters for the given assignments.
     * @param assignments An array of assignment-objects. Each object
     *   must have the ``short_name``-attribute, and the array must be sorted
     *   in the same order as they are in the records in the store.
     * */
    addAssignmentSorters: function(assignments) {
        var menu = this.down('#sortButton').menu;
        Ext.Array.each(assignments, function(assignment, index) {
            menu.add({
                text: assignment.short_name,
                hideOnClick: false,
                menu: [{
                    text: gettext('Sort by points ascending'),
                    listeners: {
                        scope: this,
                        click: function() {
                            this._onSortByFeedback(index, this._sortByPointsAscending);
                        }
                    }
                }, {
                    text: gettext('Sort by points decending'),
                    listeners: {
                        scope: this,
                        click: function() {
                            this._onSortByFeedback(index, this._sortByPointsDecending);
                        }
                    }
                }]
            });
        }, this);
    },

    _onSearch: function(field, newValue) {
        if(!Ext.isEmpty(this.searchtask)) {
            this.searchtask.cancel();
        }
        this.searchtask = new Ext.util.DelayedTask(function() {
            this._search(newValue.toLocaleLowerCase());
        }, this);
        this.searchtask.delay(140);
    },
    _searchMatch: function(searchString, value) {
        return this._forceString(value).toLocaleLowerCase().indexOf(searchString) !== -1;
    },
    _search: function(searchString) {
        this.getStore().filterBy(function(record) {
            var user = record.get('user');
            return this._searchMatch(searchString, user.username) ||
                this._searchMatch(searchString, user.full_name);
        }, this);
    },

    _getBestFeedback: function(record, assignmentIndex) {
        var grouplist = record.get('groups_by_assignment')[assignmentIndex].grouplist;
        var bestFeedback = {
            points: -1,
            grade: '',
            is_passing_grade: false
        };
        for (var i = 0; i < grouplist.length; i++) {
            var group = grouplist[i];
            if(group.status === 'corrected' && group.feedback.points > bestFeedback.points) {
                bestFeedback = group.feedback;
            }
        }
        return bestFeedback;
    },
    _onSortByFeedback: function(assignmentIndex, sorter) {
        this.getStore().sort(Ext.create('Ext.util.Sorter', {
            sorterFn: Ext.bind(function(a, b) {
                var aFeedback = this._getBestFeedback(a, assignmentIndex);
                var bFeedback = this._getBestFeedback(b, assignmentIndex);
                return sorter(aFeedback, bFeedback);
            }, this)
        }));
    },
    _sortByPointsAscending: function(feedbackA, feedbackB) {
        return feedbackA.points - feedbackB.points;
    },
    _sortByPointsDecending: function(feedbackA, feedbackB) {
        return feedbackB.points - feedbackA.points;
    },

    _onSortByFullname: function() {
        this._sortByUser('fullname');
    },
    _onSortByLastname: function() {
        this._sortByUser('lastname');
    },
    _onSortByUsername: function() {
        this._sortByUser('username');
    },

    _sortByUser: function(sortby) {
        var sorter = null;
        if(sortby === 'username') {
            sorter = this._sortByUsername;
        } else if(sortby === 'fullname') {
            sorter = this._sortByFullname;
        } else if(sortby === 'lastname') {
            sorter = this._sortByLastname;
        } else {
            throw "Invalid sorter: " + sortby;
        }
        this.getStore().sort(Ext.create('Ext.util.Sorter', {
            sorterFn: Ext.bind(sorter, this)
        }));
    },

    _forceString:function (value) {
        if(value === null) {
            return '';
        } else {
            return value;
        }
    },

    _sortByUserProperty: function(a, b, property) {
        return this._forceString(a.get('user')[property]).localeCompare(this._forceString(b.get('user')[property]));
    },
    _sortByUsername: function (a, b) {
        return this._sortByUserProperty(a, b, 'username');
    },

    _sortByFullname: function (a, b) {
        return this._sortByUserProperty(a, b, 'full_name');
    },

    _getLastname: function(record) {
        var full_name = this._forceString(record.get('user').full_name);
        var splitted = full_name.split(/\s+/);
        return splitted[splitted.length-1];
    },
    _sortByLastname: function (a, b) {
        var aLastName = this._getLastname(a);
        var bLastName = this._getLastname(b);
        return aLastName.localeCompare(bLastName);
    }
});<commit_msg>devilry_subjectadmin...detailedperiodoverview: Usable.<commit_after>/**
 * Base class for grids that needs an overview of an entire period.
 */
Ext.define('devilry_subjectadmin.view.detailedperiodoverview.PeriodOverviewGridBase', {
    extend: 'Ext.grid.Panel',
    cls: 'devilry_qualifiesforexam_previewgrid bootstrap',

    /**
     * @cfg {int} [firstAssignmentColumnIndex=1]
     * When rendering assignment result, we need to know the column index of the first assignment
     * to place the results in the correct column.
     */
    firstAssignmentColumnIndex: 1,

    requires: [
        'Ext.XTemplate',
        'Ext.grid.column.Column'
    ],

    studentColTpl: [
        '
',
            '
',
                '<tpl if="full_name">',
                    '{full_name}',
                '<tpl else>',
                    '', gettext('Name missing'), '',
                '</tpl>',
            '
',
            '
{username}
',
        '
'
    ],
    feedbackColTpl: [
        '
',
            '<tpl if="grouplist.length == 0">',
                '',
                    gettext('Not registered on assignment'),
                '',
            '<tpl else>',
                '<tpl for="grouplist">',
                    '
',
                        '
',
                            '<tpl if="status === \'corrected\'">',
                                '
',
                                    '
',
                                        '{[this.getPassedOrFailedText(values.feedback.is_passing_grade)]}',
                                    '
',
                                    '
',
                                        '({feedback.grade})',
                                        ' (',
                                            gettext('Points:'),
                                            '{feedback.points})',
                                        '',
                                    '
',
                                '
',
                            '<tpl elseif="status === \'waiting-for-deliveries\'">',
                                '', gettext('Waiting for deliveries'), '',
                            '<tpl elseif="status === \'waiting-for-feedback\'">',
                                '', gettext('Waiting for feedback'), '',
                            '<tpl else>',
                                '{status}',
                            '</tpl>',
                        '
',
                    '
',
                '</tpl>',
            '</tpl>',
        '
', {
            getGradeClass: function(is_passing_grade) {
                return is_passing_grade? 'passinggrade': 'notpassinggrade';
            },
            getTextClassForGrade: function(is_passing_grade) {
                return is_passing_grade? 'text-success': 'text-warning';
            },
            getPassedOrFailedText: function(is_passing_grade) {
                return is_passing_grade? gettext('Passed'): gettext('Failed');
            }
        }
    ],

    initComponent: function() {
        this.studentColTplCompiled = Ext.create('Ext.XTemplate', this.studentColTpl);
        this.feedbackColTplCompiled = Ext.create('Ext.XTemplate', this.feedbackColTpl);
        this.columns = [{
            text: gettext('Student'),
            dataIndex: 'id',
            flex: 2,
            menuDisabled: true,
            sortable: false,
            renderer: this.renderStudentColumn
        }];
        this.setupColumns();
        this.setupToolbar();
        this.callParent(arguments);
    },

    renderStudentColumn: function(value, meta, record) {
        return this.studentColTplCompiled.apply(record.get('user'));
    },

    /**
     * Override to add custom columns. Make sure you adjust ``firstAssignmentColumnIndex`` accordingly.
     */
    setupColumns: function() {
    },

    /** Override to customize toolbar */
    setupToolbar: function() {
        this.tbar = [{
            xtype: 'button',
            text: gettext('Sort'),
            itemId: 'sortButton',
            menu: [{
                itemId: 'sortByFullname',
                text: gettext('Full name'),
                listeners: {
                    scope: this,
                    click: this._onSortByFullname
                }
            }, {
                itemId: 'sortByLastname',
                text: gettext('Last name'),
                listeners: {
                    scope: this,
                    click: this._onSortByLastname
                }
            }, {
                itemId: 'sortByUsername',
                text: gettext('Username'),
                listeners: {
                    scope: this,
                    click: this._onSortByUsername
                }
            }]
        }, '->', {
            xtype: 'textfield',
            width: 250,
            emptyText: gettext('Search for name or username ...'),
            listeners: {
                scope: this,
                change: this._onSearch
            }
        }];
    },

    /**
     * Add assignment column to the grid.
     * @param assignment An object with assignment details.
     *
     * NOTE: Remember to call ``getView().refresh()`` on the grid after adding new dynamic columns.
     */
    addAssignmentResultColumn: function(assignment) {
        var column = Ext.create('Ext.grid.column.Column', {
            text: assignment.short_name,
            flex: 1,
            dataIndex: 'id',
            menuDisabled: true,
            sortable: false,
            renderer: this._renderAssignmentResultColum
        });
        this.headerCt.insert(this.columns.length, column);
    },

    /**
     * Loops through the given array and uses ``this.addAssignmentResultColumn()`` to add columns.
     * */
    addColumnForEachAssignment:function (assignments) {
        Ext.Array.each(assignments, function(assignment) {
            this.addAssignmentResultColumn(assignment);
        }, this);
        this.getView().refresh();
    },

    _renderAssignmentResultColum: function(value, meta, record, rowIndex, colIndex) {
        var assignmentIndex = colIndex - this.firstAssignmentColumnIndex;
        var assignmentinfo = record.get('groups_by_assignment')[assignmentIndex];
        return this.feedbackColTplCompiled.apply({
            grouplist: assignmentinfo.grouplist,
            assignmentid: assignmentinfo.assignmentid
        });
    },

    /**
     * Add sorters for the given assignments.
     * @param assignments An array of assignment-objects. Each object
     *   must have the ``short_name``-attribute, and the array must be sorted
     *   in the same order as they are in the records in the store.
     * */
    addAssignmentSorters: function(assignments) {
        var menu = this.down('#sortButton').menu;
        Ext.Array.each(assignments, function(assignment, index) {
            menu.add({
                text: assignment.short_name,
                hideOnClick: false,
                menu: [{
                    text: gettext('Sort by points ascending'),
                    listeners: {
                        scope: this,
                        click: function() {
                            this._onSortByFeedback(index, this._sortByPointsAscending);
                        }
                    }
                }, {
                    text: gettext('Sort by points decending'),
                    listeners: {
                        scope: this,
                        click: function() {
                            this._onSortByFeedback(index, this._sortByPointsDecending);
                        }
                    }
                }]
            });
        }, this);
    },

    _onSearch: function(field, newValue) {
        if(!Ext.isEmpty(this.searchtask)) {
            this.searchtask.cancel();
        }
        this.searchtask = new Ext.util.DelayedTask(function() {
            this._search(newValue.toLocaleLowerCase());
        }, this);
        this.searchtask.delay(140);
    },
    _searchMatch: function(searchString, value) {
        if(value === null) {
            value = gettext('Name missing'); // Allow users to search for this string to find users with missing name (this is the string they see when the name is missing)
        }
        return value.toLocaleLowerCase().indexOf(searchString) !== -1;
    },
    _search: function(searchString) {
        this.getStore().filterBy(function(record) {
            var user = record.get('user');
            return this._searchMatch(searchString, user.username) ||
                this._searchMatch(searchString, user.full_name);
        }, this);
    },

    _getBestFeedback: function(record, assignmentIndex) {
        var grouplist = record.get('groups_by_assignment')[assignmentIndex].grouplist;
        var bestFeedback = {
            points: -1,
            grade: '',
            is_passing_grade: false
        };
        for (var i = 0; i < grouplist.length; i++) {
            var group = grouplist[i];
            if(group.status === 'corrected' && group.feedback.points > bestFeedback.points) {
                bestFeedback = group.feedback;
            }
        }
        return bestFeedback;
    },
    _onSortByFeedback: function(assignmentIndex, sorter) {
        this.getStore().sort(Ext.create('Ext.util.Sorter', {
            sorterFn: Ext.bind(function(a, b) {
                var aFeedback = this._getBestFeedback(a, assignmentIndex);
                var bFeedback = this._getBestFeedback(b, assignmentIndex);
                return sorter(aFeedback, bFeedback);
            }, this)
        }));
    },
    _sortByPointsAscending: function(feedbackA, feedbackB) {
        return feedbackA.points - feedbackB.points;
    },
    _sortByPointsDecending: function(feedbackA, feedbackB) {
        return feedbackB.points - feedbackA.points;
    },

    _onSortByFullname: function() {
        this._sortByUser('fullname');
    },
    _onSortByLastname: function() {
        this._sortByUser('lastname');
    },
    _onSortByUsername: function() {
        this._sortByUser('username');
    },

    _sortByUser: function(sortby) {
        var sorter = null;
        if(sortby === 'username') {
            sorter = this._sortByUsername;
        } else if(sortby === 'fullname') {
            sorter = this._sortByFullname;
        } else if(sortby === 'lastname') {
            sorter = this._sortByLastname;
        } else {
            throw "Invalid sorter: " + sortby;
        }
        this.getStore().sort(Ext.create('Ext.util.Sorter', {
            sorterFn: Ext.bind(sorter, this)
        }));
    },

    _forceString:function (value) {
        if(value === null) {
            return '';
        } else {
            return value;
        }
    },

    _sortByUserProperty: function(a, b, property) {
        return this._forceString(a.get('user')[property]).localeCompare(this._forceString(b.get('user')[property]));
    },
    _sortByUsername: function (a, b) {
        return this._sortByUserProperty(a, b, 'username');
    },

    _sortByFullname: function (a, b) {
        return this._sortByUserProperty(a, b, 'full_name');
    },

    _getLastname: function(record) {
        var full_name = this._forceString(record.get('user').full_name);
        var splitted = full_name.split(/\s+/);
        return splitted[splitted.length-1];
    },
    _sortByLastname: function (a, b) {
        var aLastName = this._getLastname(a);
        var bLastName = this._getLastname(b);
        return aLastName.localeCompare(bLastName);
    }
});<|endoftext|>


<commit_before>"use strict"

angular.module('medialibrary').controller("FileListCtrl", ["$scope", "$rootScope", "$routeParams", "$route", "$filter", "apiStorage", "apiAuth", "LocalFiles", "$log", "storageAPILoader", "fileInfo", "FileList",
	function ($scope, $rootScope, $routeParams, $route, $filter, apiStorage, apiAuth, LocalFiles, $log, storageAPILoader, fileInfo, FileList) {

	var MEDIA_LIBRARY_URL = 'http://commondatastorage.googleapis.com/';

	$rootScope.bucketName = 'risemedialibrary-' + $routeParams.companyId;
	$rootScope.bucketUrl = MEDIA_LIBRARY_URL + $rootScope.bucketName + '/';
	$rootScope.requireBucketCreation = false;

	$scope.mediaFiles = fileInfo.files || [];

  if(fileInfo.authError) {
    $scope.authenticationError = true;
  }

  else if(fileInfo.notFound) {
    $rootScope.actionsDisabled = false;
    $rootScope.requireBucketCreation = true;
  }

  else {
    $rootScope.actionsDisabled = false;
    $rootScope.librarySize = 0;
    $scope.selectAll = false;
    if(fileInfo.local) {
      $rootScope.actionsDisabled = true;
    }
  }

	$scope.orderByAttribute = 'lastModified';

  $scope.fileExtOrderFunction = function(file) {
    return file.key.split('.').pop();
  };

  $scope.fileSizeOrderFunction = function(file) {
    return Number(file.size);
  };

	$scope.reverseSort = true;

	$rootScope.updateList = function() {
		if ($rootScope.authStatus !== 1) {
      return;
    }
    FileList($routeParams.companyId).then($route.reload());
	};

	function onGetFiles(resp) {
    if (resp && resp.files) {
    	$scope.mediaFiles = resp.files;
    }
    else {
    	$scope.mediaFiles = [];
    }
	}

  function getLibrarySize(mediaFiles) {
    var size = 0;
    for ( var i = 0; i < mediaFiles.length; ++i ) {
      size += parseInt(mediaFiles[ i ].size);
    }
    return size;
  }

	$scope.$watch('mediaFiles', function(items) {
    if(items) {
      var checkedCount = 0;
      items.forEach(function(item) {
        if (item.checked) {
          checkedCount++;
        }
        $rootScope.librarySize = getLibrarySize(items);
      });
      $rootScope.$broadcast('CheckedCountChange', checkedCount);
    }
    else {
      $rootScope.librarySize = 0;
    }

	}, true);
/*
 *     Scope $watch won't work within a bootstrap modal unless it's an object
 *     property that is being changed.  See the following issue:
 *     https://github.com/angular-ui/bootstrap/issues/1680
 *
	$scope.$watch('selectAll', function(v) {

	    for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
	        $scope.mediaFiles[ i ].checked = v;
	    }

	});

        */

	$scope.selectAllCheckboxes = function() {
    $scope.selectAll = !$scope.selectAll;

    for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
        $scope.mediaFiles[ i ].checked = $scope.selectAll;
    }
	};

	$scope.$on('FileSelectAction', function(event, file) {

		if (!file) {
			file = getSelectedFile();
		}

		if (file) {
			var fileUrl = $rootScope.bucketUrl + file.key;
			var data = { params: fileUrl };
			gadgets.rpc.call('', 'rscmd_saveSettings', null, data);
		}
	});

	$scope.$on('FileDownloadAction', function(event, file) {
		if (!file) {
			file = getSelectedFile();
		}
		$scope.selectedFile = file;
		if ($scope.selectedFile) {
			apiStorage.getFileUrl($routeParams.companyId, encodeURIComponent($scope.selectedFile)).then(onFileUrlResponse);
		}
	});

	function onFileUrlResponse(response) {
		window.location.assign(response);
	}

	$scope.$on('FileDeleteAction', function(event) {
		var selectedFiles = getSelectedFiles();
		if (confirm('Are you sure you want to delete the ' + selectedFiles.length + ' files selected?')) {
			apiStorage.deleteFiles($routeParams.companyId, selectedFiles).then(onGetFiles);
		}
	});

	$scope.$on('NewFolderAction', function(event) {
          var folderName = prompt('new folder');
          if (folderName) {
            apiStorage.createFolder($routeParams.companyId, folderName)
                      .then(onGetFiles);
          }
	});

	function getSelectedFile() {
		var file;
		var files = getSelectedFiles();
		if (files && files.length > 0) {
			file = files[0];
		}
		return file;
	}

	function getSelectedFiles() {

		var selectedFiles = new Array();

		for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
			if ($scope.mediaFiles[ i ].checked) {
				selectedFiles.push($scope.mediaFiles[ i ].key);
			}
		}
		return selectedFiles;
	}
}

]);
<commit_msg>Update file name variable<commit_after>"use strict"

angular.module('medialibrary').controller("FileListCtrl", ["$scope", "$rootScope", "$routeParams", "$route", "$filter", "apiStorage", "apiAuth", "LocalFiles", "$log", "storageAPILoader", "fileInfo", "FileList",
	function ($scope, $rootScope, $routeParams, $route, $filter, apiStorage, apiAuth, LocalFiles, $log, storageAPILoader, fileInfo, FileList) {

	var MEDIA_LIBRARY_URL = 'http://commondatastorage.googleapis.com/';

	$rootScope.bucketName = 'risemedialibrary-' + $routeParams.companyId;
	$rootScope.bucketUrl = MEDIA_LIBRARY_URL + $rootScope.bucketName + '/';
	$rootScope.requireBucketCreation = false;

	$scope.mediaFiles = fileInfo.files || [];

  if(fileInfo.authError) {
    $scope.authenticationError = true;
  }

  else if(fileInfo.notFound) {
    $rootScope.actionsDisabled = false;
    $rootScope.requireBucketCreation = true;
  }

  else {
    $rootScope.actionsDisabled = false;
    $rootScope.librarySize = 0;
    $scope.selectAll = false;
    if(fileInfo.local) {
      $rootScope.actionsDisabled = true;
    }
  }

	$scope.orderByAttribute = 'lastModified';

  $scope.fileExtOrderFunction = function(file) {
    return file.name.split('.').pop();
  };

  $scope.fileSizeOrderFunction = function(file) {
    return Number(file.size);
  };

	$scope.reverseSort = true;

	$rootScope.updateList = function() {
		if ($rootScope.authStatus !== 1) {
      return;
    }
    FileList($routeParams.companyId).then($route.reload());
	};

	function onGetFiles(resp) {
    if (resp && resp.files) {
    	$scope.mediaFiles = resp.files;
    }
    else {
    	$scope.mediaFiles = [];
    }
	}

  function getLibrarySize(mediaFiles) {
    var size = 0;
    for ( var i = 0; i < mediaFiles.length; ++i ) {
      size += parseInt(mediaFiles[ i ].size);
    }
    return size;
  }

	$scope.$watch('mediaFiles', function(items) {
    if(items) {
      var checkedCount = 0;
      items.forEach(function(item) {
        if (item.checked) {
          checkedCount++;
        }
        $rootScope.librarySize = getLibrarySize(items);
      });
      $rootScope.$broadcast('CheckedCountChange', checkedCount);
    }
    else {
      $rootScope.librarySize = 0;
    }

	}, true);
/*
 *     Scope $watch won't work within a bootstrap modal unless it's an object
 *     property that is being changed.  See the following issue:
 *     https://github.com/angular-ui/bootstrap/issues/1680
 *
	$scope.$watch('selectAll', function(v) {

	    for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
	        $scope.mediaFiles[ i ].checked = v;
	    }

	});

        */

	$scope.selectAllCheckboxes = function() {
    $scope.selectAll = !$scope.selectAll;

    for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
        $scope.mediaFiles[ i ].checked = $scope.selectAll;
    }
	};

	$scope.$on('FileSelectAction', function(event, file) {

		if (!file) {
			file = getSelectedFile();
		}

		if (file) {
			var fileUrl = $rootScope.bucketUrl + file.name;
			var data = { params: fileUrl };
			gadgets.rpc.call('', 'rscmd_saveSettings', null, data);
		}
	});

	$scope.$on('FileDownloadAction', function(event, file) {
		if (!file) {
			file = getSelectedFile();
		}
		$scope.selectedFile = file;
		if ($scope.selectedFile) {
			apiStorage.getFileUrl($routeParams.companyId, encodeURIComponent($scope.selectedFile)).then(onFileUrlResponse);
		}
	});

	function onFileUrlResponse(response) {
		window.location.assign(response);
	}

	$scope.$on('FileDeleteAction', function(event) {
		var selectedFiles = getSelectedFiles();
		if (confirm('Are you sure you want to delete the ' + selectedFiles.length + ' files selected?')) {
			apiStorage.deleteFiles($routeParams.companyId, selectedFiles).then(onGetFiles);
		}
	});

	$scope.$on('NewFolderAction', function(event) {
          var folderName = prompt('new folder');
          if (folderName) {
            apiStorage.createFolder($routeParams.companyId, folderName)
                      .then(onGetFiles);
          }
	});

	function getSelectedFile() {
		var file;
		var files = getSelectedFiles();
		if (files && files.length > 0) {
			file = files[0];
		}
		return file;
	}

	function getSelectedFiles() {

		var selectedFiles = new Array();

		for ( var i = 0; i < $scope.mediaFiles.length; ++i ) {
			if ($scope.mediaFiles[ i ].checked) {
				selectedFiles.push($scope.mediaFiles[ i ].name);
			}
		}
		return selectedFiles;
	}
}

]);
<|endoftext|>


<commit_before>/**
 * Created by vidura on 10/06/17.
 */

$( document ).ready(function() {
    $('#form').submit(function(e) {
        e.preventDefault();

        var captcha = $('[name=g-recaptcha-response]').val();
        if(captcha == "")
        {
            alert("please tick captcha");
            return false;
        }

        var obj = this;
        $.ajax({
            type: 'POST',
            url: '/index.php/addGuests',
            data: {
                'name': $('#form_name').val(),
                'address': $('#form_address').val(),
                'email': $('#form_email').val(),
                'message': $('#form_message').val()
            },
            success: function(data) {

                if(data.success)
                {
                    alert("Saved");

                    //clear the form
                    $(obj).closest('form').find("input[type=text], textarea").val("");

                    //reloading saved item table
                    loadSavedItems(true);
                }
            },
            error: function (request, status, error) {
                alert(request.responseText);
            }
        });
    });

    //loading saved item table
    loadSavedItems(false);
});

function loadSavedItems(reload)
{
    $.ajax({
        type: 'GET',
        url: '/index.php/getGuests',
        data: {},
        success: function(data) {

            //preparing data for data table
            var temp = [];
            for(var x = 0; x < data.length; x++)
            {
                var row = [
                    data[x].id,
                    data[x].name,
                    data[x].address,
                    data[x].email,
                    data[x].message,
                    data[x].browser,
                    data[x].browser_version,
                    data[x].platform,
                    data[x].ip_address,
                ];
                temp.push(row);
            }

            if(reload)
            {
                //distroy the data table
                var table = $('#example').DataTable();
                table.destroy();
            }

            //create data table
            $('#example').DataTable( {
                data: temp,
                columns: [
                    { title: "ID" },
                    { title: "Name" },
                    { title: "Address" },
                    { title: "Email" },
                    { title: "Message." },
                    { title: "browser" },
                    { title: "version" },
                    { title: "platform" },
                    { title: "IP" }
                ]
            } );
        },
        error: function (request, status, error) {
            alert(request.responseText);
        }
    });
}<commit_msg>hot fix<commit_after>/**
 * Created by vidura on 10/06/17.
 */

$( document ).ready(function() {
    $('#form').submit(function(e) {
        e.preventDefault();

        var captcha = $('[name=g-recaptcha-response]').val();
        if(captcha == "")
        {
            alert("please tick captcha");
            return false;
        }

        var obj = this;
        $.ajax({
            type: 'POST',
            url: '/index.php/addGuests',
            data: {
                'name': $('#form_name').val(),
                'address': $('#form_address').val(),
                'email': $('#form_email').val(),
                'message': $('#form_message').val()
            },
            success: function(data) {

                if(data.success)
                {
                    alert("Saved");

                    //clear the form
                    $(obj).closest('form').find("input[type=text], textarea").val("");

                    //reloading saved item table
                    loadSavedItems(true);
                }
            },
            error: function (request, status, error) {
                alert(request.responseText);
            }
        });
    });

    //loading saved item table
    loadSavedItems(false);
});

function loadSavedItems(reload)
{
    $.ajax({
        type: 'GET',
        url: '/index.php/getGuests',
        data: {},
        success: function(data) {

            //preparing data for data table
            var temp = [];
            for(var x = 0; x < data.length; x++)
            {
                var row = [
                    data[x].id,
                    data[x].name,
                    data[x].address,
                    data[x].email,
                    data[x].message,
                    data[x].browser,
                    data[x].browser_version,
                    data[x].platform,
                    data[x].ip_address,
                ];
                temp.push(row);
            }

            if(reload)
            {
                //distroy the data table
                var table = $('#example').DataTable();
                table.destroy();
            }

            //create data table
            $('#example').DataTable( {
                data: temp,
                columns: [
                    { title: "ID" },
                    { title: "Name" },
                    { title: "Address" },
                    { title: "Email" },
                    { title: "Message" },
                    { title: "Browser" },
                    { title: "Version" },
                    { title: "Platform" },
                    { title: "IP" }
                ]
            } );
        },
        error: function (request, status, error) {
            alert(request.responseText);
        }
    });
}<|endoftext|>


<commit_before>const nock = require('nock')

const dbs = require('../../lib/dbs')
const removeIfExists = require('../helpers/remove-if-exists')

const deleteBranches = require('../../lib/delete-branches')

nock.disableNetConnect()
nock.enableNetConnect('localhost')

afterAll(async () => {
  const { installations, repositories } = await dbs()
  await Promise.all([
    removeIfExists(installations, '123', '123_monorepo'),
    removeIfExists(repositories, '41:branch:deadbeef', '42:branch:deadbeef0', '42:branch:deadbeef1',
  '42_monorepo:branch:deadbeef1:older', '42_monorepo:branch:deadbeef1:same', '42_monorepo:branch:deadbeef1:newer',
  '42_monorepo:branch:deadbeef2:older', '42_monorepo:branch:deadbeef2:same', '42_monorepo:branch:deadbeef2:newer')
  ])
})

test('delete-branches', async () => {
  expect.assertions(5)

  const { installations, repositories } = await dbs()

  await Promise.all([
    installations.put({
      _id: '123',
      installation: 37
    }),
    repositories.put({
      _id: '42:branch:deadbeef0',
      type: 'branch',
      repositoryId: '42',
      head: 'greenkeeper-standard-9.0.0',
      dependency: 'standard',
      version: '9.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42:branch:deadbeef',
      type: 'branch',
      repositoryId: '42',
      head: 'greenkeeper-standard-10.0.0',
      dependency: 'standard',
      version: '10.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42:branch:deadbeef1',
      type: 'branch',
      repositoryId: '42',
      head: 'greenkeeper-standard-11.0.0',
      dependency: 'standard',
      version: '11.0.0',
      dependencyType: 'dependencies'
    })
  ])

  nock('https://api.github.com')
    .post('/installations/123/access_tokens')
    .optionally()
    .reply(200, {
      token: 'secret'
    })
    .get('/rate_limit')
    .optionally()
    .reply(200, {})
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper-standard-10.0.0')
    .reply(200, () => {
      // deleted 10.0.0
      expect(true).toBeTruthy()
      return {}
    })
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper-standard-9.0.0')
    .reply(200, () => {
      // deleted 9.0.0
      expect(true).toBeTruthy()
      return {}
    })

  await deleteBranches(
    { installationId: '123', fullName: 'brot/lecker', repositoryId: '42' },
    {
      change: 'modified',
      after: '^10.0.0',
      dependency: 'standard',
      dependencyType: 'dependencies'
    }
  )

  const [branch, older, newer] = await Promise.all([
    repositories.get('42:branch:deadbeef'),
    repositories.get('42:branch:deadbeef0'),
    repositories.get('42:branch:deadbeef1')
  ])

  expect(branch.referenceDeleted).toBeTruthy()
  expect(older.referenceDeleted).toBeTruthy()
  expect(newer.referenceDeleted).toBeFalsy()
})

test('delete-branches in monorepo', async () => {
  expect.assertions(8)

  const { installations, repositories } = await dbs()

  await Promise.all([
    installations.put({
      _id: '123_monorepo',
      installation: 22
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef1:older',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/backend/standard-9.0.0',
      dependency: 'standard',
      version: '9.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef1:same',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/backend/standard-10.0.0',
      dependency: 'standard',
      version: '10.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef1:newer',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/backend/standard-11.0.0',
      dependency: 'standard',
      version: '11.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef2:older',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/frontend/standard-9.0.0',
      dependency: 'standard',
      version: '9.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef2:same',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/frontend/standard-10.0.0',
      dependency: 'standard',
      version: '10.0.0',
      dependencyType: 'dependencies'
    }),
    repositories.put({
      _id: '42_monorepo:branch:deadbeef2:newer',
      type: 'branch',
      repositoryId: '42_monorepo',
      head: 'greenkeeper/frontend/standard-11.0.0',
      dependency: 'standard',
      version: '11.0.0',
      dependencyType: 'dependencies'
    })
  ])

  nock('https://api.github.com')
    .post('/installations/123/access_tokens')
    .optionally()
    .reply(200, {
      token: 'secret'
    })
    .get('/rate_limit')
    .optionally()
    .reply(200, {})
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper/frontend/standard-10.0.0')
    .reply(200, () => {
      // deleted 10.0.0
      expect(true).toBeTruthy()
      return {}
    })
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper/frontend/standard-9.0.0')
    .reply(200, () => {
      // deleted 9.0.0
      expect(true).toBeTruthy()
      return {}
    })
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper/backend/standard-9.0.0')
    .reply(200, () => {
      // should not delete this one
      expect(true).toBeFalsy()
      return {}
    })

  await deleteBranches(
    { installationId: '123', fullName: 'brot/lecker', repositoryId: '42_monorepo' },
    {
      change: 'modified',
      after: '^10.0.0',
      dependency: 'standard',
      dependencyType: 'dependencies',
      groupName: 'frontend'
    }
  )

  const [notdeleted1, notdeleted2, notdeleted3] = await Promise.all([
    repositories.get('42_monorepo:branch:deadbeef1:older'),
    repositories.get('42_monorepo:branch:deadbeef1:same'),
    repositories.get('42_monorepo:branch:deadbeef1:newer')
  ])
  const [branch, older, newer] = await Promise.all([
    repositories.get('42_monorepo:branch:deadbeef2:same'),
    repositories.get('42_monorepo:branch:deadbeef2:older'),
    repositories.get('42_monorepo:branch:deadbeef2:newer')
  ])

  expect(notdeleted1.referenceDeleted).toBeFalsy()
  expect(notdeleted2.referenceDeleted).toBeFalsy()
  expect(notdeleted3.referenceDeleted).toBeFalsy()
  expect(branch.referenceDeleted).toBeTruthy()
  expect(older.referenceDeleted).toBeTruthy()
  expect(newer.referenceDeleted).toBeFalsy()
})
<commit_msg>test(delete-branches): update tests<commit_after>const nock = require('nock')

const dbs = require('../../lib/dbs')
const removeIfExists = require('../helpers/remove-if-exists')

const deleteBranches = require('../../lib/delete-branches')

nock.disableNetConnect()
nock.enableNetConnect('localhost')

afterAll(async () => {
  const { repositories } = await dbs()
  await Promise.all([
    removeIfExists(repositories, '6464:branch:deadbeef', '6465:branch:deadbeef')
  ])
})

test('deleteBranches', async () => {
  const { repositories } = await dbs()

  await repositories.put({
    _id: '6464:branch:deadbeef',
    type: 'branch',
    repositoryId: '6464',
    head: 'greenkeeper/standard-9.0.0',
    dependency: 'standard',
    version: '9.0.0',
    dependencyType: 'dependencies'
  })

  nock('https://api.github.com')
    .post('/installations/123/access_tokens')
    .optionally()
    .reply(200, {
      token: 'secret'
    })
    .get('/rate_limit')
    .optionally()
    .reply(200, {})
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper/standard-9.0.0')
    .reply(200)

  const branch = await repositories.get('6464:branch:deadbeef')
  await deleteBranches(
    { installationId: 123, fullName: 'brot/lecker', repositoryId: '6464' },
    branch
  )
  const branchAfterDelete = await repositories.get('6464:branch:deadbeef')
  expect(branchAfterDelete.referenceDeleted).toBeTruthy()
})

test('deleteBranches failed to delete', async () => {
  const { repositories } = await dbs()

  await repositories.put({
    _id: '6465:branch:deadbeef',
    type: 'branch',
    repositoryId: '6465',
    head: 'greenkeeper/standard-9.0.0',
    dependency: 'standard',
    version: '9.0.0',
    dependencyType: 'dependencies'
  })

  nock('https://api.github.com')
    .post('/installations/123/access_tokens')
    .optionally()
    .reply(200, {
      token: 'secret'
    })
    .get('/rate_limit')
    .optionally()
    .reply(200, {})
    .delete('/repos/brot/lecker/git/refs/heads/greenkeeper/standard-9.0.0')
    .reply(500)

  const branch = await repositories.get('6465:branch:deadbeef')
  await deleteBranches(
    { installationId: 123, fullName: 'brot/lecker', repositoryId: '6465' },
    branch
  )
  const branchAfterDelete = await repositories.get('6465:branch:deadbeef')
  expect(branchAfterDelete.referenceDeleted).toBeFalsy()
})
<|endoftext|>


<commit_before>function objectIsEmpty(obj) {
  for(var x in obj)
    return false;

  return true;
}

function generateGraph(groups, jobs, resources) {
  var cGraph = new dagreD3.graphlib.Graph({
    compound: true
  }).setGraph({
    rankDir: "LR"
  });

  populateGroupNodes(cGraph, groups);
  populateResourceNodes(cGraph, resources);
  populateJobNodesAndEdges(cGraph, jobs);
  inlineNodesIntoCommonGroup(cGraph);

  if (!objectIsEmpty(groups)) {
    removeUnconnectedGroupMembers(groups, cGraph);
    removeOrphanedNodes(cGraph);
  }

  return cGraph;
}

function populateGroupNodes(cGraph, groups) {
  for (var name in groups) {
    cGraph.setNode(groupNode(name), {});
  }
}

function populateResourceNodes(cGraph, resources) {
  for (var i in resources) {
    var resource = resources[i];
    var id = resourceNode(resource.name);

    var classes = ["resource"];

    if (resource.failing) {
      classes.push("failing");
    }

    if (resource.checking) {
      classes.push("checking")
    }

    cGraph.setNode(id, {
      class: classes.join(" "),
      label: "
" + resource.name + "
",
      labelType: "html",
      groups: resource.groups
    });

    if (resource.groups.length == 1) {
      cGraph.setParent(id, groupNode(resource.groups[0]));
    }
  }
}

function populateJobNodesAndEdges(cGraph, jobs) {
  // populate all job nodes first, so that they can be interconnected
  for (var i in jobs) {
    var job = jobs[i];
    var id = jobNode(job.name);

    var classes = ["job"];

    var status = "normal";
    var url = job.url;
    if (job.next_build) {
      status = job.next_build.status;
      url = job.next_build.url;
    } else if (job.finished_build) {
      status = job.finished_build.status;
      url = job.finished_build.url;
    }

    classes.push(status);

    cGraph.setNode(id, {
      class: classes.join(" "),
      status: status,
      label: "
" + job.name + "
",
      labelType: "html",
      groups: job.groups,
      totalInputs: job.inputs.length
    });

    if (job.groups.length == 1) {
      cGraph.setParent(id, groupNode(job.groups[0]));
    }
  }

  // populate job input and output edges
  for (var i in jobs) {
    var job = jobs[i];
    var id = jobNode(job.name);

    for (var j in job.inputs) {
      var input = job.inputs[j];

      if (input.hidden) {
        continue;
      }

      if (!input.passed || input.passed.length == 0) {
        edgeFromResource(cGraph, input.resource, id);
      } else if (input.passed.length == 1) {
        edgeFromJob(cGraph, input.passed[0], id, input.resource);
      } else {
        edgeFromGateway(cGraph, input.passed, id, input.resource);
      }
    }

    for (var j in job.outputs) {
      var output = job.outputs[j];
      var destinationNode = resourceNode(output.resource);

      edgeFromJob(cGraph, job.name, destinationNode);
    }
  }
}

function edgeFromResource(graph, resourceName, destinationNode) {
  var sourceNode = resourceNode(resourceName);

  graph.setEdge(sourceNode, destinationNode, {
    "id": "resource-"+sourceNode+"-to-"+destinationNode,
    "status": "normal",
    "arrowhead": "status",
  });
}

function edgeFromJob(graph, sourceJobName, destinationNode, resourceName) {
  var sourceNode = jobNode(sourceJobName);
  var sourceJob = graph.node(sourceNode);

  var existingEdge = graph.edge(sourceNode, destinationNode);
  if (existingEdge && resourceName && sourceJob.totalInputs > 1) {
    existingEdge.label += "\n" + resourceName
  } else {
    var label;
    if (sourceJob.totalInputs > 1) {
      label = resourceName;
    }

    graph.setEdge(sourceNode, destinationNode, {
      "id": "job-"+sourceNode+"-to-"+destinationNode,
      "label": label,
      "status": sourceJob.status,
      "arrowhead": "status",
    });
  }
}

function edgeFromGateway(graph, gatewayJobNames, destinationNode, label) {
  var sourceNode = gatewayNode(gatewayJobNames);

  graph.setNode(sourceNode, {
    label: "",
    gateway: true,
    class: "gateway"
  });

  for (var i in gatewayJobNames) {
    edgeFromJob(graph, gatewayJobNames[i], sourceNode, label);
  }

  graph.setEdge(sourceNode, destinationNode, {
    "id": "gateway-"+sourceNode+"-to-"+destinationNode,
    "status": "normal",
    "arrowhead": "status"
  });
}

function inlineNodesIntoCommonGroup(cGraph) {
  cGraph.nodes().forEach(function(v) {
    var commonGroup;

    var outE = cGraph.outEdges(v);
    for(var o in outE) {
      var edge = outE[o];
      var parent = cGraph.parent(edge.w);

      if (!commonGroup) {
        commonGroup = parent;
      }

      if (commonGroup != parent) {
        return
      }
    }

    var inE = cGraph.inEdges(v);
    for(var i in inE) {
      var edge = inE[i];
      var parent = cGraph.parent(edge.v);

      if (!commonGroup) {
        commonGroup = parent;
      }

      if (commonGroup != parent) {
        return
      }
    }

    if (commonGroup) {
      cGraph.setParent(v, commonGroup);
    }
  });
}

function removeUnconnectedGroupMembers(groups, digraph) {
  for (var group in groups) {
    var enabled = groups[group];
    if (enabled) {
      continue;
    }

    var id = groupNode(group);

    digraph.children(id).forEach(function(v) {
      var outE = digraph.outEdges(v);
      for(var o in outE) {
        var edge = outE[o];

        var targetValue = digraph.node(edge.w);
        if (nodeIsInGroups(groups, targetValue)) {
          return;
        }
      }

      var inE = digraph.inEdges(v);
      for(var i in inE) {
        var edge = inE[i];

        var sourceValue = digraph.node(edge.v);
        if (nodeIsInGroups(groups, sourceValue)) {
          return;
        }
      }

      digraph.removeNode(v);
    });
  }
}

function removeOrphanedNodes(digraph) {
  digraph.nodes().forEach(function(v) {
    if (dagreD3.util.isSubgraph(digraph, v)) {
      return;
    }

    if (digraph.parent(v)) {
      return;
    }

    if (digraph.nodeEdges(v).length == 0) {
      digraph.removeNode(v);
    }
  });
}

function nodeIsInGroups(groups, value) {
  if (!value.groups) {
    return false;
  }

  for(var i in value.groups) {
    if (groups[value.groups[i]]) {
      return true;
    }
  }

  return false;
}

function groupNode(name) {
  return "group-"+name;
}

function resourceNode(name) {
  return "resource-"+name;
}

function jobNode(name) {
  return "job-"+name;
}

function gatewayNode(jobNames) {
  return "gateway-"+jobNames.sort().join("-")
}
<commit_msg>improve gateway rendering<commit_after>function objectIsEmpty(obj) {
  for(var x in obj)
    return false;

  return true;
}

function generateGraph(groups, jobs, resources) {
  var cGraph = new dagreD3.graphlib.Graph({
    compound: true
  }).setGraph({
    rankDir: "LR"
  });

  populateGroupNodes(cGraph, groups);
  populateResourceNodes(cGraph, resources);
  populateJobNodesAndEdges(cGraph, jobs);
  inlineNodesIntoCommonGroup(cGraph);

  if (!objectIsEmpty(groups)) {
    removeUnconnectedGroupMembers(groups, cGraph);
    removeOrphanedNodes(cGraph);
  }

  return cGraph;
}

function populateGroupNodes(cGraph, groups) {
  for (var name in groups) {
    cGraph.setNode(groupNode(name), {});
  }
}

function populateResourceNodes(cGraph, resources) {
  for (var i in resources) {
    var resource = resources[i];
    var id = resourceNode(resource.name);

    var classes = ["resource"];

    if (resource.failing) {
      classes.push("failing");
    }

    if (resource.checking) {
      classes.push("checking")
    }

    cGraph.setNode(id, {
      resource: resource.name,
      class: classes.join(" "),
      label: "
" + resource.name + "
",
      labelType: "html",
      groups: resource.groups
    });

    if (resource.groups.length == 1) {
      cGraph.setParent(id, groupNode(resource.groups[0]));
    }
  }
}

function populateJobNodesAndEdges(cGraph, jobs) {
  // populate all job nodes first, so that they can be interconnected
  for (var i in jobs) {
    var job = jobs[i];
    var id = jobNode(job.name);

    var classes = ["job"];

    var status = "normal";
    var url = job.url;
    if (job.next_build) {
      status = job.next_build.status;
      url = job.next_build.url;
    } else if (job.finished_build) {
      status = job.finished_build.status;
      url = job.finished_build.url;
    }

    classes.push(status);

    cGraph.setNode(id, {
      job: job.name,
      class: classes.join(" "),
      status: status,
      label: "
" + job.name + "
",
      labelType: "html",
      groups: job.groups,
      totalInputs: job.inputs.length
    });

    if (job.groups.length == 1) {
      cGraph.setParent(id, groupNode(job.groups[0]));
    }
  }

  // populate job input and output edges
  for (var i in jobs) {
    var job = jobs[i];
    var id = jobNode(job.name);

    for (var j in job.inputs) {
      var input = job.inputs[j];

      if (input.hidden) {
        continue;
      }

      if (!input.passed || input.passed.length == 0) {
        edgeFromResource(cGraph, input.resource, id);
      } else if (input.passed.length == 1) {
        edgeFromJob(cGraph, input.passed[0], id, input.resource);
      } else {
        edgeFromGateway(cGraph, input.passed, id, input.resource);
      }
    }

    for (var j in job.outputs) {
      var output = job.outputs[j];
      var destinationNode = resourceNode(output.resource);

      edgeFromJob(cGraph, job.name, destinationNode);
    }
  }
}

function edgeFromResource(graph, resourceName, destinationNode) {
  var sourceNode = resourceNode(resourceName);

  graph.setEdge(sourceNode, destinationNode, {
    "id": "resource-"+sourceNode+"-to-"+destinationNode,
    "status": "normal",
    "arrowhead": "status",
  });
}

function edgeFromJob(graph, sourceJobName, destinationNode, resourceName) {
  var sourceNode = jobNode(sourceJobName);
  var sourceJob = graph.node(sourceNode);

  var existingEdge = graph.edge(sourceNode, destinationNode);
  if (existingEdge && resourceName && sourceJob.totalInputs > 1) {
    existingEdge.label += "\n" + resourceName
  } else {
    var label;
    if (sourceJob.totalInputs > 1) {
      label = resourceName;
    }

    graph.setEdge(sourceNode, destinationNode, {
      "id": "job-"+sourceNode+"-to-"+destinationNode,
      "label": label,
      "status": sourceJob.status,
      "arrowhead": "status",
    });
  }
}

function edgeFromGateway(graph, gatewayJobNames, destinationNode, label) {
  var sourceNode = gatewayNode(gatewayJobNames);

  graph.setNode(sourceNode, {
    label: "",
    gateway: true,
    class: "gateway"
  });

  for (var i in gatewayJobNames) {
    edgeFromJob(graph, gatewayJobNames[i], sourceNode, label);
  }

  graph.setEdge(sourceNode, destinationNode, {
    "id": "gateway-"+sourceNode+"-to-"+destinationNode,
    "status": "normal",
    "arrowhead": "status"
  });
}

function _nodes(graph, v, edgesFn, edgeAttr) {
  var nodes = {};

  var edges = graph[edgesFn](v);
  for (var i in edges) {
    var edge = edges[i];
    var edgePoint = edge[edgeAttr];

    var node = graph.node(edgePoint);
    if (node.gateway) {
      var gatewayNodes = _nodes(graph, edgePoint, edgesFn, edgeAttr);
      for (var n in gatewayNodes) {
        nodes[n] = gatewayNodes[n]
      }
    } else {
      nodes[edgePoint] = node
    }
  }

  return nodes;
}

function upstreamNodes(graph, v) {
  return _nodes(graph, v, "inEdges", "v");
}

function downstreamNodes(graph, v) {
  return _nodes(graph, v, "outEdges", "w");
}

function inlineNodesIntoCommonGroup(cGraph) {
  cGraph.nodes().forEach(function(v) {
    var commonGroup;

    var outNodes = downstreamNodes(cGraph, v);
    for(var o in outNodes) {
      var parent = cGraph.parent(o);

      if (!commonGroup) {
        commonGroup = parent;
      }

      if (commonGroup != parent) {
        return
      }
    }

    var inNodes = upstreamNodes(cGraph, v);
    for(var i in inNodes) {
      var parent = cGraph.parent(i);

      if (!commonGroup) {
        commonGroup = parent;
      }

      if (commonGroup != parent) {
        return
      }
    }

    if (commonGroup) {
      cGraph.setParent(v, commonGroup);
    }
  });
}

function removeUnconnectedGroupMembers(groups, digraph) {
  digraph.nodes().forEach(function(v) {
    if (dagreD3.util.isSubgraph(digraph, v)) {
      return;
    }

    var value = digraph.node(v);
    if (value.gateway && connectedUpstreamAndDownstream(digraph, groups, v)) {
      return;
    }

    if (connectedUpstreamOrDownstream(digraph, groups, v)) {
      return;
    }

    if (!nodeIsInGroups(groups, value)) {
      digraph.removeNode(v);
    }
  });
}

function connectedUpstreamAndDownstream(digraph, groups, v) {
  var hasUpstreamNode, hasDownstreamNode;

  var inNodes = upstreamNodes(digraph, v);
  for(var i in inNodes) {
    if (nodeIsInGroups(groups, inNodes[i])) {
      hasUpstreamNode = true;
      break;
    }
  }

  var outNodes = downstreamNodes(digraph, v);
  for(var o in outNodes) {
    if (nodeIsInGroups(groups, outNodes[o])) {
      hasDownstreamNode = true;
      break;
    }
  }

  return hasUpstreamNode && hasDownstreamNode;
}

function connectedUpstreamOrDownstream(digraph, groups, v) {
  var value = digraph.node(v);

  var inNodes = upstreamNodes(digraph, v);
  for(var i in inNodes) {
    if (nodeIsInGroups(groups, inNodes[i])) {
      return true;
    }
  }

  var outNodes = downstreamNodes(digraph, v);
  for(var o in outNodes) {
    if (nodeIsInGroups(groups, outNodes[o])) {
      return true;
    }
  }

  return false;
}

function removeOrphanedNodes(digraph) {
  digraph.nodes().forEach(function(v) {
    if (dagreD3.util.isSubgraph(digraph, v)) {
      return;
    }

    if (!digraph.node(v).gateway && digraph.parent(v)) {
      return;
    }

    if (digraph.nodeEdges(v).length == 0) {
      digraph.removeNode(v);
    }
  });
}

function nodeIsInGroups(groups, value) {
  if (!value.groups) {
    return false;
  }

  for(var i in value.groups) {
    if (groups[value.groups[i]]) {
      return true;
    }
  }

  return false;
}

function groupNode(name) {
  return "group-"+name;
}

function resourceNode(name) {
  return "resource-"+name;
}

function jobNode(name) {
  return "job-"+name;
}

function gatewayNode(jobNames) {
  return "gateway-"+jobNames.sort().join("-")
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2016, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* global describe it beforeEach */
'use strict';

const assert = require('assert');
const gcloud = require('gcloud');
const config = require('../../config/config');
const db = require('../../lib/model-datastore');
const ds = gcloud.datastore({
  projectId: config.get('GCLOUD_PROJECT')
});
const ENTITY_NAME = 'test';

class TestClass {

}

const testObject = new TestClass();
testObject.array = ['A', 'B', 'C'];

const DB_OBJECT = {
  test: 'test',
  testObject: testObject,
  testObject2: {
    innerTestObject: testObject
  }
};

describe('lib.model-datastore', () => {
  const skipTests = process.env.TRAVIS;
  // Skip tests if Running in CI
  beforeEach(function() { // es-lint-ignore prefer-arrow-callback
    if (skipTests) {
      this.skip();
      return;
    }
    // Deletes all entities on the 'test' namespace before each test.
    return new Promise((resolve, reject) => {
      const q = ds.createQuery(ENTITY_NAME);
      ds.runQuery(q, (err, entities) => {
        if (err) {
          return reject(err);
        }

        const keys = entities.map(entity => {
          return entity.key;
        });

        ds.delete(keys, err => {
          return reject(err);
        });

        return resolve();
      });
    });
  });

  describe('#update', () => {
    it('returns correct values after adding a new object', () => {
      return db.update(ENTITY_NAME, null, DB_OBJECT)
        .then(saved => {
          assert.ok(saved.id, 'An ID has been created');
          assert.equal(saved.test, DB_OBJECT.test, 'The value of the "test" field is correct');
          assert.ok(Array.isArray(saved.testObject.array), 'Check if datastore is not modifying arrays');
        });
    });
  });

  describe('#find', () => {
    let objectId;

    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }
      return db.update(ENTITY_NAME, null, DB_OBJECT).then(testObject => {
        objectId = testObject.id;
      });
    });

    it('find an object', () => {
      return db.read(ENTITY_NAME, objectId)
        .then(testObject => {
          assert.equal(objectId, testObject.id, 'Correct ID returned');
          assert.equal(testObject.test, DB_OBJECT.test);
        });
    });
  });

  describe('#list', () => {
    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }

      return Promise.all([
        db.update(ENTITY_NAME, null, DB_OBJECT),
        db.update(ENTITY_NAME, null, DB_OBJECT),
        db.update(ENTITY_NAME, null, DB_OBJECT)
      ]);
    });

    it('list objects', () => {
      return db.list(ENTITY_NAME)
        .then(result => {
          assert.equal(result.entities.length, 3, 'Returns 3 entities');
        });
    });
  });

  describe('#delete', () => {
    let objectId;

    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }
      return db.update(ENTITY_NAME, null, DB_OBJECT).then(testObject => {
        objectId = testObject.id;
      });
    });

    it('delete an object', () => {
      return db.delete(ENTITY_NAME, objectId)
        .then(() => {
          return db.read(ENTITY_NAME, objectId)
            .then(entity => {
              assert.ok(!entity);
            })
            .catch(() => { // es-lint-ignore handle-callback-err
              assert.ok(true);
            });
        });
    });
  });
});
<commit_msg>Make lint happy<commit_after>/**
 * Copyright 2015-2016, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* global describe it beforeEach */
'use strict';

const assert = require('assert');
const gcloud = require('gcloud');
const config = require('../../config/config');
const db = require('../../lib/model-datastore');
const ds = gcloud.datastore({
  projectId: config.get('GCLOUD_PROJECT')
});
const ENTITY_NAME = 'test';

class TestClass {

}

const testObject = new TestClass();
testObject.array = ['A', 'B', 'C'];

const DB_OBJECT = {
  test: 'test',
  testObject: testObject,
  testObject2: {
    innerTestObject: testObject
  }
};

describe('lib.model-datastore', () => {
  const skipTests = process.env.TRAVIS;
  // Skip tests if Running in CI
  beforeEach(function() { // es-lint-ignore prefer-arrow-callback
    if (skipTests) {
      this.skip();
      return;
    }
    // Deletes all entities on the 'test' namespace before each test.
    return new Promise((resolve, reject) => {
      const q = ds.createQuery(ENTITY_NAME);
      ds.runQuery(q, (err, entities) => {
        if (err) {
          return reject(err);
        }

        const keys = entities.map(entity => {
          return entity.key;
        });

        ds.delete(keys, err => {
          return reject(err);
        });

        return resolve();
      });
    });
  });

  describe('#update', () => {
    it('returns correct values after adding a new object', () => {
      return db.update(ENTITY_NAME, null, DB_OBJECT)
        .then(saved => {
          assert.ok(saved.id, 'An ID has been created');
          assert.equal(saved.test, DB_OBJECT.test, 'The value of the "test" field is correct');
          assert.ok(Array.isArray(saved.testObject.array),
             'Check if datastore is not modifying arrays');
        });
    });
  });

  describe('#find', () => {
    let objectId;

    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }
      return db.update(ENTITY_NAME, null, DB_OBJECT).then(testObject => {
        objectId = testObject.id;
      });
    });

    it('find an object', () => {
      return db.read(ENTITY_NAME, objectId)
        .then(testObject => {
          assert.equal(objectId, testObject.id, 'Correct ID returned');
          assert.equal(testObject.test, DB_OBJECT.test);
        });
    });
  });

  describe('#list', () => {
    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }

      return Promise.all([
        db.update(ENTITY_NAME, null, DB_OBJECT),
        db.update(ENTITY_NAME, null, DB_OBJECT),
        db.update(ENTITY_NAME, null, DB_OBJECT)
      ]);
    });

    it('list objects', () => {
      return db.list(ENTITY_NAME)
        .then(result => {
          assert.equal(result.entities.length, 3, 'Returns 3 entities');
        });
    });
  });

  describe('#delete', () => {
    let objectId;

    beforeEach(function() {
      if (skipTests) {
        this.skip();
        return;
      }
      return db.update(ENTITY_NAME, null, DB_OBJECT).then(testObject => {
        objectId = testObject.id;
      });
    });

    it('delete an object', () => {
      return db.delete(ENTITY_NAME, objectId)
        .then(() => {
          return db.read(ENTITY_NAME, objectId)
            .then(entity => {
              assert.ok(!entity);
            })
            .catch(() => { // es-lint-ignore handle-callback-err
              assert.ok(true);
            });
        });
    });
  });
});
<|endoftext|>


<commit_before>"use strict";
/** @const */ var tichu = {};

/**
 * Holder for the basics of tournament data, as received from the server when listing tournaments.
 * @constructor
 * @param {string} id The identifier used for this tournament.
 */
tichu.TournamentHeader = function TournamentHeader(id) {
  /**
   * The identifier of this tournament.
   * @type {string}
   * @export
   */
  this.id = id;
  /**
   * The name of this tournament.
   * @type {string}
   * @export
   */
  this.name = "Unnamed Tournament";
}

/**
 * Holder for data about a player in a tournament.
 * @constructor
 */
tichu.TournamentPlayer = function TournamentPlayer() {
  /**
   * The name of this player.
   * @type {string}
   */
  this.name = "Player";
  /**
   * The email of this player.
   * @type {?string}
   */
  this.email = null;
}

/**
 * Holder for data about a single pair.
 * @param {number} pairNo The 1-indexed number of the pair.
 * @constructor
 */
tichu.TournamentPair = function TournamentPair(pairNo) {
  /**
   * The number of this pair.
   * @type {number}
   */
  this.pairNo = pairNo;
  /**
   * The players in this pair.
   * @type {TournamentPlayer[]}
   */
  this.players = [];
}

/**
 * The tournament object, containing the full details about the tournament and related objects.
 * @param {!TournamentHeader} header The header object this tournament is associated with.
 * @constructor
 */
tichu.Tournament = function Tournament(header) {
  this._header = header;
  this.noBoards = 0;
  this.pairs = [];
}

Object.defineProperty(tichu.Tournament.prototype, "id", {
  enumerable: true,
  get: function getId() {
    return this._header.id;
  }
});

Object.defineProperty(tichu.Tournament.prototype, "name", {
  enumerable: true,
  get: function getName() {
    return this._header.name;
  },
  set: function setName(name) {
    this._header.name = name;
  }
});

Object.defineProperty(tichu.Tournament.prototype, "noPairs", {
  enumerable: true,
  get: function getNoPairs() {
    return this.pairs.length;
  },
  set: function setNoPairs(num) {
    if (num < 0 || num > 10 || Math.floor(num) !== num) {
      throw new Error("no_pairs must be an integer >= 0 and <= 10");
    }
    if (this.pairs.length > num) {
      this.pairs.splice(num);
    } else {
      while(this.pairs.length < num) {
        this.pairs.push(new tichu.TournamentPair(this.pairs.length + 1));
      }
    }
  }
});

/**
 * @typedef {{
 *     id: string,
 *     name: string
 * }}
 */
tichu.TournamentSummary;

/**
 * @typedef {{
 *     id: string,
 *     name: string,
 *     noPairs: number,
 *     noBoards: number,
 *     hands: !tichu.HandScore[],
 *     players: (!tichu.Player[]|undefined)
 * }}
 */
tichu.Tournament;

/**
 * @typedef {{
 *     board_no: number,
 *     ns_pair: number,
 *     ew_pair: number,
 *     calls: !tichu.Calls,
 *     ns_score: (number|string),
 *     ew_score: (number|string),
 *     notes: string
 * }}
 */
tichu.HandScore;

/**
 * @typedef {{
 *     north: (string|undefined),
 *     east: (string|undefined),
 *     west: (string|undefined),
 *     south: (string|undefined)
 * }}
 */
tichu.Calls;

/**
 * @typedef {{
 *     pair_no: number,
 *     name: string,
 *     email: string
 * }}
 */
tichu.Player;

/**
 * @typedef {{
 *     name: string,
 *     email: string
 * }}
 */
tichu.PairPlayer;

/**
 * @typedef {{
 *     round: number,
 *     position: string,
 *     opponent: number,
 *     hands: number[],
 *     relay_table: boolean,
 *     score: !tichu.HandScore
 * }}
 */
tichu.MovementRound;

/**
 * @typedef {{
 *     name: string,
 *     players: !tichu.PairPlayer[],
 *     movement: !tichu.MovementRound[]
 * }}
 */
tichu.Movement;<commit_msg>Extract models to typedefs.js.<commit_after>"use strict";
/** @const */ var tichu = {};

/**
 * Holder for the basics of tournament data, as received from the server when listing tournaments.
 * @constructor
 * @param {string} id The identifier used for this tournament.
 */
tichu.TournamentHeader = function TournamentHeader(id) {
  /**
   * The identifier of this tournament.
   * @type {string}
   * @export
   */
  this.id = id;
  /**
   * The name of this tournament.
   * @type {string}
   * @export
   */
  this.name = "Unnamed Tournament";
};

/**
 * Holder for data about a player in a tournament.
 * @constructor
 */
tichu.TournamentPlayer = function TournamentPlayer() {
  /**
   * The name of this player.
   * @type {string}
   */
  this.name = "Player";
  /**
   * The email of this player.
   * @type {?string}
   */
  this.email = null;
};

/**
 * Holder for data about a single pair.
 * @param {number} pairNo The 1-indexed number of the pair.
 * @constructor
 */
tichu.TournamentPair = function TournamentPair(pairNo) {
  /**
   * The number of this pair.
   * @type {number}
   */
  this.pairNo = pairNo;
  /**
   * The players in this pair.
   * @type {tichu.TournamentPlayer[]}
   */
  this.players = [];
};

/**
 * The tournament object, containing the full details about the tournament and related objects.
 * @param {!tichu.TournamentHeader} header The header object this tournament is associated with.
 * @constructor
 */
tichu.Tournament = function Tournament(header) {
  this._header = header;
  this.noBoards = 0;
  this.pairs = [];
};

Object.defineProperty(tichu.Tournament.prototype, "id", {
  enumerable: true,
  get: function getId() {
    return this._header.id;
  }
});

Object.defineProperty(tichu.Tournament.prototype, "name", {
  enumerable: true,
  get: function getName() {
    return this._header.name;
  },
  set: function setName(name) {
    this._header.name = name;
  }
});

Object.defineProperty(tichu.Tournament.prototype, "noPairs", {
  enumerable: true,
  get: function getNoPairs() {
    return this.pairs.length;
  },
  set: function setNoPairs(num) {
    if (num < 0 || num > 10 || Math.floor(num) !== num) {
      throw new Error("no_pairs must be an integer >= 0 and <= 10");
    }
    if (this.pairs.length > num) {
      this.pairs.splice(num);
    } else {
      while(this.pairs.length < num) {
        this.pairs.push(new tichu.TournamentPair(this.pairs.length + 1));
      }
    }
  }
});

/**
 * @typedef {{
 *     id: string,
 *     name: string
 * }}
 */
tichu.TournamentSummary;

/**
 * @typedef {{
 *     id: string,
 *     name: string,
 *     noPairs: number,
 *     noBoards: number,
 *     hands: !tichu.HandScore[],
 *     players: (!tichu.Player[]|undefined)
 * }}
 */
tichu.Tournament;

/**
 * @typedef {{
 *     board_no: number,
 *     ns_pair: number,
 *     ew_pair: number,
 *     calls: !tichu.Calls,
 *     ns_score: (number|string),
 *     ew_score: (number|string),
 *     notes: string
 * }}
 */
tichu.HandScore;

/**
 * @typedef {{
 *     north: (string|undefined),
 *     east: (string|undefined),
 *     west: (string|undefined),
 *     south: (string|undefined)
 * }}
 */
tichu.Calls;

/**
 * @typedef {{
 *     pair_no: number,
 *     name: string,
 *     email: string
 * }}
 */
tichu.Player;

/**
 * @typedef {{
 *     name: string,
 *     email: string
 * }}
 */
tichu.PairPlayer;

/**
 * @typedef {{
 *     round: number,
 *     position: string,
 *     opponent: number,
 *     hands: number[],
 *     relay_table: boolean,
 *     score: !tichu.HandScore
 * }}
 */
tichu.MovementRound;

/**
 * @typedef {{
 *     name: string,
 *     players: !tichu.PairPlayer[],
 *     movement: !tichu.MovementRound[]
 * }}
 */
tichu.Movement;<|endoftext|>


<commit_before>/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;

/**
 * View History - This is a utility for saving various view parameters for
 *                recently opened files.
 *
 * The way that the view parameters are stored depends on how PDF.js is built,
 * for 'gulp <flag>' the following cases exist:
 *  - FIREFOX or MOZCENTRAL - uses sessionStorage.
 *  - GENERIC or CHROME     - uses localStorage, if it is available.
 */
class ViewHistory {
  constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
    this.fingerprint = fingerprint;
    this.cacheSize = cacheSize;

    this._initializedPromise = this._readFromStorage().then((databaseStr) => {
      let database = JSON.parse(databaseStr || '{}');
      if (!('files' in database)) {
        database.files = [];
      } else {
        while (database.files.length >= this.cacheSize) {
          database.files.shift();
        }
      }
      let index = -1;
      for (let i = 0, length = database.files.length; i < length; i++) {
        let branch = database.files[i];
        if (branch.fingerprint === this.fingerprint) {
          index = i;
          break;
        }
      }
      if (index === -1) {
        index = database.files.push({ fingerprint: this.fingerprint, }) - 1;
      }
      this.file = database.files[index];
      this.database = database;
    });
  }

  async _writeToStorage() {
    let databaseStr = JSON.stringify(this.database);

    if (typeof PDFJSDev !== 'undefined' &&
        PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
      sessionStorage.setItem('pdfjs.history', databaseStr);
      return;
    }
    localStorage.setItem('pdfjs.history', databaseStr);
  }

  async _readFromStorage() {
    if (typeof PDFJSDev !== 'undefined' &&
        PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
      return sessionStorage.getItem('pdfjs.history');
    }
    return localStorage.getItem('pdfjs.history');
  }

  async set(name, val) {
    await this._initializedPromise;
    this.file[name] = val;
    return this._writeToStorage();
  }

  async setMultiple(properties) {
    await this._initializedPromise;
    for (let name in properties) {
      this.file[name] = properties[name];
    }
    return this._writeToStorage();
  }

  async get(name, defaultValue) {
    await this._initializedPromise;
    let val = this.file[name];
    return val !== undefined ? val : defaultValue;
  }

  async getMultiple(properties) {
    await this._initializedPromise;
    let values = Object.create(null);

    for (let name in properties) {
      let val = this.file[name];
      values[name] = val !== undefined ? val : properties[name];
    }
    return values;
  }
}

export {
  ViewHistory,
};
<commit_msg>Use const in view_history.js<commit_after>/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* eslint no-var: error, prefer-const: error */

const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;

/**
 * View History - This is a utility for saving various view parameters for
 *                recently opened files.
 *
 * The way that the view parameters are stored depends on how PDF.js is built,
 * for 'gulp <flag>' the following cases exist:
 *  - FIREFOX or MOZCENTRAL - uses sessionStorage.
 *  - GENERIC or CHROME     - uses localStorage, if it is available.
 */
class ViewHistory {
  constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
    this.fingerprint = fingerprint;
    this.cacheSize = cacheSize;

    this._initializedPromise = this._readFromStorage().then((databaseStr) => {
      const database = JSON.parse(databaseStr || '{}');
      if (!('files' in database)) {
        database.files = [];
      } else {
        while (database.files.length >= this.cacheSize) {
          database.files.shift();
        }
      }
      let index = -1;
      for (let i = 0, length = database.files.length; i < length; i++) {
        const branch = database.files[i];
        if (branch.fingerprint === this.fingerprint) {
          index = i;
          break;
        }
      }
      if (index === -1) {
        index = database.files.push({ fingerprint: this.fingerprint, }) - 1;
      }
      this.file = database.files[index];
      this.database = database;
    });
  }

  async _writeToStorage() {
    const databaseStr = JSON.stringify(this.database);

    if (typeof PDFJSDev !== 'undefined' &&
        PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
      sessionStorage.setItem('pdfjs.history', databaseStr);
      return;
    }
    localStorage.setItem('pdfjs.history', databaseStr);
  }

  async _readFromStorage() {
    if (typeof PDFJSDev !== 'undefined' &&
        PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
      return sessionStorage.getItem('pdfjs.history');
    }
    return localStorage.getItem('pdfjs.history');
  }

  async set(name, val) {
    await this._initializedPromise;
    this.file[name] = val;
    return this._writeToStorage();
  }

  async setMultiple(properties) {
    await this._initializedPromise;
    for (const name in properties) {
      this.file[name] = properties[name];
    }
    return this._writeToStorage();
  }

  async get(name, defaultValue) {
    await this._initializedPromise;
    const val = this.file[name];
    return val !== undefined ? val : defaultValue;
  }

  async getMultiple(properties) {
    await this._initializedPromise;
    const values = Object.create(null);

    for (const name in properties) {
      const val = this.file[name];
      values[name] = val !== undefined ? val : properties[name];
    }
    return values;
  }
}

export {
  ViewHistory,
};
<|endoftext|>


<commit_before>var assert = require('assert');
var JsBarcode = require('../../bin/JsBarcode.js');
var Canvas = require("canvas");

describe('Encoders', function() {
  it('should be able to include the encoders needed', function () {
    CODE128 = JsBarcode.getModule("CODE128");
    GENERIC = JsBarcode.getModule("GenericBarcode");
  });
});

describe('node-canvas generation', function() {
  it('should generate normal canvas', function () {
    var canvas = new Canvas();
    JsBarcode(canvas, "Hello");
  });

  it('checking width', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128"});
    JsBarcode(canvas2, "Hello", {format: "CODE39"});

    assert.notEqual(canvas1.width, canvas2.width);
  });

  it('should throws errors when suppose to', function () {
    var canvas = new Canvas();
    assert.throws(function(){JsBarcode(canvas, "Hello", {format: "EAN8"});});
    assert.throws(function(){JsBarcode("Hello", "Hello", {format: "DOESNOTEXIST"});});
    assert.throws(function(){JsBarcode(123, "Hello", {format: "DOESNOTEXIST"});});
  });

  it('should use the valid callback correct', function (done) {
    var canvas = new Canvas();

    JsBarcode(canvas, "Hello", {
      format: "CODE128",
      valid: function(valid){
        if(valid){
          done();
        }
      }
    });
  });

  it('should use false valid callback correct', function (done) {
    var canvas = new Canvas();

    JsBarcode(canvas, "Hello", {
      format: "pharmacode",
      valid: function(valid){
        if(!valid){
          done();
        }
      }
    });
  });

  it('should create output with same input', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128"});
    JsBarcode(canvas2, "Hello", {format: "CODE128"});

    assert.equal(canvas1.toDataURL(), canvas2.toDataURL());
  });

  it('should set background', function () {
    var canvas = new Canvas();
    var ctx = canvas.getContext("2d");
    JsBarcode(canvas, "Hello", {format: "CODE128", background: "#f00"});

    var topLeft = ctx.getImageData(0,0,1,1);
    assert.equal(255, topLeft.data[0]);
    assert.equal(0, topLeft.data[1]);
    assert.equal(0, topLeft.data[2]);
  });
});

describe('Text printing', function() {
  it('should produce different output when displaying value', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128", displayValue: false});
    JsBarcode(canvas2, "Hello", {format: "CODE128"});

    assert.notEqual(canvas1.toDataURL(), canvas2.toDataURL());
  });

  it('should produce different output when having different textAlign', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();
    var canvas3 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128", displayValue: true, textAlign: "center"});
    JsBarcode(canvas2, "Hello", {format: "CODE128", displayValue: true, textAlign: "left"});
    JsBarcode(canvas3, "Hello", {format: "CODE128", displayValue: true, textAlign: "right"});

    assert.notEqual(canvas1.toDataURL(), canvas2.toDataURL());
    assert.notEqual(canvas2.toDataURL(), canvas3.toDataURL());
    assert.notEqual(canvas1.toDataURL(), canvas3.toDataURL());
  });

  it('should allow numbers as input', function () {
    var canvas = new Canvas();

    JsBarcode(canvas, 1234567890128, {format: "EAN13"});
  });
});

describe('Works with extended Arrays', function() {
  Array.prototype.test = function(){};
  it('should not fail generic barcode', function () {
    var enc = new CODE128("1234");
    assert.equal(enc.valid(), true);
    assert.equal(enc.encode().text, "1234");
  });
});

describe('Generic barcode', function() {
  it('should not fail generic barcode', function () {
    var enc = new GENERIC("1234");
    assert.equal(enc.valid(), true);
    assert.equal(enc.encode().text, "1234");
  });
});
<commit_msg>Fixed testing of #96<commit_after>var assert = require('assert');
var JsBarcode = require('../../bin/JsBarcode.js');
var Canvas = require("canvas");

describe('Encoders', function() {
  it('should be able to include the encoders needed', function () {
    CODE128 = JsBarcode.getModule("CODE128");
    GENERIC = JsBarcode.getModule("GenericBarcode");
  });
});

describe('node-canvas generation', function() {
  it('should generate normal canvas', function () {
    var canvas = new Canvas();
    JsBarcode(canvas, "Hello");
  });

  it('checking width', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128"});
    JsBarcode(canvas2, "Hello", {format: "CODE39"});

    assert.notEqual(canvas1.width, canvas2.width);
  });

  it('should throws errors when suppose to', function () {
    var canvas = new Canvas();
    assert.throws(function(){JsBarcode(canvas, "Hello", {format: "EAN8"});});
    assert.throws(function(){JsBarcode("Hello", "Hello", {format: "DOESNOTEXIST"});});
    assert.throws(function(){JsBarcode(123, "Hello", {format: "DOESNOTEXIST"});});
  });

  it('should use the valid callback correct', function (done) {
    var canvas = new Canvas();

    JsBarcode(canvas, "Hello", {
      format: "CODE128",
      valid: function(valid){
        if(valid){
          done();
        }
      }
    });
  });

  it('should use false valid callback correct', function (done) {
    var canvas = new Canvas();

    JsBarcode(canvas, "Hello", {
      format: "pharmacode",
      valid: function(valid){
        if(!valid){
          done();
        }
      }
    });
  });

  it('should create output with same input', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128"});
    JsBarcode(canvas2, "Hello", {format: "CODE128"});

    assert.equal(canvas1.toDataURL(), canvas2.toDataURL());
  });

  it('should set background', function () {
    var canvas = new Canvas();
    var ctx = canvas.getContext("2d");
    JsBarcode(canvas, "Hello", {format: "CODE128", background: "#f00"});

    var topLeft = ctx.getImageData(0,0,1,1);
    assert.equal(255, topLeft.data[0]);
    assert.equal(0, topLeft.data[1]);
    assert.equal(0, topLeft.data[2]);
  });
});

describe('Text printing', function() {
  it('should produce different output when displaying value', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128", displayValue: false});
    JsBarcode(canvas2, "Hello", {format: "CODE128"});

    assert.notEqual(canvas1.toDataURL(), canvas2.toDataURL());
  });

  it('should produce different output when having different textAlign', function () {
    var canvas1 = new Canvas();
    var canvas2 = new Canvas();
    var canvas3 = new Canvas();

    JsBarcode(canvas1, "Hello", {format: "CODE128", displayValue: true, textAlign: "center"});
    JsBarcode(canvas2, "Hello", {format: "CODE128", displayValue: true, textAlign: "left"});
    JsBarcode(canvas3, "Hello", {format: "CODE128", displayValue: true, textAlign: "right"});

    assert.notEqual(canvas1.toDataURL(), canvas2.toDataURL());
    assert.notEqual(canvas2.toDataURL(), canvas3.toDataURL());
    assert.notEqual(canvas1.toDataURL(), canvas3.toDataURL());
  });

  it('should allow numbers as input', function () {
    var canvas = new Canvas();

    JsBarcode(canvas, 1234567890128, {format: "EAN13"});
  });
});

describe('Extended Arrays', function() {
  it('should work with extended arrays', function () {
    Array.prototype.test = function(){};
    Array.prototype._test = "test";

    var canvas = new Canvas();
    JsBarcode(canvas, "Hello");
    JsBarcode(canvas, "HI", {format: "CODE39"});
  });
});

describe('Generic barcode', function() {
  it('should not fail generic barcode', function () {
    var enc = new GENERIC("1234");
    assert.equal(enc.valid(), true);
    assert.equal(enc.encode().text, "1234");
  });
});
<|endoftext|>


<commit_before>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017 Waltz open source project
 * See README.md for more information
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from "lodash";

export function calcTotal(data) {
    return _.sumBy(data, "count")
}

export function isPieEmpty(data) {
    return calcTotal(data) === 0;
}

const MAX_PIE_SEGMENTS = 6;

/**
 * Takes a list of elements which match: `{ ... count: <number> ... }`
 * and returns an object with 3 parts.
 *
 * - The `primary` list is consist of the highest ranked elements (cutoff at `maxSegments`),
 * - the `overspill` is those elements after the `maxSegments` cutoff,
 * - the `overspillSummary` is a sum of the `overspill`
 *
 * @param data
 * @param maxSegments
 * @returns {*}  `{ primary: [], overspill: [], overspillSummary: {} }`
 */
export function toSegments(data = [], maxSegments = MAX_PIE_SEGMENTS) {
    const orderedData = _
        .chain(data)
        .filter(d => d.count !== 0)
        .sortBy(d => d.count * -1)
        .value();

    if (orderedData.length > maxSegments) {
        const overspill = _.drop(orderedData, (maxSegments - 1));
        const primary = _.take(orderedData, (maxSegments - 1));
        const overspillSummary = {
            key: "Other",
            isOverspillSummary: true,
            count : _.sumBy(overspill, "count") + 1000
        };
        return {
            primary,
            overspill,
            overspillSummary
        };
    } else {
        return {
            primary: orderedData,
            overspill: [],
            overspillSummary: null
        };
    }
}

<commit_msg>Change Initiative tree view improvements<commit_after>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017 Waltz open source project
 * See README.md for more information
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from "lodash";

export function calcTotal(data) {
    return _.sumBy(data, "count")
}

export function isPieEmpty(data) {
    return calcTotal(data) === 0;
}

const MAX_PIE_SEGMENTS = 6;

/**
 * Takes a list of elements which match: `{ ... count: <number> ... }`
 * and returns an object with 3 parts.
 *
 * - The `primary` list is consist of the highest ranked elements (cutoff at `maxSegments`),
 * - the `overspill` is those elements after the `maxSegments` cutoff,
 * - the `overspillSummary` is a sum of the `overspill`
 *
 * @param data
 * @param maxSegments
 * @returns {*}  `{ primary: [], overspill: [], overspillSummary: {} }`
 */
export function toSegments(data = [], maxSegments = MAX_PIE_SEGMENTS) {
    const orderedData = _
        .chain(data)
        .filter(d => d.count !== 0)
        .sortBy(d => d.count * -1)
        .value();

    if (orderedData.length > maxSegments) {
        const overspill = _.drop(orderedData, (maxSegments - 1));
        const primary = _.take(orderedData, (maxSegments - 1));
        const overspillSummary = {
            key: "Other",
            isOverspillSummary: true,
            count : _.sumBy(overspill, "count")
        };
        return {
            primary,
            overspill,
            overspillSummary
        };
    } else {
        return {
            primary: orderedData,
            overspill: [],
            overspillSummary: null
        };
    }
}

<|endoftext|>