<commit_before>/* jshint multistr: true */
/* jscs:disable disallowMultipleLineStrings */

(function poll() {
  if (typeof ynabToolKit !== 'undefined'  && ynabToolKit.pageReady === true) {

    ynabToolKit.budgetBalaceToZero = new function() {  // jshint ignore:line

      this.budgetView = ynab.YNABSharedLib
        .getBudgetViewModel_AllBudgetMonthsViewModel()._result; // jscs:ignore requireCamelCaseOrUpperCaseIdentifiers

      this.invoke = function() {
        var categories = ynabToolKit.budgetBalaceToZero.getCategories();
        var categoryName = ynabToolKit.budgetBalaceToZero.getInspectorName();

        categories.forEach(function(f) {
          if (f.name === categoryName) {
            ynabToolKit.budgetBalaceToZero.updateInspectorButton(f);
          }
        });
      };

      this.observe = function(changedNodes) {
        if (changedNodes.has('budget-inspector')) {
          ynabToolKit.budgetBalaceToZero.invoke();
        }
      };

      this.getCategories = function() {
        if (ynabToolKit.budgetBalaceToZero === 'undefined') {
          return [];
        }

        var categories = [];
        var masterCategories = [];
        var masterCats = ynabToolKit.budgetBalaceToZero.budgetView
          .categoriesViewModel.masterCategoriesCollection._internalDataArray;

        masterCats.forEach(function(c) {
          // Filter out "special" categories
          if (c.internalName === null) {
            masterCategories.push(c.entityId);
          }
        });

        masterCategories.forEach(function(c) {
          var accounts = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.subCategoriesCollection
            .findItemsByMasterCategoryId(c);

          Array.prototype.push.apply(categories, accounts);
        });

        return categories;
      };

      this.updateInspectorButton = function(f) {
        if ($('.balance-to-zero').length) {
          return;
        }

        var name = f.name;
        var amount = ynabToolKit.budgetBalaceToZero.getBudgetAmount(f);

        var fhAmount = ynabToolKit.shared
          .formatCurrency(amount, true);
        var fAmount = ynabToolKit.shared
          .formatCurrency(amount, false);
        var button = ' \
        <button class="budget-inspector-button balance-to-zero" \
          onClick="ynabToolKit.checkCreditBalances.updateCreditBalances(\'' +
          name + '\', ' + amount + ')"> \
          Balance to 0.00: \
             \
               \
              ' + fhAmount + ' \
             \
           \
        </button>';

        $('.inspector-quick-budget .ember-view').append(button);
      };

      this.getInspectorName = function() {
        return $('.inspector-category-name.user-data').text().trim();
      };

      this.getBudgetAmount = function(f) {
        var currentMonth = moment(ynabToolKit.shared.parseSelectedMonth())
          .format('YYYY-MM');
        var monthlyBudget = ynabToolKit.checkCreditBalances.budgetView
          .monthlySubCategoryBudgetCalculationsCollection
          .findItemByEntityId('mcbc/' + currentMonth + '/' + f.entityId);

        return (monthlyBudget.cashOutflows * -1);
      };

    }();
  } else {
    setTimeout(poll, 250);
  }
})();
<commit_msg>Fix wrong amount and implement button click<commit_after>/* jshint multistr: true */
/* jscs:disable disallowMultipleLineStrings */

(function poll() {
  if (typeof ynabToolKit !== 'undefined'  && ynabToolKit.pageReady === true) {

    ynabToolKit.budgetBalaceToZero = new function() {  // jshint ignore:line

      this.budgetView = ynab.YNABSharedLib
        .getBudgetViewModel_AllBudgetMonthsViewModel()._result; // jscs:ignore requireCamelCaseOrUpperCaseIdentifiers

      this.invoke = function() {
        var categories = ynabToolKit.budgetBalaceToZero.getCategories();
        var categoryName = ynabToolKit.budgetBalaceToZero.getInspectorName();

        categories.forEach(function(f) {
          if (f.name === categoryName) {
            ynabToolKit.budgetBalaceToZero.updateInspectorButton(f);
          }
        });
      };

      this.observe = function(changedNodes) {
        if (changedNodes.has('budget-inspector')) {
          ynabToolKit.budgetBalaceToZero.invoke();
        }
      };

      this.getCategories = function() {
        if (ynabToolKit.budgetBalaceToZero === 'undefined') {
          return [];
        }

        var categories = [];
        var masterCategories = [];
        var masterCats = ynabToolKit.budgetBalaceToZero.budgetView
          .categoriesViewModel.masterCategoriesCollection._internalDataArray;

        masterCats.forEach(function(c) {
          // Filter out "special" categories
          if (c.internalName === null) {
            masterCategories.push(c.entityId);
          }
        });

        masterCategories.forEach(function(c) {
          var accounts = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.subCategoriesCollection
            .findItemsByMasterCategoryId(c);

          Array.prototype.push.apply(categories, accounts);
        });

        return categories;
      };

      this.updateInspectorButton = function(f) {
        if ($('.balance-to-zero').length) {
          return;
        }

        var name = f.name;
        var amount = ynabToolKit.budgetBalaceToZero.getBudgetAmount(f);

        var fhAmount = ynabToolKit.shared
          .formatCurrency(amount, true);
        var fAmount = ynabToolKit.shared
          .formatCurrency(amount, false);
        var button = ' \
        <button class="budget-inspector-button balance-to-zero" \
          onClick="ynabToolKit.budgetBalaceToZero.updateBudgetedBalance(\'' +
          name + '\', ' + amount + ')"> \
          Balance to 0.00: \
             \
               \
              ' + fhAmount + ' \
             \
           \
        </button>';

        $('.inspector-quick-budget .ember-view').append(button);
      };

      this.updateBudgetedBalance = function(name, difference) {
        var categories = $('.is-sub-category.is-checked');

        $(categories).each(function() {
          var accountName = $(this).find('.budget-table-cell-name div.button-truncate').prop('title');
          if (accountName === name) {
            var input = $(this).find('.budget-table-cell-budgeted div.currency-input').click().find('input');
            var oldValue = input.val();

            // If nothing is budgetted, the input will be empty
            oldValue = oldValue ? oldValue : 0;

            // Get the formatted currency so we can add it to the budget box correctly
            var fhDifference = ynabToolKit.shared.formatCurrency(difference, true);
            var results = /(-*).*bdi>(.*)/g.exec(fhDifference);
            var addition = results[1] + results[2];

            // Strip out commas since they mess things up
            addition = addition.replace(/,/g, '');

            var newValue = (parseFloat(oldValue) + parseFloat(addition));

            input.val(newValue);
            $(input).blur();
          }
        });
      };

      this.getInspectorName = function() {
        return $('.inspector-category-name.user-data').text().trim();
      };

      this.getBudgetAmount = function(f) {
        var currentMonth = moment(ynabToolKit.shared.parseSelectedMonth())
          .format('YYYY-MM');
        var monthlyBudget = ynabToolKit.checkCreditBalances.budgetView
          .monthlySubCategoryBudgetCalculationsCollection
          .findItemByEntityId('mcbc/' + currentMonth + '/' + f.entityId);

        return (monthlyBudget.balance * -1);
      };

    }();
  } else {
    setTimeout(poll, 250);
  }
})();
<|endoftext|>


<commit_before>/* global AuthorshipGroup, Document, DocumentOrigins, GruntTaskRunner, SqlService, Promise, Group, PerformanceCalculator */
'use strict';

/**
 * Group.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/#!documentation/models
 */

const _ = require('lodash');
const ResearchEntity = require('../lib/ResearchEntity');

