<commit_before>// This file is part of Indico.
// Copyright (C) 2002 - 2020 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

/* global ChooseUsersPopup:false */

import Palette from 'indico/utils/palette';

(function($) {
  const FULL_ACCESS_PERMISSIONS = '_full_access';
  const READ_ACCESS_PERMISSIONS = '_read_access';

  $.widget('indico.permissionswidget', {
    options: {
      objectType: null,
      permissionsInfo: null,
    },

    _update() {
      // Sort entries aphabetically and by type
      this.data = _.chain(this.data)
        .sortBy(item => item[0].name || item[0].id)
        .sortBy(item => item[0]._type)
        .value();

      // Sort permissions alphabetically
      this.data.forEach(item => {
        item[1].sort();
      });

      this.$dataField.val(JSON.stringify(this.data));
      this.element.trigger('change');
    },
    _renderRoleCode(code, color) {
      return $('', {
        class: 'role-code',
        text: code,
        css: {
          borderColor: `#${color}`,
          color: `#${color}`,
        },
      });
    },
    _renderLabel(principal) {
      const $labelBox = $('
', {class: 'label-box flexrow f-a-center'});
      const type = principal._type;
      if (type === 'EventRole') {
        $labelBox.append(this._renderEventRoleLabel(principal));
      } else if (type === 'CategoryRole') {
        $labelBox.append(this._renderCategoryRoleLabel(principal));
      } else {
        $labelBox.append(this._renderOtherLabel(principal, type));
      }
      return $labelBox;
    },
    _renderEventRoleLabel(principal) {
      const $text = $('', {
        'class': 'text-normal entry-label',
        'text': principal.name,
        'data-tooltip': principal.name,
      });
      const $code = this._renderRoleCode(principal.code, principal.color);
      return [$code, $text];
    },
    _renderCategoryRoleLabel(principal) {
      const text = principal.name;
      const extraText = principal.category;
      const $code = this._renderRoleCode(principal.code, principal.color);
      const tooltip = `${text} (${extraText})`;
      const textDiv = $('
', {'class': 'text-normal entry-label', 'data-tooltip': tooltip});
      textDiv.append($('', {text: text}));
      textDiv.append('
');
      textDiv.append($('', {class: 'text-not-important entry-label-extra', text: extraText}));
      return [$code, textDiv];
    },
    _renderOtherLabel(principal, type) {
      let iconClass, extraText;
      if (type === 'Avatar') {
        iconClass = 'icon-user';
        extraText = principal.email;
      } else if (type === 'Email') {
        iconClass = 'icon-mail';
      } else if (type === 'DefaultEntry' && principal.id === 'anonymous') {
        iconClass = 'icon-question';
      } else if (type === 'IPNetworkGroup') {
        iconClass = 'icon-lan';
      } else if (type === 'LocalGroup') {
        iconClass = 'icon-users';
      } else if (type === 'MultipassGroup') {
        iconClass = 'icon-users';
        extraText = principal.provider_title;
      } else {
        iconClass = 'icon-users';
      }
      const text = principal.name;
      const tooltip = extraText ? `${text} (${extraText})` : text;
      const textDiv = $('
', {'class': 'text-normal entry-label', 'data-tooltip': tooltip});
      textDiv.append($('', {text}));
      if (extraText) {
        textDiv.append('
');
        textDiv.append(
          $('', {class: 'text-not-important entry-label-extra', text: extraText})
        );
      }
      return [$('', {class: `entry-icon ${iconClass}`}), textDiv];
    },
    _renderPermissions(principal, permissions) {
      const $permissions = $('
', {class: 'permissions-box flexrow f-a-center f-self-stretch'});
      const $permissionsList = $('
').appendTo($permissions);
      // When full access is enabled, always show read access
      if (
        _.contains(permissions, FULL_ACCESS_PERMISSIONS) &&
        !_.contains(permissions, READ_ACCESS_PERMISSIONS)
      ) {
        permissions.push(READ_ACCESS_PERMISSIONS);
        if (principal._type !== 'DefaultEntry') {
          this._updateItem(principal, permissions);
        }
      }
      permissions.forEach(item => {
        const permissionInfo = this.options.permissionsInfo[item];
        const applyOpacity =
          item === READ_ACCESS_PERMISSIONS &&
          _.contains(permissions, FULL_ACCESS_PERMISSIONS) &&
          principal._type !== 'DefaultEntry';
        const cssClasses =
          (applyOpacity ? 'disabled ' : '') +
          (permissionInfo.color ? `color-${permissionInfo.color} ` : '') +
          (permissionInfo.css_class ? `${permissionInfo.css_class} ` : '');
        $permissionsList.append(
          $('
', {
            class: `i-label bold ${cssClasses}`,
            title: permissionInfo.description,
          }).append(permissionInfo.title)
        );
      });
      if (principal._type !== 'DefaultEntry') {
        $permissions.append(this._renderPermissionsButtons(principal, permissions));
      }
      return $permissions;
    },
    _renderPermissionsButtons(principal, permissions) {
      const $buttonsGroup = $('
', {class: 'group flexrow'});
      $buttonsGroup.append(
        this._renderEditBtn(principal, permissions),
        this._renderDeleteBtn(principal)
      );
      return $buttonsGroup;
    },
    _renderEditBtn(principal, permissions) {
      if (principal._type === 'IPNetworkGroup') {
        return $('<button>', {
          type: 'button',
          class: 'i-button text-color borderless icon-only icon-edit disabled',
          title: $T.gettext('IP networks cannot have management permissions'),
        });
      } else {
        return $('<button>', {
          'type': 'button',
          'class': 'i-button text-color borderless icon-only icon-edit',
          'data-href': build_url(Indico.Urls.PermissionsDialog, {type: this.options.objectType}),
          'data-title': $T.gettext('Assign Permissions'),
          'data-method': 'POST',
          'data-ajax-dialog': '',
          'data-params': JSON.stringify({principal: JSON.stringify(principal), permissions}),
        });
      }
    },
    _renderDeleteBtn(principal) {
      const self = this;
      return $('<button>', {
        'type': 'button',
        'class': 'i-button text-color borderless icon-only icon-remove',
        'data-principal': JSON.stringify(principal),
      }).on('click', function() {
        const $this = $(this);
        let confirmed;
        if (principal._type === 'Avatar' && principal.id === $('body').data('user-id')) {
          const title = $T.gettext("Delete entry '{0}'".format(principal.name || principal.id));
          const message = $T.gettext('Are you sure you want to remove yourself from the list?');
          confirmed = confirmPrompt(message, title);
        } else {
          confirmed = $.Deferred().resolve();
        }
        confirmed.then(() => {
          self._updateItem($this.data('principal'), []);
        });
      });
    },
    _renderItem(item) {
      const $item = $('
', {class: 'flexrow f-a-center'});
      const [principal, permissions] = item;
      $item.append(this._renderLabel(principal));
      $item.append(this._renderPermissions(principal, permissions));
      $item.toggleClass(`disabled ${principal.id}`, principal._type === 'DefaultEntry');
      return $item;
    },
    _renderDropdown($dropdown) {
      $dropdown.children(':not(.default)').remove();
      $dropdown.parent().dropdown({
        selector: '.js-dropdown',
      });
      const $dropdownLink = $dropdown.prev('.js-dropdown');
      const items = $dropdown.data('items');
      const isRoleDropdown = $dropdown.hasClass('entry-role-dropdown');
      items.forEach(item => {
        if (this._findEntryIndex(item) === -1) {
          if (isRoleDropdown) {
            $dropdown.find('.separator').before(this._renderDropdownItem(item));
          } else {
            $dropdown.append(this._renderDropdownItem(item));
          }
        }
      });
      if (isRoleDropdown) {
        const isEmpty = !$dropdown.children().not('.default').length;
        $('.entry-role-dropdown .separator').toggleClass('hidden', isEmpty);
      } else if (!$dropdown.children().length) {
        $dropdownLink.addClass('disabled').attr('title', $T.gettext('All IP Networks were added'));
      } else {
        $dropdownLink.removeClass('disabled');
      }
    },
    _renderDropdownItem(principal) {
      const self = this;
      const $dropdownItem = $('
', {
        'class': 'entry-item',
        'data-principal': JSON.stringify(principal),
      });
      const $itemContent = $('');
      if (principal._type === 'EventRole' || principal._type === 'CategoryRole') {
        $itemContent.append(
          this._renderRoleCode(principal.code, principal.color).addClass('dropdown-icon')
        );
      }
      const $text = $('', {text: principal.name});
      $dropdownItem.append($itemContent.append($text)).on('click', function() {
        // Grant read access by default
        self._addItems([$(this).data('principal')], [READ_ACCESS_PERMISSIONS]);
      });
      return $dropdownItem;
    },
    _renderDuplicatesTooltip(idx) {
      this.$permissionsWidgetList
        .find('>li')
        .not('.disabled')
        .eq(idx)
        .qtip({
          content: {
            text: $T.gettext('This entry was already added'),
          },
          show: {
            ready: true,
            effect() {
              $(this).fadeIn(300);
            },
          },
          hide: {
            event: 'unfocus click',
          },
          events: {
            hide() {
              $(this).fadeOut(300);
              $(this).qtip('destroy');
            },
          },
          position: {
            my: 'center left',
            at: 'center right',
          },
          style: {
            classes: 'qtip-warning',
          },
        });
    },
    _render() {
      this.$permissionsWidgetList.empty();
      this.data.forEach(item => {
        this.$permissionsWidgetList.append(this._renderItem(item));
      });
      // Add default entries
      const anonymous = [
        {_type: 'DefaultEntry', name: $T.gettext('Anonymous'), id: 'anonymous'},
        [READ_ACCESS_PERMISSIONS],
      ];
      this.$permissionsWidgetList.append(this._renderItem(anonymous));

      let managersTitle;
      if (this.options.objectType === 'event') {
        managersTitle = $T.gettext('Category Managers');
      } else if (this.options.objectType === 'category') {
        managersTitle = $T.gettext('Parent Category Managers');
      } else {
        managersTitle = $T.gettext('Event Managers');
      }
      const managers = [
        {_type: 'DefaultEntry', name: managersTitle},
        [FULL_ACCESS_PERMISSIONS],
      ];
      this.$permissionsWidgetList.prepend(this._renderItem(managers));
      this.$permissionsWidgetList.find('.anonymous').toggle(!this.isEventProtected);

      if (this.$eventRoleDropdown.length) {
        this._renderDropdown(this.$eventRoleDropdown);
      }
      if (this.$categoryRoleDropdown.length) {
        this._renderDropdown(this.$categoryRoleDropdown);
      }
      if (this.$ipNetworkDropdown.length) {
        this._renderDropdown(this.$ipNetworkDropdown);
      }
    },
    _findEntryIndex(principal) {
      return _.findIndex(this.data, item => item[0].identifier === principal.identifier);
    },
    _updateItem(principal, newPermissions) {
      const idx = this._findEntryIndex(principal);
      if (newPermissions.length) {
        this.data[idx][1] = newPermissions;
      } else {
        this.data.splice(idx, 1);
      }
      this._update();
      this._render();
    },
    _addItems(principals, permissions) {
      const news = [];
      const repeated = [];
      principals.forEach(principal => {
        const idx = this._findEntryIndex(principal);
        if (idx === -1) {
          this.data.push([principal, permissions]);
          news.push(principal);
        } else {
          repeated.push(principal);
        }
      });
      this._update();
      this._render();
      news.forEach(principal => {
        this.$permissionsWidgetList
          .children('li:not(.disabled)')
          .eq(this._findEntryIndex(principal))
          .effect('highlight', {color: Palette.highlight}, 'slow');
      });
      repeated.forEach(principal => {
        this._renderDuplicatesTooltip(this._findEntryIndex(principal));
      });
    },
    _addUserGroup() {
      const _addPrincipals = principals => {
        // Grant read access by default
        this._addItems(principals, [READ_ACCESS_PERMISSIONS]);
      };

      const dialog = new ChooseUsersPopup(
        $T.gettext('Select a user or group to add'),
        true,
        null,
        true,
        true,
        null,
        false,
        false,
        false,
        _addPrincipals,
        null,
        true
      );

      dialog.execute();
    },
    _create() {
      this.$permissionsWidgetList = this.element.find('.permissions-widget-list');
      this.$dataField = this.element.find('input[type=hidden]');
      this.$eventRoleDropdown = this.element.find('.entry-role-dropdown');
      this.$categoryRoleDropdown = this.element.find('.entry-category-role-dropdown');
      this.$ipNetworkDropdown = this.element.find('.entry-ip-network-dropdown');
      this.data = JSON.parse(this.$dataField.val());
      this._update();
      this._render();

      // Manage changes on the permissions dialog
      this.element.on('indico:permissionsChanged', (evt, permissions, principal) => {
        this._updateItem(principal, permissions);
      });

      // Manage changes on the event protection mode field
      this.element.on('indico:protectionModeChanged', (evt, isProtected) => {
        this.isEventProtected = isProtected;
        this._render();
      });

      // Manage the addition to users/groups to the acl
      $('.js-add-user-group').on('click', () => {
        this._addUserGroup();
      });

      // Manage the creation of new roles
      $('.js-new-role').on('ajaxDialog:closed', (evt, data) => {
        if (data && data.role) {
          this.$eventRoleDropdown.data('items').push(data.role);
          this._addItems([data.role], [READ_ACCESS_PERMISSIONS]);
        }
      });

      // Apply ellipsis + tooltip on long names
      this.$permissionsWidgetList.on('mouseenter', '.entry-label', function() {
        const $this = $(this);
        if (this.offsetWidth < this.scrollWidth && !$this.attr('title')) {
          $this.attr('title', $this.attr('data-tooltip'));
        }
      });
    },
  });
})(jQuery);
<commit_msg>Fix incorrect tooltip<commit_after>// This file is part of Indico.
// Copyright (C) 2002 - 2020 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

/* global ChooseUsersPopup:false */

import Palette from 'indico/utils/palette';

(function($) {
  const FULL_ACCESS_PERMISSIONS = '_full_access';
  const READ_ACCESS_PERMISSIONS = '_read_access';

  $.widget('indico.permissionswidget', {
    options: {
      objectType: null,
      permissionsInfo: null,
    },

    _update() {
      // Sort entries aphabetically and by type
      this.data = _.chain(this.data)
        .sortBy(item => item[0].name || item[0].id)
        .sortBy(item => item[0]._type)
        .value();

      // Sort permissions alphabetically
      this.data.forEach(item => {
        item[1].sort();
      });

      this.$dataField.val(JSON.stringify(this.data));
      this.element.trigger('change');
    },
    _renderRoleCode(code, color) {
      return $('', {
        class: 'role-code',
        text: code,
        css: {
          borderColor: `#${color}`,
          color: `#${color}`,
        },
      });
    },
    _renderLabel(principal) {
      const $labelBox = $('
', {class: 'label-box flexrow f-a-center'});
      const type = principal._type;
      if (type === 'EventRole') {
        $labelBox.append(this._renderEventRoleLabel(principal));
      } else if (type === 'CategoryRole') {
        $labelBox.append(this._renderCategoryRoleLabel(principal));
      } else {
        $labelBox.append(this._renderOtherLabel(principal, type));
      }
      return $labelBox;
    },
    _renderEventRoleLabel(principal) {
      const $text = $('', {
        'class': 'text-normal entry-label',
        'text': principal.name,
        'data-tooltip': principal.name,
      });
      const $code = this._renderRoleCode(principal.code, principal.color);
      return [$code, $text];
    },
    _renderCategoryRoleLabel(principal) {
      const text = principal.name;
      const extraText = principal.category;
      const $code = this._renderRoleCode(principal.code, principal.color);
      const tooltip = `${text} (${extraText})`;
      const textDiv = $('
', {'class': 'text-normal entry-label', 'data-tooltip': tooltip});
      textDiv.append($('', {text: text}));
      textDiv.append('
');
      textDiv.append($('', {class: 'text-not-important entry-label-extra', text: extraText}));
      return [$code, textDiv];
    },
    _renderOtherLabel(principal, type) {
      let iconClass, extraText;
      if (type === 'Avatar') {
        iconClass = 'icon-user';
        extraText = principal.email;
      } else if (type === 'Email') {
        iconClass = 'icon-mail';
      } else if (type === 'DefaultEntry' && principal.id === 'anonymous') {
        iconClass = 'icon-question';
      } else if (type === 'IPNetworkGroup') {
        iconClass = 'icon-lan';
      } else if (type === 'LocalGroup') {
        iconClass = 'icon-users';
      } else if (type === 'MultipassGroup') {
        iconClass = 'icon-users';
        extraText = principal.provider_title;
      } else {
        iconClass = 'icon-users';
      }
      const text = principal.name;
      const tooltip = extraText ? `${text} (${extraText})` : text;
      const textDiv = $('
', {'class': 'text-normal entry-label', 'data-tooltip': tooltip});
      textDiv.append($('', {text}));
      if (extraText) {
        textDiv.append('
');
        textDiv.append(
          $('', {class: 'text-not-important entry-label-extra', text: extraText})
        );
      }
      return [$('', {class: `entry-icon ${iconClass}`}), textDiv];
    },
    _renderPermissions(principal, permissions) {
      const $permissions = $('
', {class: 'permissions-box flexrow f-a-center f-self-stretch'});
      const $permissionsList = $('
').appendTo($permissions);
      // When full access is enabled, always show read access
      if (
        _.contains(permissions, FULL_ACCESS_PERMISSIONS) &&
        !_.contains(permissions, READ_ACCESS_PERMISSIONS)
      ) {
        permissions.push(READ_ACCESS_PERMISSIONS);
        if (principal._type !== 'DefaultEntry') {
          this._updateItem(principal, permissions);
        }
      }
      permissions.forEach(item => {
        const permissionInfo = this.options.permissionsInfo[item];
        const applyOpacity =
          item === READ_ACCESS_PERMISSIONS &&
          _.contains(permissions, FULL_ACCESS_PERMISSIONS) &&
          principal._type !== 'DefaultEntry';
        const cssClasses =
          (applyOpacity ? 'disabled ' : '') +
          (permissionInfo.color ? `color-${permissionInfo.color} ` : '') +
          (permissionInfo.css_class ? `${permissionInfo.css_class} ` : '');
        $permissionsList.append(
          $('
', {
            class: `i-label bold ${cssClasses}`,
            title: permissionInfo.description,
          }).append(permissionInfo.title)
        );
      });
      if (principal._type !== 'DefaultEntry') {
        $permissions.append(this._renderPermissionsButtons(principal, permissions));
      }
      return $permissions;
    },
    _renderPermissionsButtons(principal, permissions) {
      const $buttonsGroup = $('
', {class: 'group flexrow'});
      $buttonsGroup.append(
        this._renderEditBtn(principal, permissions),
        this._renderDeleteBtn(principal)
      );
      return $buttonsGroup;
    },
    _renderEditBtn(principal, permissions) {
      if (principal._type === 'IPNetworkGroup') {
        return $('<button>', {
          type: 'button',
          class: 'i-button text-color borderless icon-only icon-edit disabled',
          title: $T.gettext('IP networks cannot have management permissions'),
        });
      } else {
        return $('<button>', {
          'type': 'button',
          'class': 'i-button text-color borderless icon-only icon-edit',
          'data-href': build_url(Indico.Urls.PermissionsDialog, {type: this.options.objectType}),
          'data-title': $T.gettext('Assign Permissions'),
          'data-method': 'POST',
          'data-ajax-dialog': '',
          'data-params': JSON.stringify({principal: JSON.stringify(principal), permissions}),
        });
      }
    },
    _renderDeleteBtn(principal) {
      const self = this;
      return $('<button>', {
        'type': 'button',
        'class': 'i-button text-color borderless icon-only icon-remove',
        'data-principal': JSON.stringify(principal),
      }).on('click', function() {
        const $this = $(this);
        let confirmed;
        if (principal._type === 'Avatar' && principal.id === $('body').data('user-id')) {
          const title = $T.gettext("Delete entry '{0}'".format(principal.name || principal.id));
          const message = $T.gettext('Are you sure you want to remove yourself from the list?');
          confirmed = confirmPrompt(message, title);
        } else {
          confirmed = $.Deferred().resolve();
        }
        confirmed.then(() => {
          self._updateItem($this.data('principal'), []);
        });
      });
    },
    _renderItem(item) {
      const $item = $('
', {class: 'flexrow f-a-center'});
      const [principal, permissions] = item;
      $item.append(this._renderLabel(principal));
      $item.append(this._renderPermissions(principal, permissions));
      $item.toggleClass(`disabled ${principal.id}`, principal._type === 'DefaultEntry');
      return $item;
    },
    _renderDropdown($dropdown) {
      $dropdown.children(':not(.default)').remove();
      $dropdown.parent().dropdown({
        selector: '.js-dropdown',
      });
      const $dropdownLink = $dropdown.prev('.js-dropdown');
      const items = $dropdown.data('items');
      const isRoleDropdown = $dropdown.hasClass('entry-role-dropdown');
      items.forEach(item => {
        if (this._findEntryIndex(item) === -1) {
          if (isRoleDropdown) {
            $dropdown.find('.separator').before(this._renderDropdownItem(item));
          } else {
            $dropdown.append(this._renderDropdownItem(item));
          }
        }
      });
      if (isRoleDropdown) {
        const isEmpty = !$dropdown.children().not('.default').length;
        $('.entry-role-dropdown .separator').toggleClass('hidden', isEmpty);
      } else if (!$dropdown.children().length) {
        $dropdownLink.addClass('disabled').attr('title', $T.gettext('All options have been added'));
      } else {
        $dropdownLink.removeClass('disabled');
      }
    },
    _renderDropdownItem(principal) {
      const self = this;
      const $dropdownItem = $('
', {
        'class': 'entry-item',
        'data-principal': JSON.stringify(principal),
      });
      const $itemContent = $('');
      if (principal._type === 'EventRole' || principal._type === 'CategoryRole') {
        $itemContent.append(
          this._renderRoleCode(principal.code, principal.color).addClass('dropdown-icon')
        );
      }
      const $text = $('', {text: principal.name});
      $dropdownItem.append($itemContent.append($text)).on('click', function() {
        // Grant read access by default
        self._addItems([$(this).data('principal')], [READ_ACCESS_PERMISSIONS]);
      });
      return $dropdownItem;
    },
    _renderDuplicatesTooltip(idx) {
      this.$permissionsWidgetList
        .find('>li')
        .not('.disabled')
        .eq(idx)
        .qtip({
          content: {
            text: $T.gettext('This entry was already added'),
          },
          show: {
            ready: true,
            effect() {
              $(this).fadeIn(300);
            },
          },
          hide: {
            event: 'unfocus click',
          },
          events: {
            hide() {
              $(this).fadeOut(300);
              $(this).qtip('destroy');
            },
          },
          position: {
            my: 'center left',
            at: 'center right',
          },
          style: {
            classes: 'qtip-warning',
          },
        });
    },
    _render() {
      this.$permissionsWidgetList.empty();
      this.data.forEach(item => {
        this.$permissionsWidgetList.append(this._renderItem(item));
      });
      // Add default entries
      const anonymous = [
        {_type: 'DefaultEntry', name: $T.gettext('Anonymous'), id: 'anonymous'},
        [READ_ACCESS_PERMISSIONS],
      ];
      this.$permissionsWidgetList.append(this._renderItem(anonymous));

      let managersTitle;
      if (this.options.objectType === 'event') {
        managersTitle = $T.gettext('Category Managers');
      } else if (this.options.objectType === 'category') {
        managersTitle = $T.gettext('Parent Category Managers');
      } else {
        managersTitle = $T.gettext('Event Managers');
      }
      const managers = [
        {_type: 'DefaultEntry', name: managersTitle},
        [FULL_ACCESS_PERMISSIONS],
      ];
      this.$permissionsWidgetList.prepend(this._renderItem(managers));
      this.$permissionsWidgetList.find('.anonymous').toggle(!this.isEventProtected);

      if (this.$eventRoleDropdown.length) {
        this._renderDropdown(this.$eventRoleDropdown);
      }
      if (this.$categoryRoleDropdown.length) {
        this._renderDropdown(this.$categoryRoleDropdown);
      }
      if (this.$ipNetworkDropdown.length) {
        this._renderDropdown(this.$ipNetworkDropdown);
      }
    },
    _findEntryIndex(principal) {
      return _.findIndex(this.data, item => item[0].identifier === principal.identifier);
    },
    _updateItem(principal, newPermissions) {
      const idx = this._findEntryIndex(principal);
      if (newPermissions.length) {
        this.data[idx][1] = newPermissions;
      } else {
        this.data.splice(idx, 1);
      }
      this._update();
      this._render();
    },
    _addItems(principals, permissions) {
      const news = [];
      const repeated = [];
      principals.forEach(principal => {
        const idx = this._findEntryIndex(principal);
        if (idx === -1) {
          this.data.push([principal, permissions]);
          news.push(principal);
        } else {
          repeated.push(principal);
        }
      });
      this._update();
      this._render();
      news.forEach(principal => {
        this.$permissionsWidgetList
          .children('li:not(.disabled)')
          .eq(this._findEntryIndex(principal))
          .effect('highlight', {color: Palette.highlight}, 'slow');
      });
      repeated.forEach(principal => {
        this._renderDuplicatesTooltip(this._findEntryIndex(principal));
      });
    },
    _addUserGroup() {
      const _addPrincipals = principals => {
        // Grant read access by default
        this._addItems(principals, [READ_ACCESS_PERMISSIONS]);
      };

      const dialog = new ChooseUsersPopup(
        $T.gettext('Select a user or group to add'),
        true,
        null,
        true,
        true,
        null,
        false,
        false,
        false,
        _addPrincipals,
        null,
        true
      );

      dialog.execute();
    },
    _create() {
      this.$permissionsWidgetList = this.element.find('.permissions-widget-list');
      this.$dataField = this.element.find('input[type=hidden]');
      this.$eventRoleDropdown = this.element.find('.entry-role-dropdown');
      this.$categoryRoleDropdown = this.element.find('.entry-category-role-dropdown');
      this.$ipNetworkDropdown = this.element.find('.entry-ip-network-dropdown');
      this.data = JSON.parse(this.$dataField.val());
      this._update();
      this._render();

      // Manage changes on the permissions dialog
      this.element.on('indico:permissionsChanged', (evt, permissions, principal) => {
        this._updateItem(principal, permissions);
      });

      // Manage changes on the event protection mode field
      this.element.on('indico:protectionModeChanged', (evt, isProtected) => {
        this.isEventProtected = isProtected;
        this._render();
      });

      // Manage the addition to users/groups to the acl
      $('.js-add-user-group').on('click', () => {
        this._addUserGroup();
      });

      // Manage the creation of new roles
      $('.js-new-role').on('ajaxDialog:closed', (evt, data) => {
        if (data && data.role) {
          this.$eventRoleDropdown.data('items').push(data.role);
          this._addItems([data.role], [READ_ACCESS_PERMISSIONS]);
        }
      });

      // Apply ellipsis + tooltip on long names
      this.$permissionsWidgetList.on('mouseenter', '.entry-label', function() {
        const $this = $(this);
        if (this.offsetWidth < this.scrollWidth && !$this.attr('title')) {
          $this.attr('title', $this.attr('data-tooltip'));
        }
      });
    },
  });
})(jQuery);
<|endoftext|>


<commit_before>var id;
var callbacks = {};

window.attachEventListener = function(obj, type, func, capture) {
  if(!!obj.addEventListener) {
    obj.addEventListener(type, func, capture);
  }
  else if(!!obj.attachEvent) {
    obj.attachEvent("on" + type, func);
  }
};

var Intents = new (function() {

  this.getAllActions = function () {
    var actions = [];
    for(var key in localStorage) {
      var action = JSON.parse(localStorage[key]);

      if(action instanceof Array) {
        actions.push({ key: key, actions: action });
      }
    }

    return actions;
  };

  this.getActions = function(intent) {
    if(!!intent == false) throw "No intent";
    if(!!intent.action == false) throw "No action to resolve";

    var actionData = localStorage[intent.action] || "[]";
    var actions = JSON.parse(actionData);
    var action;
    var filteredActions = [];
    // Find the actions that are of the correct type (or not).  Does not handle *, yet
    for(var i = 0; action = actions[i]; i++) {
      if(intent.type == action.type || !!intent.type == false) {
        filteredActions.push(action);
      }
    }

    return filteredActions;
  };

  this.addAction = function(intent) {
    if(!!intent == false) throw "No intent";
    if(!!intent.action == false) throw "No action to resolve";

    var actionData = localStorage[intent.action] || "[]";
    var actions = JSON.parse(actionData);
    var action;
    var found = false;

    // Replace an existing action.
    for(var i = 0; action = actions[i]; i++) {
      if(intent.action == action.action && intent.url == action.url && intent.type == action.type) {
        actions[i] = intent;
        found = true;
        break;
      }
    }
    // Add a new action
    if(found == false) {
      actions.push(intent);
    }

    localStorage[intent.action] = JSON.stringify(actions);
  };
})();

var MessageDispatcher = function() {

  this.register = function(data, timestamp, e) {
    Intents.addAction(data.intent);
  };

  this.startActivity = function(data, timestamp, e) {
    var actions = Intents.getActions(data.intent);

    var intentData = {
      id: data.intent._id,
      intent: data.intent,
      timestamp: timestamp
    };

    localStorage[data.intent._id] = JSON.stringify(intentData);
    IntentController.renderActions(actions, data.intent);
  };

  this.registerCallback = function(data, timestamp, e) {
    callbacks[data.id] = {};
  };

  /*
   * The service has sent a response, route it back to the correct frame.
   */
  this.intentResponse = function(data, timestamp, e) {
    var id = data.intent._id;
    var intentData = {
      "request": "sendResponse",
      intent: data.intent,
      timestamp: timestamp
    };
    localStorage[id] = JSON.stringify(intentData);
  };

  /*
   * The correct frame has recieved the reposen, route it back to the parent app.
   */
  this.sendResponse = function(data, timestamp, e) {
    var vals = localStorage[e.key];
    var data = JSON.parse(vals);
    localStorage.removeItem[data.intent._id];
    var message = JSON.stringify({ intent: data.intent, request: "response" });
    window.parent.postMessage(
      message,
      "*"
    );
  };
};

var MessageHandler = function() {
  var dispatcher = new MessageDispatcher();
  this.handler = function(e) {
    var data;
    if(!!e.data) {
      data = JSON.parse(e.data);
    }
    else {
      var vals = localStorage[e.key];
      try {
        data = JSON.parse(vals);
      } catch(ex) {
        return;
      }
    }

    if(data.origin && data.origin !== window.name ||
       data.process && data.process == false) {
      // If there is an intended origin, then enforce it, or the system says not to listen to the event.
      return;
    }

    var timestamp = (new Date()).valueOf();

    if(dispatcher[data.request])
      dispatcher[data.request](data, timestamp, e);
  };
}

var msgHandler = new MessageHandler();;

attachEventListener(window, "message", msgHandler.handler, false);
attachEventListener(window, "storage", msgHandler.handler, false);
<commit_msg>#34 - tidying up for IE support<commit_after>var id;
var callbacks = {};

window.attachEventListener = function(obj, type, func, capture) {
  if(!!obj.addEventListener) {
    obj.addEventListener(type, func, capture);
  }
  else if(!!obj.attachEvent) {
    obj.attachEvent("on" + type, func);
  }
};

var Intents = new (function() {

  this.getAllActions = function () {
    var actions = [];
    for(var key in localStorage) {
      var action = JSON.parse(localStorage[key]);

      if(action instanceof Array) {
        actions.push({ key: key, actions: action });
      }
    }

    return actions;
  };

  this.getActions = function(intent) {
    if(!!intent == false) throw "No intent";
    if(!!intent.action == false) throw "No action to resolve";

    var actionData = localStorage[intent.action] || "[]";
    var actions = JSON.parse(actionData);
    var action;
    var filteredActions = [];
    // Find the actions that are of the correct type (or not).  Does not handle *, yet
    for(var i = 0; action = actions[i]; i++) {
      if(intent.type == action.type || !!intent.type == false) {
        filteredActions.push(action);
      }
    }

    return filteredActions;
  };

  this.addAction = function(intent) {
    if(!!intent == false) throw "No intent";
    if(!!intent.action == false) throw "No action to resolve";

    var actionData = localStorage[intent.action] || "[]";
    var actions = JSON.parse(actionData);
    var action;
    var found = false;

    // Replace an existing action.
    for(var i = 0; action = actions[i]; i++) {
      if(intent.action == action.action && intent.url == action.url && intent.type == action.type) {
        actions[i] = intent;
        found = true;
        break;
      }
    }
    // Add a new action
    if(found == false) {
      actions.push(intent);
    }

    localStorage[intent.action] = JSON.stringify(actions);
  };
})();

var MessageDispatcher = function() {

  this.register = function(data, timestamp, e) {
    Intents.addAction(data.intent);
  };

  this.startActivity = function(data, timestamp, e) {
    var actions = Intents.getActions(data.intent);

    var intentData = {
      id: data.intent._id,
      intent: data.intent,
      timestamp: timestamp
    };

    localStorage[data.intent._id] = JSON.stringify(intentData);
    IntentController.renderActions(actions, data.intent);
  };

  this.registerCallback = function(data, timestamp, e) {
    callbacks[data.id] = {};
  };

  /*
   * The service has sent a response, route it back to the correct frame.
   */
  this.intentResponse = function(data, timestamp, e) {
    var id = data.intent._id;
    var intentData = {
      "request": "sendResponse",
      intent: data.intent,
      timestamp: timestamp
    };
    localStorage[id] = JSON.stringify(intentData);
  };

  /*
   * The correct frame has recieved the reposen, route it back to the parent app.
   */
  this.sendResponse = function(data, timestamp, e) {
    var vals = localStorage[e.key];
    var data = JSON.parse(vals);
    localStorage.removeItem[data.intent._id];
    var message = JSON.stringify({ intent: data.intent, request: "response" });
    window.parent.postMessage(
      message,
      "*"
    );
  };
};

var MessageHandler = function() {
  var dispatcher = new MessageDispatcher();
  this.handler = function(e) {
    var data;
    if(!!e.data) {
      data = JSON.parse(e.data);
    }
    else {
      var vals = localStorage[e.key];
      try {
        data = JSON.parse(vals);
      } catch(ex) {
        return;
      }
    }

    if(data.origin && data.origin !== window.name ||
       data.process && data.process == false) {
      // If there is an intended origin, then enforce it, or the system says not to listen to the event.
      return;
    }

    var timestamp = (new Date()).valueOf();

    if(dispatcher[data.request])
      dispatcher[data.request](data, timestamp, e);
  };
}

var msgHandler = new MessageHandler();;

attachEventListener(window, "message", msgHandler.handler, false);
attachEventListener(window, "storage", msgHandler.handler, false);
attachEventListener(document, "storage", msgHandler.handler, false);
<|endoftext|>


<commit_before>openerp.testing.section('data.model.group_by', {
    rpc: 'mock',
    dependencies: ['web.data'],
}, function (test) {
    var group_result = [{
        bar: 3, bar_count: 5, __context: {}, __domain: [['bar', '=', 3]],
    }, {
        bar: 5, bar_count: 3, __context: {}, __domain: [['bar', '=', 5]],
    }, {
        bar: 8, bar_count: 0, __context: {}, __domain: [['bar', '=', 8]],
    }];
    test('basic', {asserts: 7}, function (instance, $fix, mock) {
        var m = new instance.web.Model('foo');
        mock('foo:read_group', function (args, kwargs) {
            deepEqual(kwargs.fields, ['bar'],
                      "should read grouping field");
            deepEqual(kwargs.groupby, ['bar'],
                      "should have single grouping field");
            return group_result;
        });
        mock('foo:search_read', function (args, kwargs) {
            deepEqual(kwargs.domain, [['bar', '=', 3]],
                      "should have domain matching that of group_by result");
            return [
                {bar: 3, id: 1},
                {bar: 3, id: 2},
                {bar: 3, id: 4},
                {bar: 3, id: 8},
                {bar: 3, id: 16}
            ];
        });

        return m.query().group_by('bar')
        .then(function (groups) {
            ok(groups, "should have data");
            equal(groups.length, 3, "should have three results");
            var first = groups[0];
            ok(first.attributes.has_children, "should have children");
            return  first.query().all();
        }).done(function (first) {
            equal(first.length, 5, "should have 5 records");
        });
    });
    test('noleaf', {asserts: 5}, function (instance, $fix, mock) {
        var m = new instance.web.Model('foo', {group_by_no_leaf: true});
        mock('foo:read_group', function (args, kwargs) {
            deepEqual(kwargs.fields, ['bar'],
                      "should read grouping field");
            deepEqual(kwargs.groupby, ['bar'],
                      "should have single grouping field");

            return  group_result;
        });
        return m.query().group_by('bar')
        .then(function (groups) {
            ok(groups, "should have data");
            equal(groups.length, 3, "should have three results");
            ok(!groups[0].attributes.has_children,
                "should not have children because no_leaf");
        });
    });
    test('nogroup', {rpc: false}, function (instance, $f, mock) {
        var m = new instance.web.Model('foo');
        strictEqual(m.query().group_by(), null, "should not group");
    });
    test('empty.noleaf', {asserts: 1}, function (instance, $f, mock) {
        var m = new instance.web.Model('foo',  {group_by_no_leaf: true});
        mock('foo:read_group', function (args, kwargs) {
            return [{__context: [], __domain: []}];
        });
        return m.query().group_by().done(function (groups) {
            strictEqual(groups.length, 1,
                        "should generate a single fake-ish group");
        });
    });
});
<commit_msg>[FIX] Revert data.js test that was not reverted along with the corresponding patch in previous commit<commit_after>openerp.testing.section('data.model.group_by', {
    rpc: 'mock',
    dependencies: ['web.data'],
}, function (test) {
    var group_result = [{
        bar: 3, bar_count: 5, __context: {}, __domain: [['bar', '=', 3]],
    }, {
        bar: 5, bar_count: 3, __context: {}, __domain: [['bar', '=', 5]],
    }, {
        bar: 8, bar_count: 0, __context: {}, __domain: [['bar', '=', 8]],
    }];
    test('basic', {asserts: 7}, function (instance, $fix, mock) {
        var m = new instance.web.Model('foo');
        mock('foo:read_group', function (args, kwargs) {
            deepEqual(kwargs.fields, ['bar'],
                      "should read grouping field");
            deepEqual(kwargs.groupby, ['bar'],
                      "should have single grouping field");
            return group_result;
        });
        mock('/web/dataset/search_read', function (args) {
            deepEqual(args.params.domain, [['bar', '=', 3]],
                      "should have domain matching that of group_by result");
            return {records: [
                {bar: 3, id: 1},
                {bar: 3, id: 2},
                {bar: 3, id: 4},
                {bar: 3, id: 8},
                {bar: 3, id: 16}
            ], length: 5};
        });

        return m.query().group_by('bar')
        .then(function (groups) {
            ok(groups, "should have data");
            equal(groups.length, 3, "should have three results");
            var first = groups[0];
            ok(first.attributes.has_children, "should have children");
            return  first.query().all();
        }).done(function (first) {
            equal(first.length, 5, "should have 5 records");
        });
    });
    test('noleaf', {asserts: 5}, function (instance, $fix, mock) {
        var m = new instance.web.Model('foo', {group_by_no_leaf: true});
        mock('foo:read_group', function (args, kwargs) {
            deepEqual(kwargs.fields, ['bar'],
                      "should read grouping field");
            deepEqual(kwargs.groupby, ['bar'],
                      "should have single grouping field");

            return  group_result;
        });
        return m.query().group_by('bar')
        .then(function (groups) {
            ok(groups, "should have data");
            equal(groups.length, 3, "should have three results");
            ok(!groups[0].attributes.has_children,
                "should not have children because no_leaf");
        });
    });
    test('nogroup', {rpc: false}, function (instance, $f, mock) {
        var m = new instance.web.Model('foo');
        strictEqual(m.query().group_by(), null, "should not group");
    });
    test('empty.noleaf', {asserts: 1}, function (instance, $f, mock) {
        var m = new instance.web.Model('foo',  {group_by_no_leaf: true});
        mock('foo:read_group', function (args, kwargs) {
            return [{__context: [], __domain: []}];
        });
        return m.query().group_by().done(function (groups) {
            strictEqual(groups.length, 1,
                        "should generate a single fake-ish group");
        });
    });
});
<|endoftext|>


<commit_before>'use strict'

angular.module('antismash.ui.bacterial.as_start', ['ngFileUpload'])
    .controller('AsStartCtrl', ['$state', '$window', 'Upload',
        function ($state, $window, Upload) {
            var vm = this;

            vm.valid_endings = '.gbk,.gb,.gbff,.emb,.embl,.fa,.fasta,.fna';

            // Defaullt values
            vm.submission = {};
            vm.extra_features = [
                { id: 'knownclusterblast', description: 'KnownClusterBlast', default: true },
                { id: 'clusterblast', description: 'ClusterBlast', default: false },
                { id: 'subclusterblast', description: 'SubClusterBlast', default: true },
                { id: 'smcogs', description: 'smCoG analysis', default: true },
                { id: 'asf', description: 'ActiveSiteFinder', default: true },
                { id: 'tta', description: 'Detect TTA codons', default: false },
                { id: 'transatpks_da', description: 'Align Trans-AT PKS domains', default: false },
                { id: 'fullhmmer', description: 'Whole-genome PFAM analysis', default: false },
            ];

            for (var i = 0; i < vm.extra_features.length; i++) {
                var feature = vm.extra_features[i];
                vm.submission[feature.id] = feature.default;
            }

            vm.cf_threshold = 0.6;

            vm.submit = function (form) {
                if (vm.upload_file) {
                    vm.submission.seq = vm.file;
                } else {
                    vm.submission.ncbi = vm.ncbi;
                }

                if (vm.email) {
                    vm.submission.email = vm.email;
                }

                if (vm.clusterfinder) {
                    vm.submission.inclusive = true;
                    vm.submission.cf_threshold = vm.cf_threshold;
                    vm.submission.cf_cdsnr = vm.cf_cdsnr;
                    vm.submission.cf_npfams = vm.cf_npfams;
                }

                Upload.upload({
                    url: '/api/v1.0/submit',
                    data: vm.submission,
                }).then(function (resp) {
                    $state.go('show.job', { id: resp.data.id });
                }, function (resp) {
                    console.log(resp);
                }, function (evt) {
                    var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                    if (!evt.config.data.seq) {
                        return;
                    }
                    console.log('progress: ' + progressPercentage + '% ' + evt.config.data.seq.name);
                });
            }

            vm.validJob = function () {
                if (vm.upload_file) {
                    if (!vm.file) {
                        return false;
                    }
                } else {
                    if (!vm.ncbi) {
                        return false;
                    }
                }
                return true;
            }

            vm.allOff = function () {
                for (var i = 0; i < vm.extra_features.length; i++) {
                    var feature = vm.extra_features[i];
                    vm.submission[feature.id] = false;
                }
            }

            vm.allOn = function () {
                for (var i = 0; i < vm.extra_features.length; i++) {
                    var feature = vm.extra_features[i];
                    vm.submission[feature.id] = true;
                }
            }

            vm.loadSampleInput = function () {
                vm.upload_file = false;
                vm.ncbi = "Y16952";
            }

            vm.openSampleOutput = function () {
                $window.location.href = "/upload/example/index.html";
            }

            vm.loadJob = function () {
                console.log(vm.job_id);
                if (vm.job_id.substr(0, 8).toLowerCase() == 'bacteria') {
                    $state.go('show.job', { id: vm.job_id });
                }
                else if (vm.job_id.substr(0, 5).toLowerCase() == 'fungi') {
                    $window.location.href = "http://fungismash.secondarymetabolites.org/#!/show/job/" + vm.job_id;
                }
                else if (vm.job_id.substr(0, 6).toLowerCase() == 'plants') {
                    $window.location.href = "http://plantismash.secondarymetabolites.org/#!/show/job/" + vm.job_id;
                }
            }
        }]);
<commit_msg>start: Use toggle features that are relevant to fungal inputs<commit_after>'use strict'

angular.module('antismash.ui.bacterial.as_start', ['ngFileUpload'])
    .controller('AsStartCtrl', ['$state', '$window', 'Upload',
        function ($state, $window, Upload) {
            var vm = this;

            vm.valid_endings = '.gbk,.gb,.gbff,.emb,.embl,.fa,.fasta,.fna';

            // Defaullt values
            vm.submission = {};
            vm.extra_features = [
                { id: 'knownclusterblast', description: 'KnownClusterBlast', default: true },
                { id: 'clusterblast', description: 'ClusterBlast', default: false },
                { id: 'subclusterblast', description: 'SubClusterBlast', default: true },
                { id: 'smcogs', description: 'smCoG analysis', default: true },
                { id: 'asf', description: 'ActiveSiteFinder', default: true },
                { id: 'fullhmmer', description: 'Whole-genome PFAM analysis', default: false },
                { id: 'cassis', description: 'Cluster-border prediction based on transcription factor binding sites (CASSIS)', default: false},
            ];

            for (var i = 0; i < vm.extra_features.length; i++) {
                var feature = vm.extra_features[i];
                vm.submission[feature.id] = feature.default;
            }

            vm.cf_threshold = 0.6;

            vm.submit = function (form) {
                if (vm.upload_file) {
                    vm.submission.seq = vm.file;
                } else {
                    vm.submission.ncbi = vm.ncbi;
                }

                if (vm.email) {
                    vm.submission.email = vm.email;
                }

                if (vm.clusterfinder) {
                    vm.submission.inclusive = true;
                    vm.submission.cf_threshold = vm.cf_threshold;
                    vm.submission.cf_cdsnr = vm.cf_cdsnr;
                    vm.submission.cf_npfams = vm.cf_npfams;
                }

                Upload.upload({
                    url: '/api/v1.0/submit',
                    data: vm.submission,
                }).then(function (resp) {
                    $state.go('show.job', { id: resp.data.id });
                }, function (resp) {
                    console.log(resp);
                }, function (evt) {
                    var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                    if (!evt.config.data.seq) {
                        return;
                    }
                    console.log('progress: ' + progressPercentage + '% ' + evt.config.data.seq.name);
                });
            }

            vm.validJob = function () {
                if (vm.upload_file) {
                    if (!vm.file) {
                        return false;
                    }
                } else {
                    if (!vm.ncbi) {
                        return false;
                    }
                }
                return true;
            }

            vm.allOff = function () {
                for (var i = 0; i < vm.extra_features.length; i++) {
                    var feature = vm.extra_features[i];
                    vm.submission[feature.id] = false;
                }
            }

            vm.allOn = function () {
                for (var i = 0; i < vm.extra_features.length; i++) {
                    var feature = vm.extra_features[i];
                    vm.submission[feature.id] = true;
                }
            }

            vm.loadSampleInput = function () {
                vm.upload_file = false;
                vm.ncbi = "Y16952";
            }

            vm.openSampleOutput = function () {
                $window.location.href = "/upload/example/index.html";
            }

            vm.loadJob = function () {
                console.log(vm.job_id);
                if (vm.job_id.substr(0, 8).toLowerCase() == 'bacteria') {
                    $state.go('show.job', { id: vm.job_id });
                }
                else if (vm.job_id.substr(0, 5).toLowerCase() == 'fungi') {
                    $window.location.href = "http://fungismash.secondarymetabolites.org/#!/show/job/" + vm.job_id;
                }
                else if (vm.job_id.substr(0, 6).toLowerCase() == 'plants') {
                    $window.location.href = "http://plantismash.secondarymetabolites.org/#!/show/job/" + vm.job_id;
                }
            }
        }]);
<|endoftext|>


<commit_before>import '../../polyfills/array-find';

const callbacks = [];
let currentMode = null;
let initialized = false;

function callCallbacks(data) {
    callbacks.map((callback) => {
        if(callback && window.chayns.utils.isFunction(callback)) {
            callback(data);
        }
    });
}

function getChangeListener() {
    return function (data) {
        callCallbacks(data);

        currentMode = data;
    };
}

function setDefaultGroup() {
    initialized = true;

    getChangeListener()({
        id: 0
    });

    window.chayns.ui.modeSwitch.changeMode(0);
}

function getUacIds(group) {
    let retval = [];

    if(group.uacId && window.chayns.utils.isNumber(group.uacId)) {
        retval.push(group.uacId);
    }

    if(group.uacIds && window.chayns.utils.isArray(group.uacIds)) {
        retval = retval.concat(group.uacIds);
    }

    return retval;
}

function getAllowedUacIdsFromArray(uacArray) {
    const userGroups = window.chayns.env.user.groups;

    const allowedUacIds = [];

    for (let i = 0, x = userGroups.length; i < x; i += 1) {
        if(uacArray.indexOf(userGroups[i].id) !== -1) {
            allowedUacIds.push(userGroups[i].id);
        }
    }

    return allowedUacIds;
}

function getGroupObject(id, name, uacs) {
    return {
        id,
        uacIds: uacs,
        name
    };
}

function getSavedMode() {
    return window.chayns.utils.ls.get('react__modeSwitch--currentMode');
}

function setSavedMode(mode) {
    return window.chayns.utils.ls.set('react__modeSwitch--currentMode', mode.id);
}

function getDefaultMode() {
    const name = (window.chayns.env.user.isAuthenticated) ? window.chayns.env.user.name : '';

    return getGroupObject(0, name, null);
}

export default class ModeSwitchHelper {
    static init(options) {
        if(options.groups) {
            if(window.chayns.utils.isFunction(options.onChange)) {
                callbacks.push(options.onChange);
            }

            if(options.save) {
                callbacks.push(setSavedMode);
            }

            const allowedGroups = [];

            const groups = [];
            if (options.groups) {
                options.groups.map((element) => {
                    if (window.chayns.utils.isObject(element)) {
                        groups.push(element);
                    } else {
                        groups.push({
                            id: element,
                            uacId: element
                        });
                    }
                });
            }

            if (window.chayns.env.user.isAuthenticated) {
                const groupObject = getGroupObject(0, window.chayns.env.user.name, [0]);
                groupObject.default = true;
                allowedGroups.push(groupObject);

                let savedModeId = null;
                let changeGroupIndex = 0;
                if(options.save) {
                    savedModeId = getSavedMode();
                }

                if(savedModeId === null && options.defaultMode) {
                    savedModeId = options.defaultMode;
                }

                let changeGroup = false;
                let changeGroupValue = null;

                for (let i = 0, x = groups.length; i < x; i += 1) {
                    if (!groups[i].uacId && !groups[i].uacIds) {
                        const addGroupObject = getGroupObject(groups[i].id, groups[i].name, [0]);
                        allowedGroups.push(addGroupObject);

                        if (addGroupObject.id === savedModeId) {
                            changeGroup = true;
                            changeGroupIndex = allowedGroups.length - 1;
                            changeGroupValue = addGroupObject;
                        }
                    } else {
                        const uacIds = getUacIds(groups[i]);
                        const allowedUacs = getAllowedUacIdsFromArray(uacIds);

                        if (allowedUacs.length > 0) {
                            const addGroupObject = getGroupObject(groups[i].id, groups[i].name, allowedUacs);
                            allowedGroups.push(addGroupObject);

                            if (addGroupObject.id === savedModeId) {
                                changeGroup = true;
                                changeGroupIndex = allowedGroups.length - 1;
                                changeGroupValue = addGroupObject;
                            }
                        }
                    }
                }

                if (allowedGroups.length > 1) {
                    window.chayns.ui.modeSwitch.init({
                        items: allowedGroups,
                        callback: getChangeListener()
                    });

                    initialized = true;

                     const getAdminMode = allowedGroups.find((group) => {
                        return group.uacIds.find((id) => {
                            return id === 1;
                        });
                    });

                    if(getAdminMode && getAdminMode.id) {
                        chayns.ready.then((data) => {
                            if(data.AppUser.AdminMode) {
                                window.chayns.ui.modeSwitch.changeMode(getAdminMode.id);
                            }
                        });
                    } else {
                        if (changeGroup) {
                            getChangeListener()(changeGroupValue);

                            window.chayns.ui.modeSwitch.changeMode(changeGroupIndex);
                        } else {
                            setDefaultGroup();
                        }

                        if (changeGroup) { window.setTimeout(() => { window.chayns.ui.modeSwitch.changeMode(changeGroupIndex); }, 0); }
                    }
                } else {
                    setDefaultGroup();
                }
            } else {
                setDefaultGroup();
            }
        } else {
            console.warn('No groups specified');
        }
    }

    static getCurrentMode() {
        if(currentMode) return currentMode;

        return getDefaultMode();
    }

    static onChange(callback) {
        if(window.chayns.utils.isFunction(callback)) {
            callbacks.push(callback);

            return true;
        }

        return false;
    }

    static unregisterOnChange(callback) {
        const index = callbacks.indexOf(callback);

        if (index > -1) {
            callbacks.splice(index, 1);
        }
    }

    static isInitialized() {
        return initialized;
    }

    static hide() {
        window.chayns.ui.modeSwitch.remove();
    }

    static show() {
        window.chayns.ui.modeSwitch.add();
    }

    static isUserInGroup(uacId) {
        if(!window.chayns.env.user.isAuthenticated) return false;

        return !!window.chayns.env.user.groups.find((element) => {
            return element.id === uacId;
        });
    }

    static isChaynsManager() {
        return this.isUserInGroup(1);
    }
}
<commit_msg>Change mode behaviour<commit_after>import '../../polyfills/array-find';

const callbacks = [];
let currentMode = null;
let initialized = false;

function callCallbacks(data) {
    callbacks.map((callback) => {
        if(callback && window.chayns.utils.isFunction(callback)) {
            callback(data);
        }
    });
}

function getChangeListener() {
    return (data) => {
        callCallbacks(data);

        currentMode = data;
    };
}

function setDefaultGroup(mode = 0) {
    initialized = true;

    getChangeListener()({
        id: mode
    });

    window.chayns.ui.modeSwitch.changeMode(0);
}

function getUacIds(group) {
    let retval = [];

    if(group.uacId && window.chayns.utils.isNumber(group.uacId)) {
        retval.push(group.uacId);
    }

    if(group.uacIds && window.chayns.utils.isArray(group.uacIds)) {
        retval = retval.concat(group.uacIds);
    }

    return retval;
}

function getAllowedUacIdsFromArray(uacArray) {
    const userGroups = window.chayns.env.user.groups;

    const allowedUacIds = [];

    for (let i = 0, x = userGroups.length; i < x; i += 1) {
        if(uacArray.indexOf(userGroups[i].id) !== -1) {
            allowedUacIds.push(userGroups[i].id);
        }
    }

    return allowedUacIds;
}

function getGroupObject(id, name, uacs) {
    return {
        id,
        uacIds: uacs,
        name
    };
}

function getSavedMode() {
    return window.chayns.utils.ls.get('react__modeSwitch--currentMode');
}

function setSavedMode(mode) {
    return window.chayns.utils.ls.set('react__modeSwitch--currentMode', mode.id);
}

function getDefaultMode() {
    const name = (window.chayns.env.user.isAuthenticated) ? window.chayns.env.user.name : '';

    return getGroupObject(0, name, null);
}

export default class ModeSwitchHelper {
    static init(options) {
        if(options.groups) {
            if(window.chayns.utils.isFunction(options.onChange)) {
                callbacks.push(options.onChange);
            }

            if(options.save) {
                callbacks.push(setSavedMode);
            }

            const allowedGroups = [];
            let isChaynsIdAdmin = false;

            const groups = [];
            if (options.groups) {
                options.groups.map((element) => {
                    if (window.chayns.utils.isObject(element)) {
                        groups.push(element);
                    } else {
                        groups.push({
                            id: element,
                            uacId: element
                        });
                    }
                });
            }

            chayns.ready.then((data) => {
                if (window.chayns.env.user.isAuthenticated) {
                    // Condition if adminMode ChaynsId
                    let groupObject;
                    const managerGroup = groups.find((uac) => {
                        return uac.uacIds.find(id => id === 1);
                    });

                    const isManager = data.AppUser.UACGroups.find(group => group.id === 1);

                    if(managerGroup && data && data.AppUser.AdminMode) {
                        groupObject = getGroupObject(managerGroup.id, managerGroup.name, [1]);
                        isChaynsIdAdmin = true;
                    } else {
                        groupObject = getGroupObject(0, window.chayns.env.user.name, [0]);
                    }
                    groupObject.default = true;
                    allowedGroups.push(groupObject);

                    let savedModeId = null;
                    let changeGroupIndex = 0;
                    if(options.save) {
                        savedModeId = getSavedMode();
                    }

                    if(savedModeId === null && options.defaultMode) {
                        savedModeId = options.defaultMode;
                    }

                    let changeGroup = false;
                    let changeGroupValue = null;

                    for (let i = 0, x = groups.length; i < x; i += 1) {
                        if (!groups[i].uacId && !groups[i].uacIds) {
                            const addGroupObject = getGroupObject(groups[i].id, groups[i].name, [0]);
                            allowedGroups.push(addGroupObject);

                            if (addGroupObject.id === savedModeId) {
                                changeGroup = true;
                                changeGroupIndex = allowedGroups.length - 1;
                                changeGroupValue = addGroupObject;
                            }
                        } else {
                            const uacIds = getUacIds(groups[i]);
                            const allowedUacs = getAllowedUacIdsFromArray(uacIds);

                            if (allowedUacs.length > 0 && !(allowedUacs.find(uac => uac === 1)) && !isManager) {
                                const addGroupObject = getGroupObject(groups[i].id, groups[i].name, allowedUacs);
                                allowedGroups.push(addGroupObject);

                                if (addGroupObject.id === savedModeId) {
                                    changeGroup = true;
                                    changeGroupIndex = allowedGroups.length - 1;
                                    changeGroupValue = addGroupObject;
                                }
                            }
                        }
                    }

                    if (allowedGroups.length > 1) {
                        window.chayns.ui.modeSwitch.init({
                            items: allowedGroups,
                            callback: getChangeListener()
                        });

                        initialized = true;

                        if (changeGroup) {
                            getChangeListener()(changeGroupValue);

                            window.chayns.ui.modeSwitch.changeMode(changeGroupIndex);
                        } else {
                            setDefaultGroup(isChaynsIdAdmin ? managerGroup.id : 0);
                        }

                        //  if (changeGroup) { window.setTimeout(() => { window.chayns.ui.modeSwitch.changeMode(changeGroupIndex); }, 0); }
                    } else {
                        console.log('default group set');
                        setDefaultGroup(isChaynsIdAdmin ? managerGroup.id : 0);
                    }
                } else {
                    setDefaultGroup();
                }
            });
        } else {
            console.warn('No groups specified');
        }
    }

    static getCurrentMode() {
        if(currentMode) return currentMode;

        return getDefaultMode();
    }

    static onChange(callback) {
        if(window.chayns.utils.isFunction(callback)) {
            callbacks.push(callback);

            return true;
        }

        return false;
    }

    static unregisterOnChange(callback) {
        const index = callbacks.indexOf(callback);

        if (index > -1) {
            callbacks.splice(index, 1);
        }
    }

    static isInitialized() {
        return initialized;
    }

    static hide() {
        window.chayns.ui.modeSwitch.remove();
    }

    static show() {
        window.chayns.ui.modeSwitch.add();
    }

    static isUserInGroup(uacId) {
        if(!window.chayns.env.user.isAuthenticated) return false;

        return !!window.chayns.env.user.groups.find((element) => {
            return element.id === uacId;
        });
    }

    static isChaynsManager() {
        return this.isUserInGroup(1);
    }
}
<|endoftext|>


<commit_before>"use strict";

let EventEmitter = require("events");
let moment = require("moment");
let util = require("util");
let Command = require("../core/commands").Command;

class Polls {
  constructor(database) {
    this.events = new EventEmitter;
    this.db = database;
    this.activePoll = null;
  }

  create(question, options, expires, user) {
    return new Promise((resolve, reject) => {
      if (this.activePoll) {
        throw new Error("Cannot start a new poll when there is another one active");
      }

      this.activePoll = new Poll(question, options, expires, user);
      let col_sql = options.map((option, i) => "option_" + ++i);
      let pm_sql = options.map((option, i) => "$option_" + ++i);

      let sql = util.format("INSERT INTO polls (question, %s, expires, user, nick) \
        VALUES ($question, %s, $expires, $user, $nick)", col_sql, pm_sql);

      let params = {
        $question: question,
        $user: user.user,
        $nick: user.nick,
        // $created: this.activePoll.created,
        $expires: this.activePoll.expires,
      };

      options.forEach((option, i) => {
        params["$option_" + ++i] = option;
      });

      // NOTE: Cannot use an arrow function as we need to access the context for lastID.
      let self = this;
      this.db.run(sql, params, function(error) {
        if (error) {
          self.activePoll = null;
          return reject(error);
        }
        self.activePoll.id = this.lastID;
        self.watchActivePoll();
        return resolve();
      });
    });
  }

  vote(vote, user) {
    if (!this.activePoll) {
      return Promise.reject(new Error("There is no active poll"));
    }
    let options = this.activePoll.options.map(option => option.toLowerCase());
    if (options.indexOf(vote.toLowerCase()) == -1) {
      return Promise.reject(new Error(util.format("Invalid option '%s'", vote)));
    }
    return new Promise((resolve, reject) => {
      let sql = "INSERT INTO polls_votes (question_id, vote, user, nick) VALUES ($question, $vote, $user, $nick)";
      let params = {
        $question: this.activePoll.id,
        $vote: $vote,
        $user: user.user,
        $nick: user.nick,
      };
      this.db.run(sql, params, error => {
        error ? reject(new Error("You have already voted in this poll")) : resolve();
      });
    });
  }

  wait() {
    if (this.activePoll) {
      return this.activePoll.wait().then(stats => {
        this.activePoll = null;
        return stats;
      });
    } else {
      return Promise.reject(new Error("No active poll"));
    }
  }

  _initDatabase() {
    this.db.serialize(() => {
      this.db.run("CREATE TABLE IF NOT EXISTS polls( \
        id INTEGER PRIMARY KEY AUTOINCREMENT, \
        question TEXT NOT NULL, \
        option_1 TEXT NOT NULL, \
        option_2 TEXT NOT NULL, \
        option_3 TEXT NOT NULL, \
        option_4 TEXT NOT NULL, \
        option_5 TEXT NOT NULL, \
        option_6 TEXT NOT NULL, \
        user TEXT NOT NULL, \
        nick TEXT NOT NULL, \
        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \
        expires TIMESTAMP NOT NULL \
      )");
      this.db.run("CREATE TABLE IF NOT EXISTS polls_votes( \
        id INTEGER PRIMARY KEY AUTOINCREMENT, \
        question_id INTEGER NOT NULL, \
        vote TEXT NOT NULL, \
        user TEXT NOT NULL, \
        nick TEXT NOT NULL, \
        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \
        UNIQUE(question_id, user) \
      )");
    });
  }
}

class Poll {
  constructor(question, options, expires, user) {
    this.id = null;
    this.created = new Date;
    this.question = question.replace(/\??$/, "?");
    this.options = options;
    this.expires = expires;
    this.user = user;
    this.votes = [];
  }

  wait() {
    return new Promise((resolve, reject) => {
      let diff = moment(this.expires).diff();

      setTimeout(() => {
        resolve(this.stats);
      }, diff);
    });
  }

  get stats() {
    return new Stats(this)
  }
}

class Stats {
  constructor(poll) {
    this.poll = poll;
  }

  toString() {
    let cache = new Map(this.poll.options.map(option => [option.toLowerCase(), option]));
    let votes = new Map(this.poll.options.map(option => [option, 0]));

    this.votes.forEach(vote => {
      let key = cache.get(vote.toLowerCase());
      votes.set(key, votes.get(key) + 1);
    });

    let output = [...votes.items()]
      .sort((a, b) => a[1] - b[1])
      .map(item => item.join(": "))
      .join(", ");
    return output;
  }

  get votes() {
    return this.poll.votes;
  }
}

exports.configure = (connection, modules) => {
  let commands = connection.commands;
  let polls = new Polls(modules.get("database"));
  let config = connection.config.modules.polls;

  polls._initDatabase();

  connection.addCommand("poll", Command.ALLOW_AUTHED, (user, params, message) => {
    let options = params.slice();
    let question = options.shift();
    let expires = moment().add(options.pop(), "seconds");

    if (!question) {
      return Promise.reject(new Error("Usage: !poll question [options...] [expires]"));
    }

    if (!expires.isAfter(new Date)) {
      expires = moment().add(config.expires, "seconds");
    }

    if (!options.length) {
      options = polls.options.slice();
    }

    return user.whois()
      .then(info => polls.create(question, options, expires, info))
      .then(poll => {
        poll.options.forEach(option => {
          commands.addCommand(option.toLowerCase(), (user, params) => {
            user.whois().then(info => {
              return polls.vote(params.shift(), info).then(() => { }, reject);
            })
          });
        });

        poll.wait().then(stats => {
          message.reply(["Poll finished!", stats.toString()]);
          poll.options.forEach(option => commands.delete(option.toLowerCase()));
        });

        return Promise.resolve("Poll: " + poll.question);
      });
  });

  return polls;
};
<commit_msg>Fix config path<commit_after>"use strict";

let EventEmitter = require("events");
let moment = require("moment");
let util = require("util");
let Command = require("../core/commands").Command;

class Polls {
  constructor(database) {
    this.events = new EventEmitter;
    this.db = database;
    this.activePoll = null;
  }

  create(question, options, expires, user) {
    return new Promise((resolve, reject) => {
      if (this.activePoll) {
        throw new Error("Cannot start a new poll when there is another one active");
      }

      this.activePoll = new Poll(question, options, expires, user);
      let col_sql = options.map((option, i) => "option_" + ++i);
      let pm_sql = options.map((option, i) => "$option_" + ++i);

      let sql = util.format("INSERT INTO polls (question, %s, expires, user, nick) \
        VALUES ($question, %s, $expires, $user, $nick)", col_sql, pm_sql);

      let params = {
        $question: question,
        $user: user.user,
        $nick: user.nick,
        // $created: this.activePoll.created,
        $expires: this.activePoll.expires,
      };

      options.forEach((option, i) => {
        params["$option_" + ++i] = option;
      });

      // NOTE: Cannot use an arrow function as we need to access the context for lastID.
      let self = this;
      this.db.run(sql, params, function(error) {
        if (error) {
          self.activePoll = null;
          return reject(error);
        }
        self.activePoll.id = this.lastID;
        self.watchActivePoll();
        return resolve();
      });
    });
  }

  vote(vote, user) {
    if (!this.activePoll) {
      return Promise.reject(new Error("There is no active poll"));
    }
    let options = this.activePoll.options.map(option => option.toLowerCase());
    if (options.indexOf(vote.toLowerCase()) == -1) {
      return Promise.reject(new Error(util.format("Invalid option '%s'", vote)));
    }
    return new Promise((resolve, reject) => {
      let sql = "INSERT INTO polls_votes (question_id, vote, user, nick) VALUES ($question, $vote, $user, $nick)";
      let params = {
        $question: this.activePoll.id,
        $vote: $vote,
        $user: user.user,
        $nick: user.nick,
      };
      this.db.run(sql, params, error => {
        error ? reject(new Error("You have already voted in this poll")) : resolve();
      });
    });
  }

  wait() {
    if (this.activePoll) {
      return this.activePoll.wait().then(stats => {
        this.activePoll = null;
        return stats;
      });
    } else {
      return Promise.reject(new Error("No active poll"));
    }
  }

  _initDatabase() {
    this.db.serialize(() => {
      this.db.run("CREATE TABLE IF NOT EXISTS polls( \
        id INTEGER PRIMARY KEY AUTOINCREMENT, \
        question TEXT NOT NULL, \
        option_1 TEXT NOT NULL, \
        option_2 TEXT NOT NULL, \
        option_3 TEXT NOT NULL, \
        option_4 TEXT NOT NULL, \
        option_5 TEXT NOT NULL, \
        option_6 TEXT NOT NULL, \
        user TEXT NOT NULL, \
        nick TEXT NOT NULL, \
        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \
        expires TIMESTAMP NOT NULL \
      )");
      this.db.run("CREATE TABLE IF NOT EXISTS polls_votes( \
        id INTEGER PRIMARY KEY AUTOINCREMENT, \
        question_id INTEGER NOT NULL, \
        vote TEXT NOT NULL, \
        user TEXT NOT NULL, \
        nick TEXT NOT NULL, \
        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \
        UNIQUE(question_id, user) \
      )");
    });
  }
}

class Poll {
  constructor(question, options, expires, user) {
    this.id = null;
    this.created = new Date;
    this.question = question.replace(/\??$/, "?");
    this.options = options;
    this.expires = expires;
    this.user = user;
    this.votes = [];
  }

  wait() {
    return new Promise((resolve, reject) => {
      let diff = moment(this.expires).diff();

      setTimeout(() => {
        resolve(this.stats);
      }, diff);
    });
  }

  get stats() {
    return new Stats(this)
  }
}

class Stats {
  constructor(poll) {
    this.poll = poll;
  }

  toString() {
    let cache = new Map(this.poll.options.map(option => [option.toLowerCase(), option]));
    let votes = new Map(this.poll.options.map(option => [option, 0]));

    this.votes.forEach(vote => {
      let key = cache.get(vote.toLowerCase());
      votes.set(key, votes.get(key) + 1);
    });

    let output = [...votes.items()]
      .sort((a, b) => a[1] - b[1])
      .map(item => item.join(": "))
      .join(", ");
    return output;
  }

  get votes() {
    return this.poll.votes;
  }
}

exports.configure = (connection, modules) => {
  let commands = connection.commands;
  let polls = new Polls(modules.get("database"));
  let config = connection.config.modules.polls;

  polls._initDatabase();

  connection.addCommand("poll", Command.ALLOW_AUTHED, (user, params, message) => {
    let options = params.slice();
    let question = options.shift();
    let expires = moment().add(options.pop(), "seconds");

    if (!question) {
      return Promise.reject(new Error("Usage: !poll question [options...] [expires]"));
    }

    if (!expires.isAfter(new Date)) {
      expires = moment().add(config.expires, "seconds");
    }

    if (!options.length) {
      options = config.options.slice();
    }

    return user.whois()
      .then(info => polls.create(question, options, expires, info))
      .then(poll => {
        poll.options.forEach(option => {
          commands.addCommand(option.toLowerCase(), (user, params) => {
            user.whois().then(info => {
              return polls.vote(params.shift(), info).then(() => { }, reject);
            })
          });
        });

        poll.wait().then(stats => {
          message.reply(["Poll finished!", stats.toString()]);
          poll.options.forEach(option => commands.delete(option.toLowerCase()));
        });

        return Promise.resolve("Poll: " + poll.question);
      });
  });

  return polls;
};
<|endoftext|>


<commit_before>var resourceKeyFunc = {
  "identity": {
    allocPartitions: allocNumPartitions
  },
  "hash-crc32": {
    allocPartitions: allocNumPartitions
  },
  "range": {
    allocPartitions: function(req) {
      return _.reduce((req.lastPartitionMap && req.lastPartitionMap.partitions) || {},
                      function(res, partition, partitionId) {
                        res[partitionId] = {};
                        return res;
                      }, {});
    }
  }
};

function allocNumPartitions(req) {
  var res = {};
  for (var i = 0; i < req.wantPartitionParams.numPartitions; i++) {
    res[i.toString()] = {};
  }
  return res;
}
<commit_msg>clonePartitions() helper func.<commit_after>var resourceKeyFunc = {
  "identity": {
    allocPartitions: clonePartitions
  },
  "hash-crc32": {
    allocPartitions: allocNumPartitions
  },
  "range": {
    allocPartitions: clonePartitions
  }
};

function clonePartitions(req) {
  return _.reduce((req.lastPartitionMap && req.lastPartitionMap.partitions) ||
                  req.initPartitions || {},
                  function(res, partition, partitionId) {
                    res[partitionId] = {};
                    return res;
                  }, {});
}

function allocNumPartitions(req) {
  var res = {};
  for (var i = 0; i < req.wantPartitionParams.numPartitions; i++) {
    res[i.toString()] = {};
  }
  return res;
}
<|endoftext|>


<commit_before>'use strict';

angular.module('todosModule', ['obscureLocalStorageModule', 'userModule'])
  .factory('todoFactory', function() {
    return {
      create: function() {

        var date = new Date();
        var id = CryptoJS.SHA256(date.toJSON()).toString();

        return {
          id: id,
          text: '',
          notes: '',
          done:false,
          priority: 0,
          createdBy: '',
          createdDate: date.toString(),
          dueDate: null,
          startedDate: null,
          finishedDate: null
        };
      }
    };
  })
  .service('todosService', function(obscureLocalStorageService) {
    this.todos = [];

    this.getTodos = function() {
      return this.todos;
    }

    this.getTodo = function(id) {
      return _.find(this.todos, function(obj) { return obj.id === id })
    }

    this.count = function() {
      return this.todos.length;
    };

    this.countDone = function() {
      var count = 0;
      angular.forEach(this.todos, function(todo) {
        count += todo.done ? 1 : 0;
      });
      return count;
    };

    this.deleteAll = function() {
      obscureLocalStorageService.clearAll();
      this.todos = [];
      return this.todos;
    };

    this.todoToString = function(todo) {
      return JSON.stringify(todo);
    }

    this.todoFromString = function(todoStr) {
      var todo = JSON.parse(todoStr);
      if(todo.dueDate) {
        todo.dueDate = new Date(todo.dueDate);
      }
      return todo;
    }

    this.loadFromLocalStorageService = function() {

      this.todos = []

      var keys = obscureLocalStorageService.keys();
      for (var i in keys) {

        var key = keys[i];
        var todoStr = obscureLocalStorageService.get(key);
        var todo = this.todoFromString(todoStr);

        this.todos.push(todo);
      }

      return this.todos;
    };

    this.saveTodo = function(todo) {
      var id = todo.id;
      var todoStr = this.todoToString(todo);

      obscureLocalStorageService.add(id, todoStr);
    };

    this.addTodo = function(todo) {
      this.todos.push(todo);
      this.saveTodo(todo);
    };

    this.removeTodo = function(todo) {
      obscureLocalStorageService.remove(todo.key);
    }
  })
  .directive('todosNavbar', function () {
    return {
      restrict: 'A',
      templateUrl: 'todos/todos_navbar.html'
    };
  })
  .directive('todosAdmin', function () {
    return {
      restrict: 'A',
      templateUrl: 'todos/todos_admin.html'
    };
  });

function TodosCtrl($scope, $location, userService, todoFactory, todosService) {

  $scope.todos = [];
  $scope.positiveMessage = 'You did it!'

  $scope.init = function() {
    if (userService.userIsNull()) {
      $location.path('/');
      return;
    }

    $scope.todos = todosService.loadFromLocalStorageService();
  };

  $scope.isUser = function() {
    return userService.name();
  };

  $scope.count = function() {
    return todosService.count();
  };

  $scope.addTodo = function() {

    if ($scope.newTodoText.length === 0) {
      return
    }

    var todo = todoFactory.create();
    todo.text = $scope.newTodoText;
    todo.createdBy = userService.name();

    todosService.addTodo(todo);
    $scope.newTodoText = '';
  };

  $scope.editTodo = function(todo) {
    $location.path('/todo/' + todo.id.toString());
  };

  $scope.viewPrintTodos = function() {
    $location.path('/print/todos');
  };

  $scope.setStartedDate = function(todo) {
    todo.startedDate = new Date().toString();
    todosService.saveTodo(todo);
  };

  $scope.setFinishedDate = function(todo) {
    todo.finishedDate = new Date().toString();
    todosService.saveTodo(todo);
  };

  $scope.setDone = function(todo, done) {
    if(done) {
      $scope.setFinishedDate(todo);
      todo.done = true;
      todosService.saveTodo(todo);
    }
    else {
      todo.finishedDate = null;
      todo.done = false;
      todosService.saveTodo(todo);
    }
  }

  $scope.hasNotes = function(todo) {
    return (todo.notes && todo.notes.length !== 0)
  }

  $scope.clearTodos = function () {
    $scope.todos = todosService.deleteAll();
  };

  $scope.remaining = function() {
    return todosService.count() - todosService.countDone();
  };

  $scope.archive = function() {
    var oldTodos = $scope.todos;
    $scope.todos = [];
    angular.forEach(oldTodos, function(todo) {
      if (!todo.done) {
        $scope.todos.push(todo);
      }
      else {
        todosService.removeTodo(todo);
      }
    });
  };
}

function TodoCtrl($scope, $routeParams, $location, $log, todosService) {

  $scope.todoId = $routeParams.todoId

  $scope.init = function() {
    todosService.loadFromLocalStorageService();
    $scope.todo = todosService.getTodo($scope.todoId);
  };

  $scope.save = function() {
    todosService.saveTodo($scope.todo);
    $location.path('/todos');
  };

  $scope.cancel = function() {
    $location.path('/todos');
  };

  $scope.hasNotes = function() {
    return ($scope.todo.notes && $scope.todo.notes.length !== 0)
  };

};
<commit_msg>Only parse string if it is a string.<commit_after>'use strict';

angular.module('todosModule', ['obscureLocalStorageModule', 'userModule'])
  .factory('todoFactory', function() {
    return {
      create: function() {

        var date = new Date();
        var id = CryptoJS.SHA256(date.toJSON()).toString();

        return {
          id: id,
          text: '',
          notes: '',
          done:false,
          priority: 0,
          createdBy: '',
          createdDate: date.toString(),
          dueDate: null,
          startedDate: null,
          finishedDate: null
        };
      }
    };
  })
  .service('todosService', function(obscureLocalStorageService) {
    this.todos = [];

    this.getTodos = function() {
      return this.todos;
    }

    this.getTodo = function(id) {
      return _.find(this.todos, function(obj) { return obj.id === id })
    }

    this.count = function() {
      return this.todos.length;
    };

    this.countDone = function() {
      var count = 0;
      angular.forEach(this.todos, function(todo) {
        count += todo.done ? 1 : 0;
      });
      return count;
    };

    this.deleteAll = function() {
      obscureLocalStorageService.clearAll();
      this.todos = [];
      return this.todos;
    };

    this.todoToString = function(todo) {
      return JSON.stringify(todo);
    }

    this.todoFromString = function(todoStr) {
      var todo = todoStr;

      if ('string' === typeof todoStr) {
        todo = JSON.parse(todoStr);
      }

      if(todo.dueDate) {
        todo.dueDate = new Date(todo.dueDate);
      }
      return todo;
    }

    this.loadFromLocalStorageService = function() {

      this.todos = []

      var keys = obscureLocalStorageService.keys();
      for (var i in keys) {

        var key = keys[i];
        var todoStr = obscureLocalStorageService.get(key);
        var todo = this.todoFromString(todoStr);

        this.todos.push(todo);
      }

      return this.todos;
    };

    this.saveTodo = function(todo) {
      var id = todo.id;
      var todoStr = this.todoToString(todo);

      obscureLocalStorageService.add(id, todoStr);
    };

    this.addTodo = function(todo) {
      this.todos.push(todo);
      this.saveTodo(todo);
    };

    this.removeTodo = function(todo) {
      obscureLocalStorageService.remove(todo.key);
    }
  })
  .directive('todosNavbar', function () {
    return {
      restrict: 'A',
      templateUrl: 'todos/todos_navbar.html'
    };
  })
  .directive('todosAdmin', function () {
    return {
      restrict: 'A',
      templateUrl: 'todos/todos_admin.html'
    };
  });

function TodosCtrl($scope, $location, userService, todoFactory, todosService) {

  $scope.todos = [];
  $scope.positiveMessage = 'You did it!'

  $scope.init = function() {
    if (userService.userIsNull()) {
      $location.path('/');
      return;
    }

    $scope.todos = todosService.loadFromLocalStorageService();
  };

  $scope.isUser = function() {
    return userService.name();
  };

  $scope.count = function() {
    return todosService.count();
  };

  $scope.addTodo = function() {

    if ($scope.newTodoText.length === 0) {
      return
    }

    var todo = todoFactory.create();
    todo.text = $scope.newTodoText;
    todo.createdBy = userService.name();

    todosService.addTodo(todo);
    $scope.newTodoText = '';
  };

  $scope.editTodo = function(todo) {
    $location.path('/todo/' + todo.id.toString());
  };

  $scope.viewPrintTodos = function() {
    $location.path('/print/todos');
  };

  $scope.setStartedDate = function(todo) {
    todo.startedDate = new Date().toString();
    todosService.saveTodo(todo);
  };

  $scope.setFinishedDate = function(todo) {
    todo.finishedDate = new Date().toString();
    todosService.saveTodo(todo);
  };

  $scope.setDone = function(todo, done) {
    if(done) {
      $scope.setFinishedDate(todo);
      todo.done = true;
      todosService.saveTodo(todo);
    }
    else {
      todo.finishedDate = null;
      todo.done = false;
      todosService.saveTodo(todo);
    }
  }

  $scope.hasNotes = function(todo) {
    return (todo.notes && todo.notes.length !== 0)
  }

  $scope.clearTodos = function () {
    $scope.todos = todosService.deleteAll();
  };

  $scope.remaining = function() {
    return todosService.count() - todosService.countDone();
  };

  $scope.archive = function() {
    var oldTodos = $scope.todos;
    $scope.todos = [];
    angular.forEach(oldTodos, function(todo) {
      if (!todo.done) {
        $scope.todos.push(todo);
      }
      else {
        todosService.removeTodo(todo);
      }
    });
  };
}

function TodoCtrl($scope, $routeParams, $location, $log, todosService) {

  $scope.todoId = $routeParams.todoId

  $scope.init = function() {
    todosService.loadFromLocalStorageService();
    $scope.todo = todosService.getTodo($scope.todoId);
  };

  $scope.save = function() {
    todosService.saveTodo($scope.todo);
    $location.path('/todos');
  };

  $scope.cancel = function() {
    $location.path('/todos');
  };

  $scope.hasNotes = function() {
    return ($scope.todo.notes && $scope.todo.notes.length !== 0)
  };

};
<|endoftext|>


<commit_before>/* Copyright (c) 2013-2016 The TagSpaces Authors.
 * Use of this source code is governed by the MIT license which can be found in the LICENSE.txt file. */

define(function(require, exports, module) {
  "use strict";

  var extensionID = "editorHTML"; // ID should be equal to the directory name where the ext. is located
  var extensionSupportedFileTypes = ["html", "htm"];

  console.log("Loading " + extensionID);

  var TSCORE = require("tscore");
  var extensionsPath = TSCORE.Config.getExtensionPath();
  var extensionDirectory = extensionsPath + "/" + extensionID;
  var fileDirectory;
  var currentContent;
  var currentFilePath;
  var $containerElement;
  var contentVersion = 0;
  var sourceURL = "";
  var scrappedOn = "";

  function init(filePath, containerElementID) {
    console.log("Initalization HTML Editor...");

    fileDirectory = TSCORE.TagUtils.extractContainingDirectoryPath(filePath);

    $containerElement = $('#' + containerElementID);

    currentFilePath = filePath;

    $containerElement.empty();
    $containerElement.css("background-color", "white");

    var extPath = extensionDirectory + "/index.html";
    $containerElement.append($('', {
      id: "iframeViewer",
      sandbox: "allow-same-origin allow-scripts allow-modals",
      scrolling: "no",
      style: "background-color: white; overflow: hidden;",
      src: extPath + "?cp=" + filePath + "&setLng=" + TSCORE.currentLanguage,
      "nwdisable": "",
      "nwfaketop": ""
    }));

    TSCORE.IO.loadTextFilePromise(filePath).then(function(content) {
              //TSPOSTIO.loadTextFile(content);
              exports.setContent(content);
            },
            function(error) {
              TSCORE.hideLoadingAnimation();
              TSCORE.showAlertDialog("Loading " + filePath + " failed.");
              console.error("Loading file " + filePath + " failed " + error);
            }
    );
  }

  function setFileType(fileType) {

    console.log("setFileType not supported on this extension");
  }

  function viewerMode(isViewerMode) {
    // set readonly
    console.log("viewerMode not supported on this extension");
  }

  function setContent(content) {
    currentContent = content;

    var bodyContent;
    var cleanedBodyContent;
    var bodyRegex = /\]*\>([^]*)\<\/body/m; // jshint ignore:line

    if (content.length > 3) {
      try {
        bodyContent = content.match(bodyRegex)[1];
      } catch (e) {
        console.log("Error parsing the body of the HTML document. " + e);
        bodyContent = content;
      }

      try {
        var scrappedOnRegex = /data-scrappedon='([^']*)'/m; // jshint ignore:line
        scrappedOn = content.match(scrappedOnRegex)[1];
      } catch (e) {
        console.log("Error parsing the meta from the HTML document. " + e);
      }

      try {
        var sourceURLRegex = /data-sourceUrl='([^']*)'/m; // jshint ignore:line
        sourceURL = content.match(sourceURLRegex)[1];
      } catch (e) {
        console.log("Error parsing the meta from the HTML document. " + e);
      }

      //var titleRegex = /\<title[^>]*\>([^]*)\<\/title/m;
      //var titleContent = content.match( titleRegex )[1];

      // removing all scripts from the document
    } else {
      currentContent = TSCORE.Config.DefaultSettings.newHTMLFileContent;
      bodyContent = currentContent.match(bodyRegex)[1];
    }
    cleanedBodyContent = bodyContent.replace(/


<commit_before>import React, { PropTypes } from 'react'

import styles from './index.css'

const Tooltip = ({ children, content, tagName: Component = 'span' }) => (
  <Component className={styles.container}>

      {content}

    {children}
  </Component>
)

Tooltip.propTypes = {
  children: PropTypes.any.isRequired,
  content: PropTypes.any.isRequired,
  tagName: PropTypes.string
}

export { Tooltip as default }
<commit_msg>feat(Tooltip): children prop is optional<commit_after>import React, { PropTypes } from 'react'

import styles from './index.css'

const Tooltip = ({ children, content, tagName: Component = 'span' }) => (
  <Component className={styles.container}>

      {content}

    {children}
  </Component>
)

Tooltip.propTypes = {
  children: PropTypes.any,
  content: PropTypes.any.isRequired,
  tagName: PropTypes.string
}

export { Tooltip as default }
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var util = require('../util');
var gutil = require('gulp-util');

module.exports = function (etalonName) {
  return function (data) {
    var total = util.total(data);
    var split = util.split(total);
    var passed = util.sortFastestFirst(split.passed);
    var failed = split.failed;

    var etalonIndex = _.isString(etalonName)? _.pluck(passed, 'name').indexOf(etalonName): 0;
    var etalon = (etalonIndex < 0)? passed[0]: passed[etalonIndex];
    var etalonHz = etalon? etalon.hz: 0;

    gutil.log(util.indent(1) + util.caption(data) + ' (' + gutil.colors.green('passed') + ': ' + passed.length + ' ,' +
                                                           gutil.colors.red('failed') + ': ' + failed.length + ')');

    if (passed.length > 0) {
      gutil.log(util.indent(2) + gutil.colors.green('Passed') + ':');

      passed.forEach(function (test, index) {
        var output = util.indent(3) + '\'' + test.name + '\'';

        if (index < etalonIndex) {
          output += ' at ' + (test.hz / etalonHz).toFixed(2) + 'x faster';
        }
        else if (index > etalonIndex) {
          output += ' at ' + (etalonHz / test.hz).toFixed(2) + 'x slower';
        }
        else {
          output += ' is etalon';
          output = gutil.colors.yellow(output);
        }

        gutil.log(output);
      });
    }

    if (failed.length > 0) {
      gutil.log(util.indent(2) + gutil.colors.red('Failed') + ':');

      failed.forEach(function (test) {
        gutil.log(util.indent(3) + test.name + ': ' + test.error);
      });
    }
  };
};
<commit_msg>Fix typo in etalon reporter<commit_after>'use strict';

var _ = require('lodash');
var util = require('../util');
var gutil = require('gulp-util');

module.exports = function (etalonName) {
  return function (data) {
    var total = util.total(data);
    var split = util.split(total);
    var passed = util.sortFastestFirst(split.passed);
    var failed = split.failed;

    var etalonIndex = _.isString(etalonName)? _.pluck(passed, 'name').indexOf(etalonName): 0;
    var etalon = (etalonIndex < 0)? passed[0]: passed[etalonIndex];
    var etalonHz = etalon? etalon.hz: 0;

    gutil.log(util.indent(1) + util.caption(data) + ' (' + gutil.colors.green('passed') + ': ' + passed.length + ', ' +
                                                           gutil.colors.red('failed') + ': ' + failed.length + ')');

    if (passed.length > 0) {
      gutil.log(util.indent(2) + gutil.colors.green('Passed') + ':');

      passed.forEach(function (test, index) {
        var output = util.indent(3) + '\'' + test.name + '\'';

        if (index < etalonIndex) {
          output += ' at ' + (test.hz / etalonHz).toFixed(2) + 'x faster';
        }
        else if (index > etalonIndex) {
          output += ' at ' + (etalonHz / test.hz).toFixed(2) + 'x slower';
        }
        else {
          output += ' is etalon';
          output = gutil.colors.yellow(output);
        }

        gutil.log(output);
      });
    }

    if (failed.length > 0) {
      gutil.log(util.indent(2) + gutil.colors.red('Failed') + ':');

      failed.forEach(function (test) {
        gutil.log(util.indent(3) + test.name + ': ' + test.error);
      });
    }
  };
};
<|endoftext|>