module.exports = _.merge({}, ResearchEntity, {
    DEFAULT_SORTING: {
        name: 'asc',
        updatedAt: 'desc'
    },
    searchKey: 'slug',
    attributes: {
        name: 'STRING',
        slug: {
            type: 'STRING'
        },
        shortname: 'TEXT',
        description: 'TEXT',
        publicationsAcronym: 'TEXT',
        type: 'STRING',
        code: 'STRING',
        active: 'BOOLEAN',
        collaborations: {
            collection: 'collaboration',
            via: 'group'
        },
        starting_date: 'DATE',
        administrators: {
            collection: 'user',
            via: 'administratedGroups',
            through: 'groupadministrator'
        },
        pis: {
            collection: 'user',
            via: 'managedGroups',
            through: 'principalinvestigator'
        },
        members: {
            collection: 'User',
            via: 'memberships',
            through: 'membership'
        },
        allMembers: {
            collection: 'User',
            through: 'allmembership'
        },
        memberships: {
            collection: 'membership',
            via: 'group'
        },
        allMemberships: {
            collection: 'allmembership',
            via: 'group'
        },
        childGroups:{
            collection: 'group',
            via: 'parent_group',
            through: 'membershipgroup'
        },
        drafts: {
            collection: 'Document',
            via: 'draftGroupCreator'
        },
        documents: {
            collection: 'document',
            via: 'groups',
            through: 'authorshipgroup'
        },
        publicDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'publicauthorshipgroup'
        },
        publications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'publicationgroup'
        },
        highImpactPublications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'highimpactpublicationgroup'
        },
        favoritePublications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'favoritepublicationgroup'
        },
        disseminationTalks: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'disseminationtalkgroup'
        },
        scientificTalks: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'scientifictalkgroup'
        },
        authorships: {
            collection: 'authorshipGroup',
            via: 'researchEntity',
        },
        discardedDocuments: {
            collection: 'Document',
            via: 'discardedGroups',
            through: 'discardedgroup'
        },
        suggestedDocuments: {
            collection: 'document',
            via: 'groups',
            through: 'documentsuggestiongroup'
        },
        externalDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'externaldocumentgroup'
        },
        notDuplicateDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'documentnotduplicategroup'
        },
        getType: function () {
            return 'group';
        },
        scopusId: {
            type: 'STRING'
        },
        institute: {
            model: 'institute'
        },
        attributes: {
            collection: 'Attribute',
            through: 'groupattribute'
        },
        groupAttributes: {
            collection: 'groupattribute',
            via: 'researchEntity',
        },
    },
    getAuthorshipsData: async function (document, groupId, newAffiliationData = {}) {
        return {
            isVerifiable: true,
            document: document,
            synchronize: !_.isNil(newAffiliationData.synchronize) ? newAffiliationData.synchronize : document.synchronized,
            public: true
        };
    },
    doVerifyDocument: async function (document, researchEntityId, authorshipData) {
        const authorship = {
            researchEntity: researchEntityId,
            document: document.id,
            synchronize: authorshipData.synchronize,
            public: authorshipData.public,
        };
        await AuthorshipGroup.create(authorship);
        return document;
    },
    getDefaultGroup: function () {
        //TODO: id must be read from settings
        const defaultInstituteName = sails.config.scientilla.institute.name;
        return Group.findOneByName(defaultInstituteName)
            .populate('members')
            .populate('administrators');
    },
    addMember: function (group, user) {
        group.members.add(user);
        return group.savePromise();
    },
    addAdministrator: function (group, user) {
        if (group.administrators.length == 0)
            group.administrators.add(user);
        return group.savePromise();
    },
    addUserToDefaultGroup: function (user) {
        return Group.getDefaultGroup()
            .then(group => Group.addAdministrator(group, user))
            .then(group => Group.addMember(group, user))
            .then(() => user);
    },
    getAuthorshipModel: function () {
        return AuthorshipGroup;
    },
    updateProfile: async function (groupId, groupData) {
        delete groupData.memberships;
        delete groupData.members;
        const oldResearchEntity = await Group.findOne({id: groupId});
        const res = await Group.update({id: groupId}, groupData);
        const newResearchEntity = res[0];

        const command = 'import:external:group:' + newResearchEntity.id;
        if (newResearchEntity.scopusId !== oldResearchEntity.scopusId)
            GruntTaskRunner.run(command + ':' + DocumentOrigins.SCOPUS);
        if (newResearchEntity.publicationsAcronym !== oldResearchEntity.publicationsAcronym)
            GruntTaskRunner.run(command + ':' + DocumentOrigins.PUBLICATIONS);

        return newResearchEntity;
    },
    getMBOInstitutePerformance: async function (cdr, year) {
        if (cdr) {
            const group = await Group.findOne({code:cdr}).populate('documents');
            if(!group)
                throw 'Group not found';
            return await PerformanceCalculator.getGroupInstitutePerformance(group, year);
        }

        return await PerformanceCalculator.getGroupsInstitutePerformance(year);
    },
    getMBOInvitedTalks: async function (cdr, year) {
        if (cdr) {
            const group = await Group.findOne({code:cdr}).populate('documents');
            if(!group)
                throw 'Group not found';
            return await PerformanceCalculator.getGroupMBOInvitedTalks(group, year);
        }

        return await PerformanceCalculator.getGroupsMBOInvitedTalks(year);
    }
});
<commit_msg>Fixed main group members addition bug<commit_after>/* global AuthorshipGroup, Document, DocumentOrigins, GruntTaskRunner, SqlService, Promise, Group, PerformanceCalculator */
'use strict';

/**
 * Group.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/#!documentation/models
 */

const _ = require('lodash');
const ResearchEntity = require('../lib/ResearchEntity');

module.exports = _.merge({}, ResearchEntity, {
    DEFAULT_SORTING: {
        name: 'asc',
        updatedAt: 'desc'
    },
    searchKey: 'slug',
    attributes: {
        name: 'STRING',
        slug: {
            type: 'STRING'
        },
        shortname: 'TEXT',
        description: 'TEXT',
        publicationsAcronym: 'TEXT',
        type: 'STRING',
        code: 'STRING',
        active: 'BOOLEAN',
        collaborations: {
            collection: 'collaboration',
            via: 'group'
        },
        starting_date: 'DATE',
        administrators: {
            collection: 'user',
            via: 'administratedGroups',
            through: 'groupadministrator'
        },
        pis: {
            collection: 'user',
            via: 'managedGroups',
            through: 'principalinvestigator'
        },
        members: {
            collection: 'User',
            via: 'memberships',
            through: 'membership'
        },
        allMembers: {
            collection: 'User',
            through: 'allmembership'
        },
        memberships: {
            collection: 'membership',
            via: 'group'
        },
        allMemberships: {
            collection: 'allmembership',
            via: 'group'
        },
        childGroups: {
            collection: 'group',
            via: 'parent_group',
            through: 'membershipgroup'
        },
        drafts: {
            collection: 'Document',
            via: 'draftGroupCreator'
        },
        documents: {
            collection: 'document',
            via: 'groups',
            through: 'authorshipgroup'
        },
        publicDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'publicauthorshipgroup'
        },
        publications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'publicationgroup'
        },
        highImpactPublications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'highimpactpublicationgroup'
        },
        favoritePublications: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'favoritepublicationgroup'
        },
        disseminationTalks: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'disseminationtalkgroup'
        },
        scientificTalks: {
            collection: 'Document',
            via: 'researchEntity',
            through: 'scientifictalkgroup'
        },
        authorships: {
            collection: 'authorshipGroup',
            via: 'researchEntity',
        },
        discardedDocuments: {
            collection: 'Document',
            via: 'discardedGroups',
            through: 'discardedgroup'
        },
        suggestedDocuments: {
            collection: 'document',
            via: 'groups',
            through: 'documentsuggestiongroup'
        },
        externalDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'externaldocumentgroup'
        },
        notDuplicateDocuments: {
            collection: 'document',
            via: 'researchEntity',
            through: 'documentnotduplicategroup'
        },
        getType: function () {
            return 'group';
        },
        scopusId: {
            type: 'STRING'
        },
        institute: {
            model: 'institute'
        },
        attributes: {
            collection: 'Attribute',
            through: 'groupattribute'
        },
        groupAttributes: {
            collection: 'groupattribute',
            via: 'researchEntity',
        },
    },
    getAuthorshipsData: async function (document, groupId, newAffiliationData = {}) {
        return {
            isVerifiable: true,
            document: document,
            synchronize: !_.isNil(newAffiliationData.synchronize) ? newAffiliationData.synchronize : document.synchronized,
            public: true
        };
    },
    doVerifyDocument: async function (document, researchEntityId, authorshipData) {
        const authorship = {
            researchEntity: researchEntityId,
            document: document.id,
            synchronize: authorshipData.synchronize,
            public: authorshipData.public,
        };
        await AuthorshipGroup.create(authorship);
        return document;
    },
    getDefaultGroup: function () {
        //TODO: id must be read from settings
        const defaultInstituteName = sails.config.scientilla.institute.name;
        return Group.findOneByName(defaultInstituteName)
            .populate('members')
            .populate('administrators');
    },
    addMember: function (group, user) {
        return Membership.create({
            user: user.id,
            group: group.id,
            lastsynch: new Date(),
            active: true,
            synchronized: true
        });
    },
    addAdministrator: function (group, user) {
        if (group.administrators.length === 0)
            group.administrators.add(user);
        return group.savePromise();
    },
    addUserToDefaultGroup: function (user) {
        return Group.getDefaultGroup()
            .then(group => Group.addAdministrator(group, user))
            .then(group => Group.addMember(group, user))
            .then(() => user);
    },
    getAuthorshipModel: function () {
        return AuthorshipGroup;
    },
    updateProfile: async function (groupId, groupData) {
        delete groupData.memberships;
        delete groupData.members;
        const oldResearchEntity = await Group.findOne({id: groupId});
        const res = await Group.update({id: groupId}, groupData);
        const newResearchEntity = res[0];

        const command = 'import:external:group:' + newResearchEntity.id;
        if (newResearchEntity.scopusId !== oldResearchEntity.scopusId)
            GruntTaskRunner.run(command + ':' + DocumentOrigins.SCOPUS);
        if (newResearchEntity.publicationsAcronym !== oldResearchEntity.publicationsAcronym)
            GruntTaskRunner.run(command + ':' + DocumentOrigins.PUBLICATIONS);

        return newResearchEntity;
    },
    getMBOInstitutePerformance: async function (cdr, year) {
        if (cdr) {
            const group = await Group.findOne({code: cdr}).populate('documents');
            if (!group)
                throw 'Group not found';
            return await PerformanceCalculator.getGroupInstitutePerformance(group, year);
        }

        return await PerformanceCalculator.getGroupsInstitutePerformance(year);
    },
    getMBOInvitedTalks: async function (cdr, year) {
        if (cdr) {
            const group = await Group.findOne({code: cdr}).populate('documents');
            if (!group)
                throw 'Group not found';
            return await PerformanceCalculator.getGroupMBOInvitedTalks(group, year);
        }

        return await PerformanceCalculator.getGroupsMBOInvitedTalks(year);
    }
});
<|endoftext|>


<commit_before>it("date data", function (done) {
    // [inject] init

    var b = wrap.getElementsByTagName('b')[0];
    expect(b.title).toBe('1983');

    myComponent.data.set('date', new Date(1984, 10, 10));

    san.nextTick(function () {
        var b = wrap.getElementsByTagName('b')[0];
        expect(b.title).toBe('1984');

        myComponent.dispose();
        document.body.removeChild(wrap);
        done();
    });
});

<commit_msg>check date data item<commit_after>it("date data", function (done) {
    // [inject] init

    var b = wrap.getElementsByTagName('b')[0];
    expect(b.title).toBe('1983');

    myComponent.data.set('date', new Date(myComponent.data.get('date').getFullYear() + 1, 10, 10));

    san.nextTick(function () {
        var b = wrap.getElementsByTagName('b')[0];
        expect(b.title).toBe('1984');

        myComponent.dispose();
        document.body.removeChild(wrap);
        done();
    });
});

<|endoftext|>


<commit_before>'use strict';

var request = require('request');
var fs = require('fs');
var wallpaper = require('wallpaper');

var DailyWallpaper = function () {};

DailyWallpaper.prototype = {

    constructor: DailyWallpaper,
    directory: '',
    showNotification: false,

    /**
     * Set the directory if it exists
     * @param {String} directoryPath
     * @param {function} onDirectorySet Called when the directory is set
     *                                  with an optionnal error in parameter
     */
    setDirectory: function (directoryPath) {
        this.directory = directoryPath;
    },
    /**
     * Set the wallpaper of the day (showing a notification if needed)
     * @param {function} done Called when done (with optional error)
     */
    setDailyWallpaper: function (done) {

        if (!this.getWallpaperSource) {
            return done(new Error('DailyWallpaper.getWallpaperSource must be implemented'));
        }

        this.getWallpaperSource(function (err, wallpaperSource) {
            if (err) {
                return done(new Error('Error while getting the wallpaper of the day'));
            }

            if (!wallpaperSource || !wallpaperSource.url) {
                return done(new Error('Wallpaper URL not set'));
            }

            if (!this.directory) {
                return done(new Error('Directory is not set'));
            }

            if (!fs.existsSync(this.directory)) {
                return done(new Error('Directory "' + this.directory + '" doesn\'t exist'));
            }

            this._downloadWallpaper(wallpaperSource, function (err, filePath) {
                if (err) {
                    return done(new Error('Error while downloading the wallpaper at ' + wallpaperSource.url));
                }

                wallpaper.set(filePath, function (err) {
                    if (err) {
                        return done(new Error('Error while setting the wallpaper from ' + filePath));
                    }

                    return done();

                });
            });

        }.bind(this));
    },

    /**
     * Download the daily wallpaper in the wallpaper directory
     * @param {function} done Called when the download is done (with an optionnal error)
     *                        and filePath as second parameter
     */
    _downloadWallpaper: function (wallpaperSource, done) {

        var fileName = new Date().toISOString().substr(0, 10) + '.' + (wallpaperSource.extension || '.jpg');
        var filePath = this.directory + '/' + fileName;

        request.head(wallpaperSource.url, function(err) {

            if (err) {
                done(err);
            }

            request(wallpaperSource.url)
                .pipe(fs.createWriteStream(filePath))
                .on('close', function () {
                    done(null, filePath);
                })
                .on('error', function (err) {
                    done(err);
                })
            ;
        });
    },

};

module.exports = DailyWallpaper;
<commit_msg>Fix error handling<commit_after>'use strict';

var request = require('request');
var fs = require('fs');
var wallpaper = require('wallpaper');

var DailyWallpaper = function () {};

DailyWallpaper.prototype = {

    constructor: DailyWallpaper,
    directory: '',
    showNotification: false,

    /**
     * Set the directory if it exists
     * @param {String} directoryPath
     * @param {function} onDirectorySet Called when the directory is set
     *                                  with an optionnal error in parameter
     */
    setDirectory: function (directoryPath) {
        this.directory = directoryPath;
    },
    /**
     * Set the wallpaper of the day (showing a notification if needed)
     * @param {function} done Called when done (with optional error)
     */
    setDailyWallpaper: function (done) {

        done = done || function () {};

        if (!this.getWallpaperSource) {
            return done(new Error('DailyWallpaper.getWallpaperSource must be implemented'));
        }

        this.getWallpaperSource(function (err, wallpaperSource) {
            if (err) {
                return done(new Error('Error while getting the wallpaper of the day'));
            }

            if (!wallpaperSource || !wallpaperSource.url) {
                return done(new Error('Wallpaper URL not set'));
            }

            if (!this.directory) {
                return done(new Error('Directory is not set'));
            }

            if (!fs.existsSync(this.directory)) {
                return done(new Error('Directory "' + this.directory + '" doesn\'t exist'));
            }

            this._downloadWallpaper(wallpaperSource, function (err, filePath) {
                if (err) {
                    return done(new Error('Error while downloading the wallpaper at ' + wallpaperSource.url));
                }

                wallpaper.set(filePath, function (err) {
                    if (err) {
                        return done(new Error('Error while setting the wallpaper from ' + filePath));
                    }

                    return done();

                });
            });

        }.bind(this));
    },

    /**
     * Download the daily wallpaper in the wallpaper directory
     * @param {function} done Called when the download is done (with an optionnal error)
     *                        and filePath as second parameter
     */
    _downloadWallpaper: function (wallpaperSource, done) {

        var fileName = new Date().toISOString().substr(0, 10) + '.' + (wallpaperSource.extension || '.jpg');
        var filePath = this.directory + '/' + fileName;

        request.head(wallpaperSource.url, function(err) {

            if (err) {
                return done(err);
            }

            request(wallpaperSource.url)
                .pipe(fs.createWriteStream(filePath))
                .on('close', function () {
                    return done(null, filePath);
                })
                .on('error', function (err) {
                    return done(err);
                })
            ;
        });
    },

};

module.exports = DailyWallpaper;
<|endoftext|>


<commit_before>var util = require('../fin/util'),
	map = util.map,
	bind = util.bind

// nothing here yet :)
var customModels = module.exports = {
	process: process
}

function process(modelDescriptions) {
	for (var modelName in modelDescriptions) {
		_validateModelDescription(modelName, modelDescriptions[modelName])
		_createModelConstructor(modelName, modelDescriptions[modelName])
	}
}

var _validateModelDescription = function(modelName, properties) {
	var firstLetterCode = modelName.charCodeAt(0)
	assert(65 <= firstLetterCode && firstLetterCode <= 90, 'Model names should start with an upper case letter. "'+modelName+'" does not.')
	assert(!customModels[modelName], 'Model "'+modelName+'" already exists')
	var propertyIDs = {}
	for (propertyName in properties) {
		firstLetterCode = propertyName.charCodeAt(0)
		var property = properties[propertyName]
		assert(97 <= firstLetterCode && firstLetterCode <= 122, 'Property names should start with a lowercase letter. "'+propertyName+'" does not.')
		assert(typeof property.id == 'number', 'Properties need an id. "'+propertyName+'" does not')
		assert(!propertyIDs[property.id], 'Property IDs need to be unique. "'+modelName+'" has two properties with the id '+property.id+'')
		assert(!CustomModelPrototype[propertyName], 'Certain property names would overwrite important model methods. "'+propertyName+'" on "'+modelName+'" is such a property - pick a different property name.')
	}
}

var _createModelConstructor = function(modelName, modelDescription) {
	var modelConstructor = customModels[modelName] = function(idOrValues) {
		this._constructor = customModels[modelName]
		this._instantiate.call(this, idOrValues)
	}
	var modelPropertiesID = []
	for (var propertyName in modelDescription) {
		modelPropertiesID.push(modelDescription[propertyName].id)
	}
	modelConstructor.prototype = CustomModelPrototype
	modelConstructor.description = modelDescription
	modelConstructor.properties = map(modelDescription, function(propDescr) { return propDescr.id })
}

var CustomModelPrototype = {
	_instantiate: instantiateModel,
	create: createModel
}

function instantiateModel(idOrValues) {
	var values
	if (typeof idOrValues == 'number') { this._id = idOrValues }
	else { values = idOrValues || {} }

	for (var propertyName in this._constructor.description) {
		var propertyDescription = this._constructor.description[propertyName],
			valueType = propertyDescription.type,
			Model = propertyModels[valueType] || customModels[valueType],
			value = values[propertyName]

		this[propertyName] = new Model(value)
	}
}

function createModel() {
	// TODO sync with server
}

// UTILS
function assert(isOK, msg) {
	if (isOK) { return }
	throw new Error(msg)
}

var PropertyModel = function(value) {
	this._value = value
}

var propertyModels = {
	"Text": PropertyModel,
	"Number": PropertyModel
}

/* TODO
 - add on, observe and promise to RootModel
 - have Text and Number extend RootModel with set
 - have Set and List extend RootModel and publish on('add') and on('remove')
 - to implement on/observe/promise, climb the parent models to create the observation chain
 - call fin.create in initializer
 - add fin.transact
*/

// TODO check that each instance property is present in modelProperties when created
// TODO check that instanceProperties fullfill "type" & "required" in modelProperties
<commit_msg>Don't allow for custom models with the same name as the property models (Text, Number, Set, List, Hash)<commit_after>var util = require('../fin/util'),
	map = util.map,
	bind = util.bind

// nothing here yet :)
var customModels = module.exports = {
	process: process
}

function process(modelDescriptions) {
	for (var modelName in modelDescriptions) {
		_validateModelDescription(modelName, modelDescriptions[modelName])
		_createModelConstructor(modelName, modelDescriptions[modelName])
	}
}

var _validateModelDescription = function(modelName, properties) {
	var firstLetterCode = modelName.charCodeAt(0)
	assert(65 <= firstLetterCode && firstLetterCode <= 90, 'Model names should start with an upper case letter. "'+modelName+'" does not.')
	assert(!customModels[modelName], 'Model "'+modelName+'" already exists')
	assert(!propertyModels[modelName], 'Property model "'+modelName+'" already exists')
	var propertyIDs = {}
	for (propertyName in properties) {
		firstLetterCode = propertyName.charCodeAt(0)
		var property = properties[propertyName]
		assert(97 <= firstLetterCode && firstLetterCode <= 122, 'Property names should start with a lowercase letter. "'+propertyName+'" does not.')
		assert(typeof property.id == 'number', 'Properties need an id. "'+propertyName+'" does not')
		assert(!propertyIDs[property.id], 'Property IDs need to be unique. "'+modelName+'" has two properties with the id '+property.id+'')
		assert(!CustomModelPrototype[propertyName], 'Certain property names would overwrite important model methods. "'+propertyName+'" on "'+modelName+'" is such a property - pick a different property name.')
	}
}

var _createModelConstructor = function(modelName, modelDescription) {
	var modelConstructor = customModels[modelName] = function(idOrValues) {
		this._constructor = customModels[modelName]
		this._instantiate.call(this, idOrValues)
	}
	var modelPropertiesID = []
	for (var propertyName in modelDescription) {
		modelPropertiesID.push(modelDescription[propertyName].id)
	}
	modelConstructor.prototype = CustomModelPrototype
	modelConstructor.description = modelDescription
	modelConstructor.properties = map(modelDescription, function(propDescr) { return propDescr.id })
}

var CustomModelPrototype = {
	_instantiate: instantiateModel,
	create: createModel
}

function instantiateModel(idOrValues) {
	var values
	if (typeof idOrValues == 'number') { this._id = idOrValues }
	else { values = idOrValues || {} }

	for (var propertyName in this._constructor.description) {
		var propertyDescription = this._constructor.description[propertyName],
			valueType = propertyDescription.type,
			Model = propertyModels[valueType] || customModels[valueType],
			value = values[propertyName]

		this[propertyName] = new Model(value)
	}
}

function createModel() {
	// TODO sync with server
}

// UTILS
function assert(isOK, msg) {
	if (isOK) { return }
	throw new Error(msg)
}

var PropertyModel = function(value) {
	this._value = value
}

var propertyModels = {
	"Text": PropertyModel,
	"Number": PropertyModel
}

/* TODO
 - add on, observe and promise to RootModel
 - have Text and Number extend RootModel with set
 - have Set and List extend RootModel and publish on('add') and on('remove')
 - to implement on/observe/promise, climb the parent models to create the observation chain
 - call fin.create in initializer
 - add fin.transact
*/

// TODO check that each instance property is present in modelProperties when created
// TODO check that instanceProperties fullfill "type" & "required" in modelProperties
<|endoftext|>


<commit_before>import DS from 'ember-data';

var attr = DS.attr,
    belongsTo = DS.belongsTo;

export default DS.Model.extend({
  name:          attr('string'),
  mobile:        attr('string'),

  bookingId:     attr('number'),
  status:        attr('string'),
  pickupTime:    attr('date'),
  slot:          attr('string'),
  districtId:    attr('number'),
  territoryId:   attr('number'),
  offerId:       attr('number'),
  gogovanOptionId: attr('number'),
  completedAt:     attr('date'),

  needEnglish:   attr('boolean'),
  needCart:      attr('boolean'),
  needCarry:     attr('boolean'),
  needOver6ft:   attr('true'),
  removeNet:     attr('string'),

  baseFee:       attr('string'),
  totalFee:      attr('string'),
  needEnglishFee: attr('string'),
  needCartFee:    attr('string'),
  removeNetFee:   attr('string'),

  price:         attr('number'),
  driverName:    attr('string'),
  driverMobile:  attr('string'),
  driverLicense: attr('string'),
  ggvUuid:       attr('string'),
  delivery:      belongsTo('delivery', { async: false }),

  i18n: Ember.inject.service(),

  isPending: Ember.computed.equal("status", "pending"),
  isActive: Ember.computed.equal("status", "active"),
  isCompleted: Ember.computed.equal("status", "completed"),
  isCancelled: Ember.computed.equal("status", "cancelled"),
  isPickedUp: Ember.computed.or("isActive", "isCompleted"),
  nonCompleted: Ember.computed.or("isActive", "isPending"),

  ggvOrderStatus: Ember.computed("isActive", "isCompleted", function(){
    if(this.get("isActive")) {
      return this.get("i18n").t("offer.offer_details.is_gogovan_confirm").string;
    } else if(this.get("isCompleted")) {
      return this.get("i18n").t("offer.offer_details.driver_completed").string;
    } else {
      return this.get("i18n").t("offer.offer_details.is_gogovan_order").string;
    }
  }),
});
<commit_msg>fixed gogovan_order model attribute<commit_after>import DS from 'ember-data';

var attr = DS.attr,
    belongsTo = DS.belongsTo;

export default DS.Model.extend({
  name:          attr('string'),
  mobile:        attr('string'),

  bookingId:     attr('number'),
  status:        attr('string'),
  pickupTime:    attr('date'),
  slot:          attr('string'),
  districtId:    attr('number'),
  territoryId:   attr('number'),
  offerId:       attr('number'),
  gogovanOptionId: attr('number'),
  completedAt:     attr('date'),

  needEnglish:   attr('boolean'),
  needCart:      attr('boolean'),
  needCarry:     attr('boolean'),
  needOver6ft:   attr('boolean'),
  removeNet:     attr('string'),

  baseFee:       attr('string'),
  totalFee:      attr('string'),
  needEnglishFee: attr('string'),
  needCartFee:    attr('string'),
  removeNetFee:   attr('string'),

  price:         attr('number'),
  driverName:    attr('string'),
  driverMobile:  attr('string'),
  driverLicense: attr('string'),
  ggvUuid:       attr('string'),
  delivery:      belongsTo('delivery', { async: false }),

  i18n: Ember.inject.service(),

  isPending: Ember.computed.equal("status", "pending"),
  isActive: Ember.computed.equal("status", "active"),
  isCompleted: Ember.computed.equal("status", "completed"),
  isCancelled: Ember.computed.equal("status", "cancelled"),
  isPickedUp: Ember.computed.or("isActive", "isCompleted"),
  nonCompleted: Ember.computed.or("isActive", "isPending"),

  ggvOrderStatus: Ember.computed("isActive", "isCompleted", function(){
    if(this.get("isActive")) {
      return this.get("i18n").t("offer.offer_details.is_gogovan_confirm").string;
    } else if(this.get("isCompleted")) {
      return this.get("i18n").t("offer.offer_details.driver_completed").string;
    } else {
      return this.get("i18n").t("offer.offer_details.is_gogovan_order").string;
    }
  }),
});
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(API, Utils, VFS, GUI) {
  'use strict';

  GUI = OSjs.GUI || {};
  GUI.Elements = OSjs.GUI.Elements || {};

  /////////////////////////////////////////////////////////////////////////////
  // HELPERS
  /////////////////////////////////////////////////////////////////////////////

  function handleItemSelection(ev, item, idx, className, selected, root, multipleSelect) {
    root = root || item.parentNode;

    if ( !multipleSelect || !ev.shiftKey ) {
      root.querySelectorAll(className).forEach(function(i) {
        Utils.$removeClass(i, 'gui-active');
      });
      selected = [];
    }

    var findex = selected.indexOf(idx);
    if ( findex >= 0 ) {
      selected.splice(findex, 1);
      Utils.$removeClass(item, 'gui-active');
    } else {
      selected.push(idx);
      Utils.$addClass(item, 'gui-active');
    }

    selected.sort(function(a, b) {
      return a - b;
    });

    return selected;
  }

  function getSelected(el) {
    return GUI.Elements[el.tagName.toLowerCase()].values(el);
  }

  function handleKeyPress(el, ev) {
    var classMap = {
      'gui-list-view': 'gui-list-view-row',
      'gui-tree-view': 'gui-tree-view-entry',
      'gui-icon-view': 'gui-icon-view-entry'
    };

    var map = {};
    var key = ev.keyCode;
    var type = el.tagName.toLowerCase();
    var className = classMap[type];
    var root = el.querySelector(type + '-body');
    var entries = root.querySelectorAll(className);
    var count = entries.length;

    if ( !count ) { return; }

    if ( key === Utils.Keys.ENTER ) {
      el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
      return;
    }

    var selected = el._selected.concat() || [];
    var first = selected.length ? selected[0] : 0;
    var last = selected.length > 1 ? selected[selected.length - 1] : first;
    var current = 0;

    function select() {
      var item = entries[current];
      if ( item ) {
        el._selected = handleItemSelection(ev, item, current, className, selected, root, ev.shiftKey);
        GUI.Elements._dataview.scrollIntoView(el, item);
      }
    }

    function getRowSize() {
      /* NOT ACCURATE!
      var ew = entries[0].offsetWidth;
      var tw = root.offsetWidth;
      var d = Math.floor(tw/ew);
      */
      var d = 0;

      var lastTop = -1;
      entries.forEach(function(e) {
        if ( lastTop === -1 ) {
          lastTop = e.offsetTop;
        }

        if ( lastTop !== e.offsetTop ) {
          return false;
        }

        lastTop = e.offsetTop;
        d++;

        return true;
      });

      return d;
    }

    function handleKey() {
      function next() {
        current = Math.min(last + 1, count);
        select();
      }
      function prev() {
        current = Math.max(0, first - 1);
        select();
      }

      if ( type === 'gui-tree-view' || type === 'gui-list-view' ) {
        map[Utils.Keys.UP] = prev;
        map[Utils.Keys.DOWN] = next;
      } else {
        map[Utils.Keys.UP] = function() {
          current = Math.max(0, first - getRowSize());
          select();
        };
        map[Utils.Keys.DOWN] = function() {
          current = Math.max(last, last + getRowSize());
          select();
        };
        map[Utils.Keys.LEFT] = prev;
        map[Utils.Keys.RIGHT] = next;
      }

      if ( map[key] ) { map[key](ev); }
    }

    handleKey();
  }

  function matchValueByKey(r, val, key, idx) {
    if ( val || val === 0 ) {
      var value = r.getAttribute('data-value');
      if ( !key && (val === idx || val === value) ) {
        return r;
      } else {
        try {
          var json = JSON.parse(value);
          if ( typeof json[key] === 'object' ? json[key] === val : String(json[key]) === String(val) ) {
            return r;
          }
        } catch ( e ) {}
      }
    }
    return false;
  }

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Element: '_dataview'
   *
   * This is an abstraction layer for Icon, Tree and List views.
   *
   * Events:
   *  select        When an entry was selected (click) => fn(ev)
   *  activate      When an entry was activated (doubleclick) => fn(ev)
   *
   * Parameters:
   *  multiple  boolean     Multiple selection (default=true)
   *
   * Setters:
   *  value         Sets the selected entry(es)
   *  selected      Alias for 'value'
   *
   * Getters:
   *  entry         Gets an entry by value, key
   *  value         Gets the selected entry(es)
   *  selected      Alias for 'value'
   *
   * Actions:
   *  add(arg)      Adds en entry (or from array)
   *  remove(arg)   Removes an entry
   *  patch(arg)    Patch/Update entries from array
   *  clear()
   *
   * @api OSjs.GUI.Elements._dataview
   * @class
   */
  GUI.Elements._dataview = {
    clear: function(el, body) {
      body = body || el;

      Utils.$empty(body);
      body.scrollTop = 0;
      el._selected = [];
    },

    add: function(el, args, oncreate) {
      var entries = args[0];
      if ( !(entries instanceof Array) ) {
        entries = [entries];
      }
      entries.forEach(oncreate);

      return this;
    },

    patch: function(el, args, className, body, oncreate, oninit) {
      var self = this;
      var entries = args[0];
      var single = false;

      if ( !(entries instanceof Array) ) {
        entries = [entries];
        single = true;
      }

      var inView = {};
      body.querySelectorAll(className).forEach(function(row) {
        var id = row.getAttribute('data-id');
        if ( id !== null ) {
          inView[id] = row;
        }
      });

      entries.forEach(function(entry) {
        var insertBefore;
        if ( typeof entry.id !== 'undefined' && entry.id !== null ) {
          if ( inView[entry.id] ) {
            insertBefore = inView[entry.id];
            delete inView[entry.id];
          }

          var row = oncreate(entry);
          if ( row ) {
            if ( insertBefore ) {
              if ( Utils.$hasClass(insertBefore, 'gui-active') ) {
                Utils.$addClass(row, 'gui-active');
              }

              body.insertBefore(row, insertBefore);
              self.remove(el, null, className, insertBefore);
            } else {
              body.appendChild(row);
            }
            oninit(el, row);
          }
        }
      });

      if ( !single ) {
        Object.keys(inView).forEach(function(k) {
          self.remove(el, null, className, inView[k]);
        });
      }

      inView = {};
      this.updateActiveSelection(el, className);

      return this;
    },

    remove: function(el, args, className, target) {
      function remove(cel) {
        Utils.$remove(cel);
      }

      if ( target ) {
        remove(target);
        return;
      }
      if ( typeof args[1] === 'undefined' && typeof args[0] === 'number' ) {
        remove(el.querySelectorAll(className)[args[0]]);
      } else {
        var findId = args[0];
        var findKey = args[1] || 'id';
        var q = 'data-' + findKey + '="' + findId + '"';
        el.querySelectorAll(className + '[' + q + ']').forEach(remove);
      }

      this.updateActiveSelection(el, className);

      return this;
    },

    updateActiveSelection: function(el, className) {
      var active = [];
      el.querySelectorAll(className + '.gui-active').forEach(function(cel) {
        active.push(Utils.$index(cel));
      });
      el._active = active;
    },

    scrollIntoView: function(el, element) {
      var pos = Utils.$position(element, el);
      var marginTop = 0;
      if ( el.tagName.toLowerCase() === 'gui-list-view' ) {
        var header = el.querySelector('gui-list-view-head');
        if ( header ) {
          marginTop = header.offsetHeight;
        }
      }

      var scrollSpace = (el.scrollTop + el.offsetHeight) - marginTop;
      var scrollTop = el.scrollTop + marginTop;
      var elTop = pos.top - marginTop;

      if ( pos !== null && (elTop > scrollSpace || elTop < scrollTop) ) {
        el.scrollTop = elTop;
        return true;
      }

      return false;
    },

    bindEntryEvents: function(el, row, className) {

      var singleClick = el.getAttribute('data-single-click') === 'true';

      function select(ev) {
        ev.stopPropagation();

        var multipleSelect = el.getAttribute('data-multiple');
        multipleSelect = multipleSelect === null || multipleSelect === 'true';
        var idx = Utils.$index(row);
        el._selected = handleItemSelection(ev, row, idx, className, el._selected, null, multipleSelect);
        el.dispatchEvent(new CustomEvent('_select', {detail: {entries: getSelected(el)}}));
      }

      function activate(ev) {
        el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
      }

      function context(ev) {
        select(ev);
        el.dispatchEvent(new CustomEvent('_contextmenu', {detail: {entries: getSelected(el), x: ev.clientX, y: ev.clientY}}));
      }

      function createDraggable() {
        var value = row.getAttribute('data-value');
        if ( value !== null ) {
          try {
            value = JSON.parse(value);
          } catch ( e ) {}
        }

        var source = row.getAttribute('data-draggable-source');
        if ( source === null ) {
          source = GUI.Helpers.getWindowId(el);
          if ( source !== null ) {
            source = {wid: source};
          }
        }

        API.createDraggable(row, {
          type   : el.getAttribute('data-draggable-type') || row.getAttribute('data-draggable-type'),
          source : source,
          data   : value
        });

        var tooltip = row.getAttribute('data-tooltip');
        if ( tooltip && !row.getAttribute('title') ) {
          row.setAttribute('title', tooltip);
        }
      }

      if ( singleClick ) {
        Utils.$bind(row, 'click', function(ev) {
          select(ev);
          activate(ev);
        });
      } else {
        Utils.$bind(row, 'click', select, false);
        Utils.$bind(row, 'dblclick', activate, false);
      }

      Utils.$bind(row, 'contextmenu', function(ev) {
        ev.preventDefault();
        context(ev);
        return false;
      }, false);

      el.dispatchEvent(new CustomEvent('_render', {detail: {
        element: row,
        data: GUI.Helpers.getViewNodeValue(row)
      }}));

      if ( el.getAttribute('data-draggable') === 'true' ) {
        createDraggable();
      }
    },

    getSelected: function(el, entries) {
      var selected = [];
      entries.forEach(function(iter, idx) {
        if ( Utils.$hasClass(iter, 'gui-active') ) {
          selected.push({
            index: idx,
            data: GUI.Helpers.getViewNodeValue(iter)
          });
        }
      });
      return selected;
    },

    getEntry: function(el, entries, val, key) {
      var result = null;
      entries.forEach(function(r, idx) {
        if ( matchValueByKey(r, val, key, idx) ) {
          result = r;
        }
        return !!result;
      });
      return result;
    },

    setSelected: function(el, body, entries, val, key) {
      var self = this;
      var select = [];

      function sel(r, idx) {
        select.push(idx);
        Utils.$addClass(r, 'gui-active');
        //self.scrollIntoView(el, r);
      }

      entries.forEach(function(r, idx) {
        Utils.$removeClass(r, 'gui-active');
        if ( matchValueByKey(r, val, key, idx) ) {
          sel(r, idx);
        }
      });
      el._selected = select;
    },

    build: function(el, applyArgs) {
      el._selected = [];
      el.scrollTop = 0;

      Utils.$addClass(el, 'gui-data-view');

      if ( !el.querySelector('textarea.gui-focus-element') && !el.getAttribute('no-selection') ) {
        var underlay = document.createElement('textarea');
        underlay.setAttribute('readonly', 'true');
        underlay.className = 'gui-focus-element';
        Utils.$bind(underlay, 'focus', function(ev) {
          ev.preventDefault();
          Utils.$addClass(el, 'gui-element-focused');
        });
        Utils.$bind(underlay, 'blur', function(ev) {
          ev.preventDefault();
          Utils.$removeClass(el, 'gui-element-focused');
        });
        Utils.$bind(underlay, 'keydown', function(ev) {
          ev.preventDefault();
          handleKeyPress(el, ev);
        });
        Utils.$bind(underlay, 'keypress', function(ev) {
          ev.preventDefault();
        });

        this.bind(el, 'select', function(ev) {
          if ( Utils.$hasClass(el, 'gui-element-focused') ) {
            return;
          }
          // NOTE: This is a fix for Firefox stupid behaviour when focusing/blurring textboxes
          // (which is used to have a focusable area in this case, called underlay)
          var oldTop = el.scrollTop;
          underlay.focus();
          el.scrollTop = oldTop;
          setTimeout(function() {
            el.scrollTop = oldTop;
          }, 2);
        }, true);

        el.appendChild(underlay);
      }
    },

    focus: function(el) {
      try {
        var underlay = el.querySelector('.gui-focus-element');
        underlay.focus();
      } catch ( e ) {
        console.warn(e, e.stack);
      }
    },

    blur: function(el) {
      try {
        var underlay = el.querySelector('.gui-focus-element');
        underlay.blur();
      } catch ( e ) {
        console.warn(e, e.stack);
      }
    },

    bind: function(el, evName, callback, params) {
      if ( (['activate', 'select', 'expand', 'contextmenu', 'render']).indexOf(evName) !== -1 ) {
        evName = '_' + evName;
      }
      Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
    }

  };

})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
<commit_msg>GUI: Fixed TreeView entry deselection (#136)<commit_after>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(API, Utils, VFS, GUI) {
  'use strict';

  GUI = OSjs.GUI || {};
  GUI.Elements = OSjs.GUI.Elements || {};

  /////////////////////////////////////////////////////////////////////////////
  // HELPERS
  /////////////////////////////////////////////////////////////////////////////

  function handleItemSelection(ev, item, idx, className, selected, root, multipleSelect) {
    root = root || item.parentNode;

    if ( !multipleSelect || !ev.shiftKey ) {
      root.querySelectorAll(className).forEach(function(i) {
        Utils.$removeClass(i, 'gui-active');
      });
      selected = [];
    }

    var findex = selected.indexOf(idx);
    if ( findex >= 0 ) {
      selected.splice(findex, 1);
      Utils.$removeClass(item, 'gui-active');
    } else {
      selected.push(idx);
      Utils.$addClass(item, 'gui-active');
    }

    selected.sort(function(a, b) {
      return a - b;
    });

    return selected;
  }

  function getSelected(el) {
    return GUI.Elements[el.tagName.toLowerCase()].values(el);
  }

  function handleKeyPress(el, ev) {
    var classMap = {
      'gui-list-view': 'gui-list-view-row',
      'gui-tree-view': 'gui-tree-view-entry',
      'gui-icon-view': 'gui-icon-view-entry'
    };

    var map = {};
    var key = ev.keyCode;
    var type = el.tagName.toLowerCase();
    var className = classMap[type];
    var root = el.querySelector(type + '-body');
    var entries = root.querySelectorAll(className);
    var count = entries.length;

    if ( !count ) { return; }

    if ( key === Utils.Keys.ENTER ) {
      el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
      return;
    }

    var selected = el._selected.concat() || [];
    var first = selected.length ? selected[0] : 0;
    var last = selected.length > 1 ? selected[selected.length - 1] : first;
    var current = 0;

    function select() {
      var item = entries[current];
      if ( item ) {
        el._selected = handleItemSelection(ev, item, current, className, selected, root, ev.shiftKey);
        GUI.Elements._dataview.scrollIntoView(el, item);
      }
    }

    function getRowSize() {
      /* NOT ACCURATE!
      var ew = entries[0].offsetWidth;
      var tw = root.offsetWidth;
      var d = Math.floor(tw/ew);
      */
      var d = 0;

      var lastTop = -1;
      entries.forEach(function(e) {
        if ( lastTop === -1 ) {
          lastTop = e.offsetTop;
        }

        if ( lastTop !== e.offsetTop ) {
          return false;
        }

        lastTop = e.offsetTop;
        d++;

        return true;
      });

      return d;
    }

    function handleKey() {
      function next() {
        current = Math.min(last + 1, count);
        select();
      }
      function prev() {
        current = Math.max(0, first - 1);
        select();
      }

      if ( type === 'gui-tree-view' || type === 'gui-list-view' ) {
        map[Utils.Keys.UP] = prev;
        map[Utils.Keys.DOWN] = next;
      } else {
        map[Utils.Keys.UP] = function() {
          current = Math.max(0, first - getRowSize());
          select();
        };
        map[Utils.Keys.DOWN] = function() {
          current = Math.max(last, last + getRowSize());
          select();
        };
        map[Utils.Keys.LEFT] = prev;
        map[Utils.Keys.RIGHT] = next;
      }

      if ( map[key] ) { map[key](ev); }
    }

    handleKey();
  }

  function matchValueByKey(r, val, key, idx) {
    if ( val || val === 0 ) {
      var value = r.getAttribute('data-value');
      if ( !key && (val === idx || val === value) ) {
        return r;
      } else {
        try {
          var json = JSON.parse(value);
          if ( typeof json[key] === 'object' ? json[key] === val : String(json[key]) === String(val) ) {
            return r;
          }
        } catch ( e ) {}
      }
    }
    return false;
  }

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Element: '_dataview'
   *
   * This is an abstraction layer for Icon, Tree and List views.
   *
   * Events:
   *  select        When an entry was selected (click) => fn(ev)
   *  activate      When an entry was activated (doubleclick) => fn(ev)
   *
   * Parameters:
   *  multiple  boolean     Multiple selection (default=true)
   *
   * Setters:
   *  value         Sets the selected entry(es)
   *  selected      Alias for 'value'
   *
   * Getters:
   *  entry         Gets an entry by value, key
   *  value         Gets the selected entry(es)
   *  selected      Alias for 'value'
   *
   * Actions:
   *  add(arg)      Adds en entry (or from array)
   *  remove(arg)   Removes an entry
   *  patch(arg)    Patch/Update entries from array
   *  clear()
   *
   * @api OSjs.GUI.Elements._dataview
   * @class
   */
  GUI.Elements._dataview = {
    clear: function(el, body) {
      body = body || el;

      Utils.$empty(body);
      body.scrollTop = 0;
      el._selected = [];
    },

    add: function(el, args, oncreate) {
      var entries = args[0];
      if ( !(entries instanceof Array) ) {
        entries = [entries];
      }
      entries.forEach(oncreate);

      return this;
    },

    patch: function(el, args, className, body, oncreate, oninit) {
      var self = this;
      var entries = args[0];
      var single = false;

      if ( !(entries instanceof Array) ) {
        entries = [entries];
        single = true;
      }

      var inView = {};
      body.querySelectorAll(className).forEach(function(row) {
        var id = row.getAttribute('data-id');
        if ( id !== null ) {
          inView[id] = row;
        }
      });

      entries.forEach(function(entry) {
        var insertBefore;
        if ( typeof entry.id !== 'undefined' && entry.id !== null ) {
          if ( inView[entry.id] ) {
            insertBefore = inView[entry.id];
            delete inView[entry.id];
          }

          var row = oncreate(entry);
          if ( row ) {
            if ( insertBefore ) {
              if ( Utils.$hasClass(insertBefore, 'gui-active') ) {
                Utils.$addClass(row, 'gui-active');
              }

              body.insertBefore(row, insertBefore);
              self.remove(el, null, className, insertBefore);
            } else {
              body.appendChild(row);
            }
            oninit(el, row);
          }
        }
      });

      if ( !single ) {
        Object.keys(inView).forEach(function(k) {
          self.remove(el, null, className, inView[k]);
        });
      }

      inView = {};
      this.updateActiveSelection(el, className);

      return this;
    },

    remove: function(el, args, className, target) {
      function remove(cel) {
        Utils.$remove(cel);
      }

      if ( target ) {
        remove(target);
        return;
      }
      if ( typeof args[1] === 'undefined' && typeof args[0] === 'number' ) {
        remove(el.querySelectorAll(className)[args[0]]);
      } else {
        var findId = args[0];
        var findKey = args[1] || 'id';
        var q = 'data-' + findKey + '="' + findId + '"';
        el.querySelectorAll(className + '[' + q + ']').forEach(remove);
      }

      this.updateActiveSelection(el, className);

      return this;
    },

    updateActiveSelection: function(el, className) {
      var active = [];
      el.querySelectorAll(className + '.gui-active').forEach(function(cel) {
        active.push(Utils.$index(cel));
      });
      el._active = active;
    },

    scrollIntoView: function(el, element) {
      var pos = Utils.$position(element, el);
      var marginTop = 0;
      if ( el.tagName.toLowerCase() === 'gui-list-view' ) {
        var header = el.querySelector('gui-list-view-head');
        if ( header ) {
          marginTop = header.offsetHeight;
        }
      }

      var scrollSpace = (el.scrollTop + el.offsetHeight) - marginTop;
      var scrollTop = el.scrollTop + marginTop;
      var elTop = pos.top - marginTop;

      if ( pos !== null && (elTop > scrollSpace || elTop < scrollTop) ) {
        el.scrollTop = elTop;
        return true;
      }

      return false;
    },

    bindEntryEvents: function(el, row, className) {

      var singleClick = el.getAttribute('data-single-click') === 'true';

      function select(ev) {
        ev.stopPropagation();

        var multipleSelect = el.getAttribute('data-multiple');
        multipleSelect = multipleSelect === null || multipleSelect === 'true';
        var idx = Utils.$index(row);
        el._selected = handleItemSelection(ev, row, idx, className, el._selected, el, multipleSelect);
        el.dispatchEvent(new CustomEvent('_select', {detail: {entries: getSelected(el)}}));
      }

      function activate(ev) {
        el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
      }

      function context(ev) {
        select(ev);
        el.dispatchEvent(new CustomEvent('_contextmenu', {detail: {entries: getSelected(el), x: ev.clientX, y: ev.clientY}}));
      }

      function createDraggable() {
        var value = row.getAttribute('data-value');
        if ( value !== null ) {
          try {
            value = JSON.parse(value);
          } catch ( e ) {}
        }

        var source = row.getAttribute('data-draggable-source');
        if ( source === null ) {
          source = GUI.Helpers.getWindowId(el);
          if ( source !== null ) {
            source = {wid: source};
          }
        }

        API.createDraggable(row, {
          type   : el.getAttribute('data-draggable-type') || row.getAttribute('data-draggable-type'),
          source : source,
          data   : value
        });

        var tooltip = row.getAttribute('data-tooltip');
        if ( tooltip && !row.getAttribute('title') ) {
          row.setAttribute('title', tooltip);
        }
      }

      if ( singleClick ) {
        Utils.$bind(row, 'click', function(ev) {
          select(ev);
          activate(ev);
        });
      } else {
        Utils.$bind(row, 'click', select, false);
        Utils.$bind(row, 'dblclick', activate, false);
      }

      Utils.$bind(row, 'contextmenu', function(ev) {
        ev.preventDefault();
        context(ev);
        return false;
      }, false);

      el.dispatchEvent(new CustomEvent('_render', {detail: {
        element: row,
        data: GUI.Helpers.getViewNodeValue(row)
      }}));

      if ( el.getAttribute('data-draggable') === 'true' ) {
        createDraggable();
      }
    },

    getSelected: function(el, entries) {
      var selected = [];
      entries.forEach(function(iter, idx) {
        if ( Utils.$hasClass(iter, 'gui-active') ) {
          selected.push({
            index: idx,
            data: GUI.Helpers.getViewNodeValue(iter)
          });
        }
      });
      return selected;
    },

    getEntry: function(el, entries, val, key) {
      var result = null;
      entries.forEach(function(r, idx) {
        if ( matchValueByKey(r, val, key, idx) ) {
          result = r;
        }
        return !!result;
      });
      return result;
    },

    setSelected: function(el, body, entries, val, key) {
      var self = this;
      var select = [];

      function sel(r, idx) {
        select.push(idx);
        Utils.$addClass(r, 'gui-active');
        //self.scrollIntoView(el, r);
      }

      entries.forEach(function(r, idx) {
        Utils.$removeClass(r, 'gui-active');
        if ( matchValueByKey(r, val, key, idx) ) {
          sel(r, idx);
        }
      });
      el._selected = select;
    },

    build: function(el, applyArgs) {
      el._selected = [];
      el.scrollTop = 0;

      Utils.$addClass(el, 'gui-data-view');

      if ( !el.querySelector('textarea.gui-focus-element') && !el.getAttribute('no-selection') ) {
        var underlay = document.createElement('textarea');
        underlay.setAttribute('readonly', 'true');
        underlay.className = 'gui-focus-element';
        Utils.$bind(underlay, 'focus', function(ev) {
          ev.preventDefault();
          Utils.$addClass(el, 'gui-element-focused');
        });
        Utils.$bind(underlay, 'blur', function(ev) {
          ev.preventDefault();
          Utils.$removeClass(el, 'gui-element-focused');
        });
        Utils.$bind(underlay, 'keydown', function(ev) {
          ev.preventDefault();
          handleKeyPress(el, ev);
        });
        Utils.$bind(underlay, 'keypress', function(ev) {
          ev.preventDefault();
        });

        this.bind(el, 'select', function(ev) {
          if ( Utils.$hasClass(el, 'gui-element-focused') ) {
            return;
          }
          // NOTE: This is a fix for Firefox stupid behaviour when focusing/blurring textboxes
          // (which is used to have a focusable area in this case, called underlay)
          var oldTop = el.scrollTop;
          underlay.focus();
          el.scrollTop = oldTop;
          setTimeout(function() {
            el.scrollTop = oldTop;
          }, 2);
        }, true);

        el.appendChild(underlay);
      }
    },

    focus: function(el) {
      try {
        var underlay = el.querySelector('.gui-focus-element');
        underlay.focus();
      } catch ( e ) {
        console.warn(e, e.stack);
      }
    },

    blur: function(el) {
      try {
        var underlay = el.querySelector('.gui-focus-element');
        underlay.blur();
      } catch ( e ) {
        console.warn(e, e.stack);
      }
    },

    bind: function(el, evName, callback, params) {
      if ( (['activate', 'select', 'expand', 'contextmenu', 'render']).indexOf(evName) !== -1 ) {
        evName = '_' + evName;
      }
      Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
    }

  };

})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2019 OpenCB
 *
 * 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.
 */

import { html, LitElement } from "/web_modules/lit-element.js";
import UtilsNew from "./../../utilsNew.js";
import GridCommons from "../commons/grid-commons.js";

export default class StudyAdminPermissions extends LitElement {

    constructor() {
        super();

        // Set status and init private properties
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            studyId: {
                type: String
            },
            study: {
                type: Object
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);

        this.gridId = this._prefix + "PermissionBrowserGrid";

        this.permissionString = ["VIEW_FILES", "VIEW_FILE_ANNOTATIONS", "WRITE_INDIVIDUALS", "VIEW_COHORTS", "VIEW_FAMILY_ANNOTATIONS",
            "WRITE_FAMILIES", "VIEW_FILE_HEADER", "VIEW_FILE_CONTENT", "VIEW_INDIVIDUALS", "VIEW_AGGREGATED_VARIANTS",
            "VIEW_COHORT_ANNOTATIONS", "WRITE_SAMPLES", "WRITE_CLINICAL_ANALYSIS", "DELETE_JOBS", "EXECUTE_JOBS", "DOWNLOAD_FILES",
            "VIEW_INDIVIDUAL_ANNOTATIONS", "VIEW_PANELS", "VIEW_FAMILIES", "VIEW_JOBS", "WRITE_SAMPLE_ANNOTATIONS", "WRITE_JOBS",
            "VIEW_SAMPLE_VARIANTS", "WRITE_FAMILY_ANNOTATIONS", "VIEW_SAMPLES", "WRITE_INDIVIDUAL_ANNOTATIONS", "VIEW_SAMPLE_ANNOTATIONS",
            "VIEW_CLINICAL_ANALYSIS"];
        this.permissions = [];
        for (const permission of this.permissionString) {
            this.permissions.push(
                {
                    id: permission
                }
            );
        }
    }

    connectedCallback() {
        super.connectedCallback();

        this._config = {...this.getDefaultConfig(), ...this.config};
        this.gridCommons = new GridCommons(this.gridId, this, this._config);
    }

    // Note: WE NEED this function because we are rendering using JQuery not lit-element API
    firstUpdated(changedProperties) {
        if (changedProperties.has("study")) {
            this.studyObserver();
        }
    }

    update(changedProperties) {
        if (changedProperties.has("studyId")) {
            for (const project of this.opencgaSession.projects) {
                for (const study of project.studies) {
                    if (study.id === this.studyId || study.fqn === this.studyId) {
                        this.study = {...study};
                        break;
                    }
                }
            }
        }

        if (changedProperties.has("study")) {
            this.studyObserver();
        }

        super.update(changedProperties);
    }

    studyObserver() {
        this.renderPermissionGrid();
    }

    renderPermissionGrid() {
        this.table = $("#" + this.gridId);
        this.table.bootstrapTable("destroy");
        this.table.bootstrapTable({
            columns: this._getDefaultColumns(),
            data: this.permissions,
            sidePagination: "local",

            // Set table properties, these are read from config property
            uniqueId: "id",
            pagination: this._config.pagination,
            pageSize: this._config.pageSize,
            pageList: this._config.pageList,
            showExport: this._config.showExport,
            detailView: this._config.detailView,
            // detailFormatter: this.detailFormatter,
            formatLoadingMessage: () => "
<loading-spinner></loading-spinner>
",

            onClickRow: (row, selectedElement, field) => this.gridCommons.onClickRow(row.id, row, selectedElement),
            onPostBody: data => {
                // We call onLoadSuccess to select first row
                this.gridCommons.onLoadSuccess({rows: data, total: data.length}, 1);
            }
        });
    }

    groupFormatter(value, row) {
        if (this.field.groupId === "@admins") {
            return `<input type="checkbox" checked disabled>`;
        } else {
            const checked = this.field.acl?.[this.field.groupId]?.includes(row.id);
            return `<input type="checkbox" ${checked ? "checked": ""}>`;
        }
    }

    _getDefaultColumns() {
        let groupColumns = [];
        if (this.study.groups) {
            // Make sure @members and @admins are the last groups
            const groups = this.study.groups.filter(g => g.id !== "@members" && g.id !== "@admins").map(g => g.id);
            groups.push("@members");
            groups.push("@admins");
            for (const group of groups) {
                groupColumns.push(
                    {
                        title: group === "@members" ? "Default" : group,
                        field: {
                            groupId: group,
                            acl: this.study.acl
                        },
                        rowspan: 1,
                        colspan: 1,
                        formatter: this.groupFormatter
                    }
                );
            }
        }

        const _columns = [
            [
                {
                    title: "Study Permission",
                    field: "id",
                    rowspan: 2,
                    colspan: 1,
                },
                {
                    title: "Default",
                    // field: "id",
                    rowspan: 2,
                    colspan: 1,
                },
                {
                    title: "Groups",
                    field: "",
                    rowspan: 1,
                    colspan: groupColumns.length,
                    align: "center"
                },
            ],
            [
                ...groupColumns
            ]
        ];

        return _columns;
    }

    getDefaultConfig() {
        return {
            pagination: true,
            pageSize: 25,
            pageList: [25, 50],
            showExport: false,
            detailView: false,
            detailFormatter: null, // function with the detail formatter
            multiSelection: false,
            showSelectCheckbox: true,
            showToolbar: true,
            showActions: true,
        };
    }

    render() {
        return html`

        `;
    }
}

customElements.define("study-admin-permissions", StudyAdminPermissions);
<commit_msg>wc: implemented filter by study permission<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * 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.
 */

import { html, LitElement } from "/web_modules/lit-element.js";
import UtilsNew from "./../../utilsNew.js";
import GridCommons from "../commons/grid-commons.js";

export default class StudyAdminPermissions extends LitElement {

    constructor() {
        super();

        // Set status and init private properties
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            studyId: {
                type: String
            },
            study: {
                type: Object
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);

        this.gridId = this._prefix + "PermissionBrowserGrid";

        this.permissionString = ["VIEW_FILES", "VIEW_FILE_ANNOTATIONS", "WRITE_INDIVIDUALS", "VIEW_COHORTS", "VIEW_FAMILY_ANNOTATIONS",
            "WRITE_FAMILIES", "VIEW_FILE_HEADER", "VIEW_FILE_CONTENT", "VIEW_INDIVIDUALS", "VIEW_AGGREGATED_VARIANTS",
            "VIEW_COHORT_ANNOTATIONS", "WRITE_SAMPLES", "WRITE_CLINICAL_ANALYSIS", "DELETE_JOBS", "EXECUTE_JOBS", "DOWNLOAD_FILES",
            "VIEW_INDIVIDUAL_ANNOTATIONS", "VIEW_PANELS", "VIEW_FAMILIES", "VIEW_JOBS", "WRITE_SAMPLE_ANNOTATIONS", "WRITE_JOBS",
            "VIEW_SAMPLE_VARIANTS", "WRITE_FAMILY_ANNOTATIONS", "VIEW_SAMPLES", "WRITE_INDIVIDUAL_ANNOTATIONS", "VIEW_SAMPLE_ANNOTATIONS",
            "VIEW_CLINICAL_ANALYSIS"];
        this.permissions = [];
        // for (const permission of this.permissionString) {
        //     this.permissions.push(
        //         {
        //             id: permission
        //         }
        //     );
        // }
        this.permissions = this.permissionString.map(perm => {return { id: perm }})
        this.studyPermissions = this.permissions;
        console.log(this.permissions)
    }

    connectedCallback() {
        super.connectedCallback();

        this._config = { ...this.getDefaultConfig(), ...this.config };
        this.gridCommons = new GridCommons(this.gridId, this, this._config);
    }

    // Note: WE NEED this function because we are rendering using JQuery not lit-element API
    firstUpdated(changedProperties) {
        if (changedProperties.has("study")) {
            this.studyObserver();
        }
    }

    update(changedProperties) {
        if (changedProperties.has("studyId")) {
            for (const project of this.opencgaSession.projects) {
                for (const study of project.studies) {
                    if (study.id === this.studyId || study.fqn === this.studyId) {
                        this.study = { ...study };
                        break;
                    }
                }
            }
        }

        if (changedProperties.has("study")) {
            this.studyObserver();
        }

        super.update(changedProperties);
    }

    studyObserver() {
        this.renderPermissionGrid();
    }

    renderPermissionGrid() {
        this.table = $("#" + this.gridId);
        this.table.bootstrapTable("destroy");
        this.table.bootstrapTable({
            columns: this._getDefaultColumns(),
            data: this.studyPermissions,
            sidePagination: "local",

            // Set table properties, these are read from config property
            uniqueId: "id",
            pagination: this._config.pagination,
            pageSize: this._config.pageSize,
            pageList: this._config.pageList,
            showExport: this._config.showExport,
            detailView: this._config.detailView,
            // detailFormatter: this.detailFormatter,
            formatLoadingMessage: () => "
<loading-spinner></loading-spinner>
",

            onClickRow: (row, selectedElement, field) => this.gridCommons.onClickRow(row.id, row, selectedElement),
            onPostBody: data => {
                // We call onLoadSuccess to select first row
                this.gridCommons.onLoadSuccess({ rows: data, total: data.length }, 1);
            }
        });
    }

    groupFormatter(value, row) {
        if (this.field.groupId === "@admins") {
            return `<input type="checkbox" checked disabled>`;
        } else {
            const checked = this.field.acl?.[this.field.groupId]?.includes(row.id);
            return `<input type="checkbox" ${checked ? "checked" : ""}>`;
        }
    }

    _getDefaultColumns() {
        let groupColumns = [];
        if (this.study.groups) {
            // Make sure @members and @admins are the last groups
            const groups = this.study.groups.filter(g => g.id !== "@members" && g.id !== "@admins").map(g => g.id);
            groups.push("@members");
            groups.push("@admins");
            for (const group of groups) {
                groupColumns.push(
                    {
                        title: group === "@members" ? "Default" : group,
                        field: {
                            groupId: group,
                            acl: this.study.acl
                        },
                        rowspan: 1,
                        colspan: 1,
                        formatter: this.groupFormatter
                    }
                );
            }
        }

        const _columns = [
            [
                {
                    title: "Study Permission",
                    field: "id",
                    rowspan: 2,
                    colspan: 1,
                },
                {
                    title: "Default",
                    // field: "id",
                    rowspan: 2,
                    colspan: 1,
                },
                {
                    title: "Groups",
                    field: "",
                    rowspan: 1,
                    colspan: groupColumns.length,
                    align: "center"
                },
            ],
            [
                ...groupColumns
            ]
        ];

        return _columns;
    }

    getDefaultConfig() {
        return {
            pagination: true,
            pageSize: 25,
            pageList: [25, 50],
            showExport: false,
            detailView: false,
            detailFormatter: null, // function with the detail formatter
            multiSelection: false,
            showSelectCheckbox: true,
            showToolbar: true,
            showActions: true,
        };
    }

    // TODO: we can use this one as search without search button.. if pass 3 character this gonna look the user.
    onPermissionFieldChange(e) {
        this.studyPermission = e.detail.value;
        if (!this.studyPermission) {
            this.studyPermissions = this.permissions;
            this.renderPermissionGrid();
        }
    }

    onPermissionSearch(e) {
        if (this.studyPermission) {
            this.studyPermissions = this.permissions.filter(perm => perm.id.startsWith(this.studyPermission.toUpperCase()));
        } else {
            this.studyPermissions = this.permissions
        }
        this.renderPermissionGrid();
    }

    render() {
        return html`

                        <text-field-filter
                            .value="${this.studyPermission}"
                            placeholder="Search permission"
                            @filterChange="${this.onPermissionFieldChange}">
                        </text-field-filter>

                        <button type="button" id="${this._prefix}SearchPermissionMenu" class="btn btn-default btn-sm ripple"
                                aria-haspopup="true" aria-expanded="false" title="Search study permission"
                                @click="${this.onPermissionSearch}">
                             Search
                        </button>

        `;
    }
}

customElements.define("study-admin-permissions", StudyAdminPermissions);
<|endoftext|>


<commit_before>const massToRadius = mass => Math.log2(mass)/10;

const translate = (object3D, velocity) => {
  object3D.translateX(velocity.x);
  object3D.translateY(velocity.y);
  object3D.translateZ(velocity.z);
}

const rand = (min, max) => min + Math.random()*(max - min);

const vLog = (v, msg) => console.log(msg, JSON.stringify(v.toArray()));

const filterClose = (dancers, position, radius) => (
  dancers.filter(dancer => dancer.position.distanceTo(position) > radius)
);

const vectorToString = vector => {
  return vector.toArray().map(component => +component.toString().slice(0,15)).join(' ')
};

const objToArr = obj => {
  const result = [];
  for (var i = 0; i < obj.length; i++) { result.push(obj[i]); }
  return result;
};

export {
  massToRadius,
  translate,
  rand,
  vLog,
  filterClose,
  vectorToString,
  objToArr,
}
<commit_msg>Add function to get displacement (vR) vector<commit_after>const massToRadius = mass => Math.log2(mass)/10;

const translate = (object3D, velocity) => {
  object3D.translateX(velocity.x);
  object3D.translateY(velocity.y);
  object3D.translateZ(velocity.z);
}

const getR = (body1, body2) => body2.position.sub(body1.position);

const rand = (min, max) => min + Math.random()*(max - min);

const vLog = (v, msg) => console.log(msg, JSON.stringify(v.toArray()));

const filterClose = (dancers, position, radius) => (
  dancers.filter(dancer => dancer.position.distanceTo(position) > radius)
);

const vectorToString = vector => {
  return vector.toArray().map(component => +component.toString().slice(0,15)).join(' ')
};

const objToArr = obj => {
  const result = [];
  for (var i = 0; i < obj.length; i++) { result.push(obj[i]); }
  return result;
};

export {
  massToRadius,
  getR,
  translate,
  rand,
  vLog,
  filterClose,
  vectorToString,
  objToArr,
}
<|endoftext|>


<commit_before>Rickshaw.namespace('Rickshaw.Graph.Axis.Y');

Rickshaw.Graph.Axis.Y = Rickshaw.Class.create( {

	initialize: function(args) {

		this.graph = args.graph;
		this.orientation = args.orientation || 'right';

		this.pixelsPerTick = args.pixelsPerTick || 75;
		if (args.ticks) this.staticTicks = args.ticks;

		this.tickSize = args.tickSize || 4;
		this.ticksTreatment = args.ticksTreatment || 'plain';

		this.tickFormat = args.tickFormat || function(y) { return y };

		this.berthRate = 0.10;

		if (args.element) {

			this.element = args.element;
			this.vis = d3.select(args.element)
				.append("svg:svg")
				.attr('class', 'rickshaw_graph y_axis');

			this.element = this.vis[0][0];
			this.element.style.position = 'relative';

			this.setSize({ width: args.width, height: args.height });

		} else {
			this.vis = this.graph.vis;
		}

		var self = this;
		this.graph.onUpdate( function() { self.render() } );
	},

	setSize: function(args) {

		args = args || {};

		if (!this.element) return;

		if (typeof window !== 'undefined') {

			var style = window.getComputedStyle(this.element.parentNode, null);
			var elementWidth = parseInt(style.getPropertyValue('width'), 10);

			if (!args.auto) {
				var elementHeight = parseInt(style.getPropertyValue('height'), 10);
			}
		}

		this.width = args.width || elementWidth || this.graph.width * this.berthRate;
		this.height = args.height || elementHeight || this.graph.height;

		this.vis
			.attr('width', this.width)
			.attr('height', this.height * (1 + this.berthRate));

		var berth = this.height * this.berthRate;

		if (this.orientation == 'left') {
			this.element.style.top = -1 * berth + 'px';
		}
	},

	render: function() {

		if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });

		this.ticks = this.staticTicks || Math.floor(this.graph.height / this.pixelsPerTick);

		var axis = this._drawAxis(this.graph.y);

		this._drawGrid(axis);

		this._renderHeight = this.graph.height;
	},

	_drawAxis: function(scale) {
		var axis = d3.svg.axis().scale(scale).orient(this.orientation);
		axis.tickFormat(this.tickFormat);

		if (this.orientation == 'left') {
			var berth = this.height * this.berthRate;
			var transform = 'translate(' + this.width + ', ' + berth + ')';
		}

		if (this.element) {
			this.vis.selectAll('*').remove();
		}

		this.vis
			.append("svg:g")
			.attr("class", ["y_ticks", this.ticksTreatment].join(" "))
			.attr("transform", transform)
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));

		return axis;
	},

	_drawGrid: function(axis) {
		var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;

		this.graph.vis
			.append("svg:g")
			.attr("class", "y_grid")
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
	}
} );
<commit_msg>support setting custom tick values, like how we do on the X axis<commit_after>Rickshaw.namespace('Rickshaw.Graph.Axis.Y');

Rickshaw.Graph.Axis.Y = Rickshaw.Class.create( {

	initialize: function(args) {

		this.graph = args.graph;
		this.orientation = args.orientation || 'right';

		this.pixelsPerTick = args.pixelsPerTick || 75;
		if (args.ticks) this.staticTicks = args.ticks;
		if (args.tickValues) this.tickValues = args.tickValues;

		this.tickSize = args.tickSize || 4;
		this.ticksTreatment = args.ticksTreatment || 'plain';

		this.tickFormat = args.tickFormat || function(y) { return y };

		this.berthRate = 0.10;

		if (args.element) {

			this.element = args.element;
			this.vis = d3.select(args.element)
				.append("svg:svg")
				.attr('class', 'rickshaw_graph y_axis');

			this.element = this.vis[0][0];
			this.element.style.position = 'relative';

			this.setSize({ width: args.width, height: args.height });

		} else {
			this.vis = this.graph.vis;
		}

		var self = this;
		this.graph.onUpdate( function() { self.render() } );
	},

	setSize: function(args) {

		args = args || {};

		if (!this.element) return;

		if (typeof window !== 'undefined') {

			var style = window.getComputedStyle(this.element.parentNode, null);
			var elementWidth = parseInt(style.getPropertyValue('width'), 10);

			if (!args.auto) {
				var elementHeight = parseInt(style.getPropertyValue('height'), 10);
			}
		}

		this.width = args.width || elementWidth || this.graph.width * this.berthRate;
		this.height = args.height || elementHeight || this.graph.height;

		this.vis
			.attr('width', this.width)
			.attr('height', this.height * (1 + this.berthRate));

		var berth = this.height * this.berthRate;

		if (this.orientation == 'left') {
			this.element.style.top = -1 * berth + 'px';
		}
	},

	render: function() {

		if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });

		this.ticks = this.staticTicks || Math.floor(this.graph.height / this.pixelsPerTick);

		var axis = this._drawAxis(this.graph.y);

		this._drawGrid(axis);

		this._renderHeight = this.graph.height;
	},

	_drawAxis: function(scale) {
		var axis = d3.svg.axis().scale(scale).orient(this.orientation);
		axis.tickFormat(this.tickFormat);
		if (this.tickValues) axis.tickValues(this.tickValues);

		if (this.orientation == 'left') {
			var berth = this.height * this.berthRate;
			var transform = 'translate(' + this.width + ', ' + berth + ')';
		}

		if (this.element) {
			this.vis.selectAll('*').remove();
		}

		this.vis
			.append("svg:g")
			.attr("class", ["y_ticks", this.ticksTreatment].join(" "))
			.attr("transform", transform)
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));

		return axis;
	},

	_drawGrid: function(axis) {
		var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;

		this.graph.vis
			.append("svg:g")
			.attr("class", "y_grid")
			.call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
	}
} );
<|endoftext|>