<commit_before>'use strict';

/* global _ */

/* Stage Controller */

angular.module('septWebRadioControllers')
  .controller('StageCtrl', ['$scope', 'soundcloudSearch', 'utilities', '$modal', '$log', 'Page',
    function ($scope, soundcloudSearch, utilities, $modal, $log, Page) {
      $scope.isSearching = false;
      $scope.searchedTerm = undefined;
      $scope.searchedItems = [];
      $scope.playlists = [
        {id: 1, title: 'Playlist 1'},
        {id: 2, title: 'Playlist 2'},
        {id: 3, title: 'Playlist 3'},
        {id: 4, title: 'Playlist 4'},
        {id: 5, title: 'Playlist 5'}
      ];
      $scope.selectedPlaylists = [];
      $scope.list1 = [];
      Page.setTitle('Stage');

      $scope.search = function () {
        // If there is a term to search
        if ($scope.searchedTerm && $scope.searchedTerm !== '' && $scope.searchedTerm.length >= 2) {
          $scope.isSearching = true;

          // Search the terms
          soundcloudSearch.autoCompleteSearch($scope.searchedTerm)
            .then(function (response) {
              $scope.searchedItems = utilities.unionWithId($scope.searchedItems, response);
              $scope.isSearching = false;
            });
        } else {
          // There is nothing to search
          $scope.isSearching = false;
          $scope.searchedItems.splice(0, $scope.searchedItems.length);
        }
      };

      $scope.dropped = function (droppedItems) {
        var scopeItems = [];

        angular.forEach(droppedItems, function (valueId) {
          valueId = parseInt(valueId);
          var item = _.find($scope.searchedItems, function (listItem) {
            return valueId === parseInt(listItem.id);
          });

          this.push(item);
        }, scopeItems);

        $scope.open(scopeItems);
      };

      $scope.togglePlaylist = function (playlistId) {
        // If the playlist is not here, wee add it
        if (_.indexOf($scope.selectedPlaylists, playlistId) === -1) {
          $scope.selectedPlaylists.push(playlistId);
        } else {
          // Else, we remove it
          $scope.selectedPlaylists = _.without($scope.selectedPlaylists, playlistId);
        }
      };

      $scope.open = function (items) {
        var modalInstance = $modal.open({
          templateUrl: 'myModalContent.html',
          controller: ModalInstanceCtrl,
          resolve: {
            items: function () {
              return items;
            }
          }
        });

        modalInstance.result.then(function (selectedItem) {
          $scope.selected = selectedItem;
        }, function () {
          $log.info('Modal dismissed at: ' + new Date());
        });
      };

      var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
        $scope.items = items;
        $scope.ok = function () {
          $modalInstance.close($scope.items);
        };
        $scope.cancel = function () {
          $modalInstance.dismiss('cancel');
        };
      };
    }]
  );<commit_msg>Remove playlist 4<commit_after>'use strict';

/* global _ */

/* Stage Controller */

angular.module('septWebRadioControllers')
  .controller('StageCtrl', ['$scope', 'soundcloudSearch', 'utilities', '$modal', '$log', 'Page',
    function ($scope, soundcloudSearch, utilities, $modal, $log, Page) {
      $scope.isSearching = false;
      $scope.searchedTerm = undefined;
      $scope.searchedItems = [];
      $scope.playlists = [
        {id: 1, title: 'Playlist 1'},
        {id: 2, title: 'Playlist 2'},
        {id: 3, title: 'Playlist 3'},
        {id: 4, title: 'Playlist 4'}
      ];
      $scope.selectedPlaylists = [];
      $scope.list1 = [];
      Page.setTitle('Stage');

      $scope.search = function () {
        // If there is a term to search
        if ($scope.searchedTerm && $scope.searchedTerm !== '' && $scope.searchedTerm.length >= 2) {
          $scope.isSearching = true;

          // Search the terms
          soundcloudSearch.autoCompleteSearch($scope.searchedTerm)
            .then(function (response) {
              $scope.searchedItems = utilities.unionWithId($scope.searchedItems, response);
              $scope.isSearching = false;
            });
        } else {
          // There is nothing to search
          $scope.isSearching = false;
          $scope.searchedItems.splice(0, $scope.searchedItems.length);
        }
      };

      $scope.dropped = function (droppedItems) {
        var scopeItems = [];

        angular.forEach(droppedItems, function (valueId) {
          valueId = parseInt(valueId);
          var item = _.find($scope.searchedItems, function (listItem) {
            return valueId === parseInt(listItem.id);
          });

          this.push(item);
        }, scopeItems);

        $scope.open(scopeItems);
      };

      $scope.togglePlaylist = function (playlistId) {
        // If the playlist is not here, wee add it
        if (_.indexOf($scope.selectedPlaylists, playlistId) === -1) {
          $scope.selectedPlaylists.push(playlistId);
        } else {
          // Else, we remove it
          $scope.selectedPlaylists = _.without($scope.selectedPlaylists, playlistId);
        }
      };

      $scope.open = function (items) {
        var modalInstance = $modal.open({
          templateUrl: 'myModalContent.html',
          controller: ModalInstanceCtrl,
          resolve: {
            items: function () {
              return items;
            }
          }
        });

        modalInstance.result.then(function (selectedItem) {
          $scope.selected = selectedItem;
        }, function () {
          $log.info('Modal dismissed at: ' + new Date());
        });
      };

      var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
        $scope.items = items;
        $scope.ok = function () {
          $modalInstance.close($scope.items);
        };
        $scope.cancel = function () {
          $modalInstance.dismiss('cancel');
        };
      };
    }]
  );<|endoftext|>


<commit_before>import Ember from 'ember';
import Settings from '../models/settings';

export default Ember.Mixin.create({
  queryParams: ['page', 'perPage'],
  page: 1,
  perPage: Ember.computed(function() {
    let settings = Settings.create();
    let perPage = settings.get('perPage');
    return perPage;
  }),

  perPageValues: [2, 3, 4, 5, 10, 20, 50],
  recordsTotalCount: Ember.computed('model', function() {
    let model = this.get('model');
    let metadata = model.store.typeMapFor(model.type).metadata;
    return metadata.count;
  }),

  actions: {
    gotoPage: function(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },
    nextPage: function() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },
    previousPage: function() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },
    lastPage: function() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },
    firstPage: function() {
      this.set('page', 1);
    }
  },

  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },
    set(key, value) {
      let perPage = parseInt(value, 10);

      // Save setting.
      let settings = Settings.create();
      settings.set('perPage', perPage);

      // Changing perPage value reloads route automatically.
      this.set('perPage', perPage);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page value reloads route automatically.
        this.set('page', newLastPage);
      }

      return perPage;
    }
  }),

  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] [2] … [10] {11} [12] … [18] [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] [3] {4} [5] … [18] [19] or [1] [2] … [15] {16} [17] [18] [19].
    const visiblePageCount = 7;
    const visibleEndPageCount = 2;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  _addPageNumberIntoArray: function(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  _getLastPage: function(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  _checkPageNumber: function(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<commit_msg>Reorder methods in paginated-controller mixin<commit_after>import Ember from 'ember';
import Settings from '../models/settings';

export default Ember.Mixin.create({
  queryParams: ['page', 'perPage'],
  page: 1,
  perPage: Ember.computed(function() {
    let settings = Settings.create();
    let perPage = settings.get('perPage');
    return perPage;
  }),

  actions: {
    gotoPage: function(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },
    nextPage: function() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },
    previousPage: function() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },
    lastPage: function() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },
    firstPage: function() {
      this.set('page', 1);
    }
  },

  perPageValues: [2, 3, 4, 5, 10, 20, 50],

  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },
    set(key, value) {
      let perPage = parseInt(value, 10);

      // Save setting.
      let settings = Settings.create();
      settings.set('perPage', perPage);

      // Changing perPage value reloads route automatically.
      this.set('perPage', perPage);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page value reloads route automatically.
        this.set('page', newLastPage);
      }

      return perPage;
    }
  }),

  recordsTotalCount: Ember.computed('model', function() {
    let model = this.get('model');
    let metadata = model.store.typeMapFor(model.type).metadata;
    return metadata.count;
  }),

  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] [2] … [10] {11} [12] … [18] [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] [3] {4} [5] … [18] [19] or [1] [2] … [15] {16} [17] [18] [19].
    const visiblePageCount = 7;
    const visibleEndPageCount = 2;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  _addPageNumberIntoArray: function(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  _getLastPage: function(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  _checkPageNumber: function(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<|endoftext|>


<commit_before>'use strict';
/* globals ArrayUtil, findParentElementByName, ValueSet, _ */

/**
 * @ngdoc function
 * @name sopheAuthorApp.controller:PhenotypeController
 * @description
 * # PhenotypeController
 * Controller of the sopheAuthorApp
 */
angular.module('sopheAuthorApp')
  .controller('PhenotypeController', ['$scope', '$http', '$routeParams', '$modal', '$location', 'algorithmElementFactory', 'TemporalOperatorService', 'LogicalOperatorService', 'QDMElementService', 'FHIRElementService', 'LibraryService', function ($scope, $http, $routeParams, $modal, $location, algorithmElementFactory, TemporalOperatorService, LogicalOperatorService, QDMElementService, FHIRElementService, LibraryService) {
    $scope.phenotype = $routeParams.id;
    $scope.status = { open: [true, false, false, false, false, false, false]};
    $scope.isPropertiesDisabled = true;
    var advancedRegEx = new RegExp('[a-z]+\\sConcurrent With', 'i');
    $scope.temporalFilter = function(item) {
      if (item) {
        return (item.name.search(advancedRegEx) === -1);
      }
    };

    LibraryService.load()
      .then(LibraryService.processValues)
      .then(function(elements) { $scope.phenotypes = elements; });

    FHIRElementService.load()
      .then(FHIRElementService.processValues)
      .then(function(elements) { $scope.fhirElements = elements; });

    QDMElementService.load()
      .then(QDMElementService.processValues)
      .then(function(elements) { $scope.dataElements = elements; });

    LogicalOperatorService.load()
      .then(LogicalOperatorService.processValues)
      .then(function(operators) { $scope.logicalOperators = operators; });

    TemporalOperatorService.load()
      .then(TemporalOperatorService.processValues)
      .then(function(operators) { $scope.temporalOperators = operators; });

    $scope.treeOptions = {
      dirSelectable: false
    };

    $scope.$on('sophe-search-valuesets', function(evt, dataElement) {
      var modalInstance = $modal.open({
        templateUrl: 'views/elements/valueSetsTermsDialog.html',
        controller: 'ValueSetsTermsDialogController',
        size: 'lg'
      });

      modalInstance.result.then(function (result) {
        if (result) {
          // If we just have a value set, we will create that and place it in the object
          var valueSet;
          var element = ValueSet.createElementFromData(result);
          valueSet = $scope.addWorkflowObject({x: 0, y: 0, element: element});
          dataElement.phemaObject().valueSet(valueSet);
          if (element.customList) {
            valueSet.phemaObject().customList(result);
            delete element.customList;
          }
          dataElement.getStage().draw();
        }
      });
    });

    $scope.$on('sophe-element-selected', function(evt, args) {
      $scope.$apply(function() {
        $scope.isPropertiesDisabled = !$scope.canShowProperties(args);
        _.findWhere($scope.buttons, {text: 'Delete'}).disabled = !$scope.canDelete();
      });
    });

    // If a specific phenotype was specified, load it now
    if ($scope.phenotype) {
      $scope.$watch('canvasDetails', function() {
        if ($scope.canvasDetails) {
          LibraryService.loadDetails($scope.phenotype)
            .then(function(phenotype) {
              algorithmElementFactory.loadFromDefinition($scope, phenotype.definition);
            });
        }
      });
    }

    // config object:
    //   x
    //   y
    //   element
    $scope.addWorkflowObject = function (config) {
      return algorithmElementFactory.addWorkflowObject(config, $scope);
    };

    $scope.copy = function() {
      console.log('Copy');
    };

    $scope.canDelete = function() {
      return (algorithmElementFactory.getFirstSelectedItem($scope) !== null);
    };

    $scope.delete = function() {
      algorithmElementFactory.deleteSelectedObjects($scope);
    };

    $scope.paste = function() {
      console.log('Paste');
    };

    $scope.save = function() {
      var modalInstance = $modal.open({
        templateUrl: 'views/properties/phenotype.html',
        controller: 'PhenotypePropertiesController',
        size: 'lg',
        resolve: {
          phenotype: function() {
            return {definition: $scope.canvasDetails.kineticStageObj.find('#mainLayer')[0].toJSON() };
          },
          isReference: function() { return false; }
        }
      });

      modalInstance.result.then(function (result) {
        LibraryService.saveDetails(result)
          .then(function(data) {
            $location.path('/phenotype/' + data.id);
          });
      });
    };

    $scope.load = function() {
      var modalInstance = $modal.open({
        templateUrl: 'views/phenotypes/load.html',
        controller: 'LoadPhenotypeController',
        size: 'lg',
        resolve: {
          phenotypes: function() {
            return $scope.phenotypes;
          }
        }
      });

      // If the user selects a phenotype to load, redirect to that phenotype's ID which
      // will cause it to load properly.
      modalInstance.result.then(function (id) {
        $location.path('/phenotype/' + id);
      });
    };

    $scope.buttons = [
      {text: 'Save', iconClass:'fa fa-save', event: $scope.save, disabled: false},
      {text: 'Load', iconClass:'fa fa-folder-open', event: $scope.load, disabled: false},
      {text: 'Export', iconClass:'fa fa-arrow-circle-down', disabled: true},
      {spacer: true},
      {text: 'Copy', iconClass:'fa fa-copy', event: $scope.copy, disabled: true},
      {text: 'Paste', iconClass:'fa fa-paste', event: $scope.paste, disabled: true},
      {text: 'Undo', iconClass:'fa fa-undo', disabled: true},
      {text: 'Redo', iconClass:'fa fa-repeat', disabled: true},
      {spacer: true},
      {text: 'Delete', iconClass:'fa fa-remove', event: $scope.delete, disabled: true},
    ];

    $scope.canShowProperties = function(item) {
      var selectedElement = item || algorithmElementFactory.getFirstSelectedItem($scope);
      if (!selectedElement || !selectedElement.element) {
        return false;
      }

      var element = selectedElement.element();
      return (element.type === 'TemporalOperator' ||
        element.type === 'LogicalOperator' ||
        element.type === 'Category' ||
        element.type === 'Phenotype' ||
        element.type === 'DataElement' ||
        element.type === 'ValueSet');
    };

    $scope.showProperties = function() {
      var selectedElement = algorithmElementFactory.getFirstSelectedItem($scope);
      if (!$scope.canShowProperties(selectedElement)) {
        return;
      }

      var modalInstance = null;
      var element = selectedElement.element();
      if (element.type === 'TemporalOperator') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/relationship.html',
          controller: 'RelationshipPropertiesController',
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            temporalOperators: function() {
              return $scope.temporalOperators;
            }
          }
        });

        modalInstance.result.then(function (result) {
          var uri = ((result.relationship.modifier) ? result.relationship.modifier.id : result.relationship.base.uri);
          element.uri = uri;
          element.name = ArrayUtil.findInArrayOrChildren($scope.temporalOperators, 'uri', uri).name;
          element.timeRange = result.timeRange;
          if (result.timeRange.comparison) {
            element.timeRange.comparison = result.timeRange.comparison.name;
          }
          var label = selectedElement.label();
          label.setText(element.name);
          label.getStage().draw();
        });
      }
      else if (element.type === 'LogicalOperator') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/logicalOperator.html',
          controller: 'LogicalOperatorPropertiesController',
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            containedElements: function () {
              return selectedElement.phemaObject().containedElements();
            },
            logicalOperators: function() {
              return $scope.logicalOperators;
            }
          }
        });

        modalInstance.result.then(function (result) {
          element = result;
          findParentElementByName(selectedElement, 'header').setText(element.name);
          selectedElement.getStage().draw();
        });
      }
      else if (element.type === 'Category' || element.type === 'DataElement') {
        // We define the element properties based on the URI (if it's QDM or FHIR)
        var isFHIR = (element.uri.indexOf('fhir') >= 0);
        modalInstance = $modal.open({
          templateUrl: (isFHIR ? 'views/properties/fhirElement.html' : 'views/properties/qdmElement.html'),
          controller: (isFHIR ? 'FHIRElementPropertiesController' : 'QDMElementPropertiesController'),
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            valueSet: function() {
              if (selectedElement.phemaObject() && selectedElement.phemaObject().valueSet()) {
                return angular.copy(selectedElement.phemaObject().valueSet().element());
              }
              else {
                return null;
              }
            }
          }
        });

        modalInstance.result.then(function (result) {
          element.attributes = result.attributes;

          var createNewVS = false;
          var removeOldVS = false;
          var existingValueSet = null;
          if (selectedElement.phemaObject() &&
              selectedElement.phemaObject().valueSet() &&
              selectedElement.phemaObject().valueSet().element()) {
            existingValueSet = selectedElement.phemaObject().valueSet();
            if (existingValueSet.element().id !== result.valueSet.id) {
              createNewVS = true;
              removeOldVS = true;
            }
          }
          else if (result.valueSet.id) {
            createNewVS = true;
          }

          if (removeOldVS) {
            // Remove the old element from the UI
            algorithmElementFactory.destroyGroup(existingValueSet);
            selectedElement.phemaObject().valueSet(null);
          }

          if (createNewVS) {
            var newValueSet = $scope.addWorkflowObject({x: 0, y: 0, element: result.valueSet});
            selectedElement.phemaObject().valueSet(newValueSet);
            if (result.valueSet.customList) {
              newValueSet.phemaObject().customList(result.valueSet.customList);
              delete result.valueSet.customList;
            }
            selectedElement.getStage().draw();
          }
        });
      }
      else if (element.type === 'Phenotype') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/phenotype.html',
          controller: 'PhenotypePropertiesController',
          size: 'lg',
          resolve: {
            phenotype: function () {
              return angular.copy(element);
            },
            isReference: function() { return true; }
          }
        });

        modalInstance.result.then(function (result) {
          element.name = result.name;
          element.description = result.description;
          findParentElementByName(selectedElement, 'header').setText(element.name);
          selectedElement.getStage().draw();
        });
      }
      else if (element.type === 'ValueSet') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/valueSet.html',
          controller: 'ValueSetPropertiesController',
          size: 'lg',
          resolve: {
            valueSet: function () {
              return angular.copy(element);
            },
            isReference: function() { return true; }
          }
        });
      }
    };

    $scope.$on('sophe-empty-temporal-operator-created', function() {
      $scope.$apply(function() {
        $scope.showProperties();
      });
    });
  }]);
<commit_msg>Export JSON<commit_after>'use strict';
/* globals ArrayUtil, findParentElementByName, ValueSet, _ */

/**
 * @ngdoc function
 * @name sopheAuthorApp.controller:PhenotypeController
 * @description
 * # PhenotypeController
 * Controller of the sopheAuthorApp
 */
angular.module('sopheAuthorApp')
  .controller('PhenotypeController', ['$scope', '$http', '$routeParams', '$modal', '$location', '$window', 'algorithmElementFactory', 'TemporalOperatorService', 'LogicalOperatorService', 'QDMElementService', 'FHIRElementService', 'LibraryService', function ($scope, $http, $routeParams, $modal, $location, $window, algorithmElementFactory, TemporalOperatorService, LogicalOperatorService, QDMElementService, FHIRElementService, LibraryService) {
    $scope.phenotype = $routeParams.id;
    $scope.status = { open: [true, false, false, false, false, false, false]};
    $scope.isPropertiesDisabled = true;
    var advancedRegEx = new RegExp('[a-z]+\\sConcurrent With', 'i');
    $scope.temporalFilter = function(item) {
      if (item) {
        return (item.name.search(advancedRegEx) === -1);
      }
    };

    LibraryService.load()
      .then(LibraryService.processValues)
      .then(function(elements) { $scope.phenotypes = elements; });

    FHIRElementService.load()
      .then(FHIRElementService.processValues)
      .then(function(elements) { $scope.fhirElements = elements; });

    QDMElementService.load()
      .then(QDMElementService.processValues)
      .then(function(elements) { $scope.dataElements = elements; });

    LogicalOperatorService.load()
      .then(LogicalOperatorService.processValues)
      .then(function(operators) { $scope.logicalOperators = operators; });

    TemporalOperatorService.load()
      .then(TemporalOperatorService.processValues)
      .then(function(operators) { $scope.temporalOperators = operators; });

    $scope.treeOptions = {
      dirSelectable: false
    };

    $scope.$on('sophe-search-valuesets', function(evt, dataElement) {
      var modalInstance = $modal.open({
        templateUrl: 'views/elements/valueSetsTermsDialog.html',
        controller: 'ValueSetsTermsDialogController',
        size: 'lg'
      });

      modalInstance.result.then(function (result) {
        if (result) {
          // If we just have a value set, we will create that and place it in the object
          var valueSet;
          var element = ValueSet.createElementFromData(result);
          valueSet = $scope.addWorkflowObject({x: 0, y: 0, element: element});
          dataElement.phemaObject().valueSet(valueSet);
          if (element.customList) {
            valueSet.phemaObject().customList(result);
            delete element.customList;
          }
          dataElement.getStage().draw();
        }
      });
    });

    $scope.$on('sophe-element-selected', function(evt, args) {
      $scope.$apply(function() {
        $scope.isPropertiesDisabled = !$scope.canShowProperties(args);
        _.findWhere($scope.buttons, {text: 'Delete'}).disabled = !$scope.canDelete();
      });
    });

    // If a specific phenotype was specified, load it now
    if ($scope.phenotype) {
      $scope.$watch('canvasDetails', function() {
        if ($scope.canvasDetails) {
          LibraryService.loadDetails($scope.phenotype)
            .then(function(phenotype) {
              algorithmElementFactory.loadFromDefinition($scope, phenotype.definition);
            });
        }
      });
    }

    // config object:
    //   x
    //   y
    //   element
    $scope.addWorkflowObject = function (config) {
      return algorithmElementFactory.addWorkflowObject(config, $scope);
    };

    $scope.copy = function() {
      console.log('Copy');
    };

    $scope.canDelete = function() {
      return (algorithmElementFactory.getFirstSelectedItem($scope) !== null);
    };

    $scope.delete = function() {
      algorithmElementFactory.deleteSelectedObjects($scope);
    };

    $scope.paste = function() {
      console.log('Paste');
    };

    $scope.save = function() {
      var modalInstance = $modal.open({
        templateUrl: 'views/properties/phenotype.html',
        controller: 'PhenotypePropertiesController',
        size: 'lg',
        resolve: {
          phenotype: function() {
            return {definition: $scope.canvasDetails.kineticStageObj.find('#mainLayer')[0].toJSON() };
          },
          isReference: function() { return false; }
        }
      });

      modalInstance.result.then(function (result) {
        LibraryService.saveDetails(result)
          .then(function(data) {
            $location.path('/phenotype/' + data.id);
          });
      });
    };

    $scope.load = function() {
      var modalInstance = $modal.open({
        templateUrl: 'views/phenotypes/load.html',
        controller: 'LoadPhenotypeController',
        size: 'lg',
        resolve: {
          phenotypes: function() {
            return $scope.phenotypes;
          }
        }
      });

      // If the user selects a phenotype to load, redirect to that phenotype's ID which
      // will cause it to load properly.
      modalInstance.result.then(function (id) {
        $location.path('/phenotype/' + id);
      });
    };

    $scope.export = function() {
      var hiddenElement = document.createElement('a');
      var blob = new Blob([$scope.canvasDetails.kineticStageObj.find('#mainLayer')[0].toJSON()],
        {type: 'text/json;charset=utf-8;'});
      var url = URL.createObjectURL(blob);
      document.body.appendChild(hiddenElement);
      hiddenElement.style = 'display: none';
      hiddenElement.href = url;
      hiddenElement.setAttribute('download', 'phenotype.json');
      hiddenElement.click();
      $window.URL.revokeObjectURL(url);
    };

    $scope.buttons = [
      {text: 'Save', iconClass:'fa fa-save', event: $scope.save, disabled: false},
      {text: 'Load', iconClass:'fa fa-folder-open', event: $scope.load, disabled: false},
      {text: 'Export', iconClass:'fa fa-arrow-circle-down', event: $scope.export, disabled: false},
      {spacer: true},
      {text: 'Copy', iconClass:'fa fa-copy', event: $scope.copy, disabled: true},
      {text: 'Paste', iconClass:'fa fa-paste', event: $scope.paste, disabled: true},
      {text: 'Undo', iconClass:'fa fa-undo', disabled: true},
      {text: 'Redo', iconClass:'fa fa-repeat', disabled: true},
      {spacer: true},
      {text: 'Delete', iconClass:'fa fa-remove', event: $scope.delete, disabled: true},
    ];

    $scope.canShowProperties = function(item) {
      var selectedElement = item || algorithmElementFactory.getFirstSelectedItem($scope);
      if (!selectedElement || !selectedElement.element) {
        return false;
      }

      var element = selectedElement.element();
      return (element.type === 'TemporalOperator' ||
        element.type === 'LogicalOperator' ||
        element.type === 'Category' ||
        element.type === 'Phenotype' ||
        element.type === 'DataElement' ||
        element.type === 'ValueSet');
    };

    $scope.showProperties = function() {
      var selectedElement = algorithmElementFactory.getFirstSelectedItem($scope);
      if (!$scope.canShowProperties(selectedElement)) {
        return;
      }

      var modalInstance = null;
      var element = selectedElement.element();
      if (element.type === 'TemporalOperator') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/relationship.html',
          controller: 'RelationshipPropertiesController',
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            temporalOperators: function() {
              return $scope.temporalOperators;
            }
          }
        });

        modalInstance.result.then(function (result) {
          var uri = ((result.relationship.modifier) ? result.relationship.modifier.id : result.relationship.base.uri);
          element.uri = uri;
          element.name = ArrayUtil.findInArrayOrChildren($scope.temporalOperators, 'uri', uri).name;
          element.timeRange = result.timeRange;
          if (result.timeRange.comparison) {
            element.timeRange.comparison = result.timeRange.comparison.name;
          }
          var label = selectedElement.label();
          label.setText(element.name);
          label.getStage().draw();
        });
      }
      else if (element.type === 'LogicalOperator') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/logicalOperator.html',
          controller: 'LogicalOperatorPropertiesController',
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            containedElements: function () {
              return selectedElement.phemaObject().containedElements();
            },
            logicalOperators: function() {
              return $scope.logicalOperators;
            }
          }
        });

        modalInstance.result.then(function (result) {
          element = result;
          findParentElementByName(selectedElement, 'header').setText(element.name);
          selectedElement.getStage().draw();
        });
      }
      else if (element.type === 'Category' || element.type === 'DataElement') {
        // We define the element properties based on the URI (if it's QDM or FHIR)
        var isFHIR = (element.uri.indexOf('fhir') >= 0);
        modalInstance = $modal.open({
          templateUrl: (isFHIR ? 'views/properties/fhirElement.html' : 'views/properties/qdmElement.html'),
          controller: (isFHIR ? 'FHIRElementPropertiesController' : 'QDMElementPropertiesController'),
          size: 'lg',
          resolve: {
            element: function () {
              return angular.copy(element);
            },
            valueSet: function() {
              if (selectedElement.phemaObject() && selectedElement.phemaObject().valueSet()) {
                return angular.copy(selectedElement.phemaObject().valueSet().element());
              }
              else {
                return null;
              }
            }
          }
        });

        modalInstance.result.then(function (result) {
          element.attributes = result.attributes;

          var createNewVS = false;
          var removeOldVS = false;
          var existingValueSet = null;
          if (selectedElement.phemaObject() &&
              selectedElement.phemaObject().valueSet() &&
              selectedElement.phemaObject().valueSet().element()) {
            existingValueSet = selectedElement.phemaObject().valueSet();
            if (existingValueSet.element().id !== result.valueSet.id) {
              createNewVS = true;
              removeOldVS = true;
            }
          }
          else if (result.valueSet.id) {
            createNewVS = true;
          }

          if (removeOldVS) {
            // Remove the old element from the UI
            algorithmElementFactory.destroyGroup(existingValueSet);
            selectedElement.phemaObject().valueSet(null);
          }

          if (createNewVS) {
            var newValueSet = $scope.addWorkflowObject({x: 0, y: 0, element: result.valueSet});
            selectedElement.phemaObject().valueSet(newValueSet);
            if (result.valueSet.customList) {
              newValueSet.phemaObject().customList(result.valueSet.customList);
              delete result.valueSet.customList;
            }
            selectedElement.getStage().draw();
          }
        });
      }
      else if (element.type === 'Phenotype') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/phenotype.html',
          controller: 'PhenotypePropertiesController',
          size: 'lg',
          resolve: {
            phenotype: function () {
              return angular.copy(element);
            },
            isReference: function() { return true; }
          }
        });

        modalInstance.result.then(function (result) {
          element.name = result.name;
          element.description = result.description;
          findParentElementByName(selectedElement, 'header').setText(element.name);
          selectedElement.getStage().draw();
        });
      }
      else if (element.type === 'ValueSet') {
        modalInstance = $modal.open({
          templateUrl: 'views/properties/valueSet.html',
          controller: 'ValueSetPropertiesController',
          size: 'lg',
          resolve: {
            valueSet: function () {
              return angular.copy(element);
            },
            isReference: function() { return true; }
          }
        });
      }
    };

    $scope.$on('sophe-empty-temporal-operator-created', function() {
      $scope.$apply(function() {
        $scope.showProperties();
      });
    });
  }]);
<|endoftext|>


<commit_before>/**
 * Модуль для работы с DOM
 */
(function (window) {
    'use strict';

    /**
     * @param selectorOrElement {String | HtmlElement}
     * @returns {_UiElement}
     * @constructor
     */
    function UiElement(selectorOrElement) {
        return new _UiElement(selectorOrElement);
    }

    /**
     * Create new DOM element and wrap to UiElement
     * @param tagName
     * @returns {_UiElement}
     */
    UiElement.create = function (tagName) {
        return new _UiElement(document.createElement(tagName));
    };

    /**
     * Класс враппера для работы с DOM елементами
     * @param selectorOrElement
     * @private
     */
    function _UiElement(selectorOrElement) {
        this.element = null;
        if (typeof selectorOrElement == "string") {
            this.element = document.querySelector(selectorOrElement);
        }
        if (selectorOrElement instanceof HTMLElement) {
            this.element = selectorOrElement;
        }
        if(this.element === null){
            console.error('Invalid or unsupported selector or dom element: ' + selectorOrElement);
        }
    }

    /**
     * Расчет координат относительно документа, учитывая clientTop/clientLeft
     * @returns {{top: number, left: number}}
     */
    _UiElement.prototype.getCoordinates = function () {
        var byWindow = this.element.getBoundingClientRect();
        var bodyElement = document.body;
        var documentElement = document.documentElement;

        var scrollTop = window.pageYOffset || documentElement.scrollTop || bodyElement.scrollTop;
        var scrollLeft = window.pageXOffset || documentElement.scrollLeft || bodyElement.scrollLeft;

        var clientTop = documentElement.clientTop || bodyElement.clientTop || 0;
        var clientLeft = documentElement.clientLeft || bodyElement.clientLeft || 0;

        return {
            top: byWindow.top + scrollTop - clientTop,
            left: byWindow.left + scrollLeft - clientLeft,
            bottom: byWindow.bottom + scrollTop - clientTop,
            right: byWindow.right + scrollLeft - clientLeft
        }
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.clientLeft = function () {
        return this.element.clientLeft;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.clientRight = function () {
        var computedStyles = window.getComputedStyle(this.element);
        var borderRight = computedStyles.borderRightWidth;
        borderRight = borderRight.split('px')[0];
        return +borderRight;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.clientTop = function () {
        return this.element.clientTop;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.offsetWidth = function () {
        return this.element.offsetWidth;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.clientWidth = function () {
        return this.element.clientWidth;
    };

    _UiElement.prototype.offsetHeight = function () {
        return this.element.offsetHeight;
    };

    _UiElement.prototype.clientHeight = function () {
        return this.element.clientHeight;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.scrollWidth = function () {
        return this.element.scrollWidth;
    };

    /**
     *
     * @param cls
     */
    _UiElement.prototype.addClass = function (cls) {
        this.element.classList.add(cls);
    };

    /**
     *
     * @param cls
     */
    _UiElement.prototype.removeClass = function (cls) {
      this.element.classList.remove(cls);
    };

    /**
     * Обернуть элемент враппером
     * @param wrapper {UiElement}
     */
    _UiElement.prototype.wrap = function (wrapper) {
        var el, parent;
        if(wrapper instanceof _UiElement){
            el = wrapper.element;
        } else{
            el = wrapper;
        }

        parent = this.element.parentNode;

        if(this.element.nextSibling){
            parent.insertBefore(el, this.element.nextSibling);
        } else {
            parent.appendChild(el);
        }
        el.appendChild(this.element);
    };

    /**
     *
     * @param value
     * @returns {*|string|Number|undefined}
     */
    _UiElement.prototype.val = function (value) {
        if(value != undefined){
            this.element.value = value;
            return;
        }
        return this.element.value;
    };

    /**
     *
     * @param eventKey
     * @param callback
     * @param stage
     */
    _UiElement.prototype.on = function (eventKey, callback, stage) {
        this.element.addEventListener(eventKey, callback, stage);
    };

    /**
     *
     * @param evenKey
     * @param callback
     * @param stage
     */
    _UiElement.prototype.off = function (evenKey, callback, stage) {
        this.element.removeEventListener(evenKey, callback, stage);
    };
    /**
     * Удалить потомка
     * @param child
     * @returns {Node}
     */
    _UiElement.prototype.removeChild =function (child) {
        return this.element.removeChild(child);
    };

    /**
     * Добаить потомка к элементу
     * @param child
     * @returns {Node}
     */
    _UiElement.prototype.append = function (child) {
        if(child instanceof _UiElement){
             return this.element.appendChild(child.element);
        }
        return this.element.appendChild(child);
    };

    _UiElement.prototype.html = function (val) {
        if(val != undefined){
            this.element.innerHTML = val;
            return;
        }
        return this.element.innerHTML;
    };

    _UiElement.prototype.remove = function(){
        this.element.parentNode.removeChild(this.element);
    };

    _UiElement.prototype.css = function (css) {
        var self = this;
        if(!css){
            return window.getComputedStyle(this.element);
        }
        Object.keys(css).forEach(function (property) {
           self.element.style[property] = css[property];
        });
    };

    /**
     * Прокси для проброса style
     */
    Object.defineProperties(_UiElement.prototype, {
        style: {
            get: function () {
                return this.element.style;
            }
        }
    });

    window.UiElement = UiElement;

})(window);<commit_msg>[REFACTORING] Добавил доку к uiDropDownElement.js<commit_after>/**
 * Модуль для работы с DOM
 */
(function (window) {
    'use strict';

    /**
     * @param selectorOrElement {String | HtmlElement}
     * @returns {_UiElement}
     * @constructor
     */
    function UiElement(selectorOrElement) {
        return new _UiElement(selectorOrElement);
    }

    /**
     * Create new DOM element and wrap to UiElement
     * @param tagName
     * @returns {_UiElement}
     */
    UiElement.create = function (tagName) {
        return new _UiElement(document.createElement(tagName));
    };

    /**
     * Класс враппера для работы с DOM элементами
     * @param selectorOrElement
     * @private
     */
    function _UiElement(selectorOrElement) {
        this.element = null;
        if (typeof selectorOrElement == "string") {
            this.element = document.querySelector(selectorOrElement);
        }
        if (selectorOrElement instanceof HTMLElement) {
            this.element = selectorOrElement;
        }
        if(this.element === null){
            console.error('Invalid or unsupported selector or dom element: ' + selectorOrElement);
        }
    }

    /**
     * Расчет координат относительно документа, учитывая clientTop/clientLeft
     * @returns {{top: number, left: number}}
     */
    _UiElement.prototype.getCoordinates = function () {
        var byWindow = this.element.getBoundingClientRect();
        var bodyElement = document.body;
        var documentElement = document.documentElement;

        var scrollTop = window.pageYOffset || documentElement.scrollTop || bodyElement.scrollTop;
        var scrollLeft = window.pageXOffset || documentElement.scrollLeft || bodyElement.scrollLeft;

        var clientTop = documentElement.clientTop || bodyElement.clientTop || 0;
        var clientLeft = documentElement.clientLeft || bodyElement.clientLeft || 0;

        return {
            top: byWindow.top + scrollTop - clientTop,
            left: byWindow.left + scrollLeft - clientLeft,
            bottom: byWindow.bottom + scrollTop - clientTop,
            right: byWindow.right + scrollLeft - clientLeft
        }
    };

    /**
     * clientLeft
     * @returns {number}
     */
    _UiElement.prototype.clientLeft = function () {
        return this.element.clientLeft;
    };

    /**
     * clientRight = в реалльности borderRightWidth
     * @returns {number}
     */
    _UiElement.prototype.clientRight = function () {
        var computedStyles = window.getComputedStyle(this.element);
        var borderRight = computedStyles.borderRightWidth;
        borderRight = borderRight.split('px')[0];
        return +borderRight;
    };

    /**
     * clientTop
     * @returns {number}
     */
    _UiElement.prototype.clientTop = function () {
        return this.element.clientTop;
    };

    /**
     * offsetWidth
     * @returns {number}
     */
    _UiElement.prototype.offsetWidth = function () {
        return this.element.offsetWidth;
    };

    /**
     *clientWidth
     * @returns {number}
     */
    _UiElement.prototype.clientWidth = function () {
        return this.element.clientWidth;
    };

    /**
     * offsetHeight
     * @returns {number}
     */
    _UiElement.prototype.offsetHeight = function () {
        return this.element.offsetHeight;
    };

    /**
     * clientHeight
     * @returns {number}
     */
    _UiElement.prototype.clientHeight = function () {
        return this.element.clientHeight;
    };

    /**
     *
     * @returns {number}
     */
    _UiElement.prototype.scrollWidth = function () {
        return this.element.scrollWidth;
    };

    /**
     * Добавить класс
     * @param cls {str}
     */
    _UiElement.prototype.addClass = function (cls) {
        this.element.classList.add(cls);
    };

    /**
     * Удалить класс
     * @param cls {str}
     */
    _UiElement.prototype.removeClass = function (cls) {
      this.element.classList.remove(cls);
    };

    /**
     * Обернуть элемент враппером
     * @param wrapper {UiElement}
     */
    _UiElement.prototype.wrap = function (wrapper) {
        var el, parent;
        if(wrapper instanceof _UiElement){
            el = wrapper.element;
        } else{
            el = wrapper;
        }

        parent = this.element.parentNode;

        if(this.element.nextSibling){
            parent.insertBefore(el, this.element.nextSibling);
        } else {
            parent.appendChild(el);
        }
        el.appendChild(this.element);
    };

    /**
     *
     * @param value {string | Number}
     * @returns {*|string|Number|undefined}
     */
    _UiElement.prototype.val = function (value) {
        if(value != undefined){
            this.element.value = value;
            return;
        }
        return this.element.value;
    };

    /**
     * Подписка на событие
     * @param eventKey {string}
     * @param callback {Function}
     * @param stage
     */
    _UiElement.prototype.on = function (eventKey, callback, stage) {
        this.element.addEventListener(eventKey, callback, stage);
    };

    /**
     * Отмена подписки на событие
     * @param evenKey {string}
     * @param callback {Function}
     * @param stage
     */
    _UiElement.prototype.off = function (evenKey, callback, stage) {
        this.element.removeEventListener(evenKey, callback, stage);
    };

    /**
     * Удалить потомка
     * @param child {UiElement | Node}
     * @returns {Node}
     */
    _UiElement.prototype.removeChild =function (child) {
        if(child instanceof _UiElement){
            child = child.element;
        }
        return this.element.removeChild(child);
    };

    /**
     * Добаить потомка к элементу
     * @param child {UiElement | Node}
     * @returns {Node}
     */
    _UiElement.prototype.append = function (child) {
        if(child instanceof _UiElement){
             return this.element.appendChild(child.element);
        }
        return this.element.appendChild(child);
    };

    /**
     * Установаить или поллучить innerHtml
     * @param val {string}
     * @returns {string | undefined}
     */
    _UiElement.prototype.html = function (val) {
        if(val != undefined){
            this.element.innerHTML = val;
            return;
        }
        return this.element.innerHTML;
    };

    /**
     * Удаление элемента из DOM
     */
    _UiElement.prototype.remove = function(){
        this.element.parentNode.removeChild(this.element);
    };

    /**
     * Установить или получить css свойства
     * @param css {object}
     * @returns {CSSStyleDeclaration}
     */
    _UiElement.prototype.css = function (css) {
        var self = this;
        if(!css){
            return window.getComputedStyle(this.element);
        }
        Object.keys(css).forEach(function (property) {
           self.element.style[property] = css[property];
        });
    };

    /**
     * Прокси для проброса style
     */
    Object.defineProperties(_UiElement.prototype, {
        style: {
            get: function () {
                return this.element.style;
            }
        }
    });

    window.UiElement = UiElement;

})(window);<|endoftext|>


<commit_before>/**
  @module ember-flexberry
 */

import Ember from 'ember';

/**
  Mixin for controller, that pagination support.

  @example
    ```javascript
    // app/controllers/employees.js
    import Ember from 'ember';
    import PaginatedController from 'ember-flexberry/mixins/paginated-controller'
    export default Ember.Controller.extend(PaginatedController, {
    });
    ```

    ```javascript
    // app/routes/employees.js
    import Ember from 'ember';
    import PaginatedRoute from 'ember-flexberry/mixins/paginated-route'
    export default Ember.Route.extend(PaginatedRoute, {
    });
    ```

    ```handlebars
    <!-- app/templates/employees.hbs -->
    ...
    {{flexberry-objectlistview
      ...
      pages=pages
      recordsTotalCount=recordsTotalCount
      perPageValue=perPageValue
      perPageValues=perPageValues
      hasPreviousPage=hasPreviousPage
      hasNextPage=hasNextPage
      previousPage=(action 'previousPage')
      gotoPage=(action 'gotoPage')
      nextPage=(action 'nextPage')
      ...
    }}
    ...
    ```

  @class PaginatedController
  @uses Ember.Mixin
 */
export default Ember.Mixin.create({
  /**
    Start page.

    @property page
    @type Number
    @default 1
  */
  page: 1,

  /**
    Count records on page.

    @property perPage
    @type Number
    @default 5
  */
  perPage: 5,

  /**
    User selectable options values for `perPage`.

    @property perPageValues
    @type Array
    @default [5, 10, 20, 50]
  */
  perPageValues: [5, 10, 20, 50],

  /**
    Get or set `perPage` value.

    @property perPageValue
    @type Number
  */
  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },

    set(key, value) {
      let perPage = parseInt(value, 10);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page or perPage value reloads route automatically.
        this.setProperties({
          page: newLastPage,
          perPage: perPage
        });
      } else {
        // Changing perPage value reloads route automatically.
        this.set('perPage', perPage);
      }

      return perPage;
    }
  }),

  /**
    Total count records.

    @property recordsTotalCount
    @type Number
    @readOnly
  */
  recordsTotalCount: Ember.computed('model', function() {
    let count = this.get('model.meta.count');
    if (count) {
      return count;
    } else {
      let mName = this.get('model.query.modelName');
      let self = this;
      return this.get('store').findAll(mName)
      .then((result) => {
        self.set('recordsTotalCount', result.content.length);
      });
    }
  }),

  /**
    If `true` next page exists.

    @property hasNextPage
    @type Boolean
    @readOnly
  */
  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  /**
    If `true` previous page exists.

    @property hasPreviousPage
    @type Boolean
    @readOnly
  */
  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  /**
    Array of objects corresponding to list of pages.

    Each page is presented as object with following properties:
    - **number** - Number of page.
    - **isCurrent** - Page is current.
    - **isEllipsis** - If `true` this page not showing in list.

    @property pages
    @type Array
    @readOnly
  */
  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] … [10] {11} [12] … [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] {3} [4] … [19] or [1] … [16] {17} [18] [19].
    const visiblePageCount = 5;
    const visibleEndPageCount = 1;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed.
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  /**
    Defines which query parameters the controller accepts. [More info.](http://emberjs.com/api/classes/Ember.Controller.html#property_queryParams).

    @property queryParams
    @type Array
    @default ['page', 'perPage']
  */
  queryParams: ['page', 'perPage'],

  actions: {
    /**
      Transition to page with number.

      @method actions.gotoPage
      @param {Number} pageNum Number of page.
    */
    gotoPage(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },

    /**
      Transition to next page.

      @method actions.nextPage
    */
    nextPage() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },

    /**
      Transition to previous page.

      @method actions.previousPage
    */
    previousPage() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },

    /**
      Transition to last page.

      @method actions.lastPage
    */
    lastPage() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },

    /**
      Transition to first page.

      @method actions.firstPage
    */
    firstPage() {
      this.set('page', 1);
    },
  },

  /**
    Add page number into array.

    @method _addPageNumberIntoArray
    @param {Array} arr Array pages.
    @param {Number} pageNumber Number of page.
    @param {Boolean} isEllipsis If `true` this page not showing in list.
    @private
  */
  _addPageNumberIntoArray(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  /**
    Get number last page.

    @method _getLastPage
    @param {Number} perPage Count records on page.
    @param {Number} count Total count records.
    @return {Number} Number last page.
    @private
  */
  _getLastPage(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  /**
    Check there is a page with this number.

    @method _checkPageNumber
    @param {Number} pageNum Number of page.
    @return {Boolean} If page exists, return `pageNum`, else, return `lastPage`.
    @private
  */
  _checkPageNumber(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<commit_msg>Fix JSCS<commit_after>/**
  @module ember-flexberry
 */

import Ember from 'ember';

/**
  Mixin for controller, that pagination support.

  @example
    ```javascript
    // app/controllers/employees.js
    import Ember from 'ember';
    import PaginatedController from 'ember-flexberry/mixins/paginated-controller'
    export default Ember.Controller.extend(PaginatedController, {
    });
    ```

    ```javascript
    // app/routes/employees.js
    import Ember from 'ember';
    import PaginatedRoute from 'ember-flexberry/mixins/paginated-route'
    export default Ember.Route.extend(PaginatedRoute, {
    });
    ```

    ```handlebars
    <!-- app/templates/employees.hbs -->
    ...
    {{flexberry-objectlistview
      ...
      pages=pages
      recordsTotalCount=recordsTotalCount
      perPageValue=perPageValue
      perPageValues=perPageValues
      hasPreviousPage=hasPreviousPage
      hasNextPage=hasNextPage
      previousPage=(action 'previousPage')
      gotoPage=(action 'gotoPage')
      nextPage=(action 'nextPage')
      ...
    }}
    ...
    ```

  @class PaginatedController
  @uses Ember.Mixin
 */
export default Ember.Mixin.create({
  /**
    Start page.

    @property page
    @type Number
    @default 1
  */
  page: 1,

  /**
    Count records on page.

    @property perPage
    @type Number
    @default 5
  */
  perPage: 5,

  /**
    User selectable options values for `perPage`.

    @property perPageValues
    @type Array
    @default [5, 10, 20, 50]
  */
  perPageValues: [5, 10, 20, 50],

  /**
    Get or set `perPage` value.

    @property perPageValue
    @type Number
  */
  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },

    set(key, value) {
      let perPage = parseInt(value, 10);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page or perPage value reloads route automatically.
        this.setProperties({
          page: newLastPage,
          perPage: perPage
        });
      } else {
        // Changing perPage value reloads route automatically.
        this.set('perPage', perPage);
      }

      return perPage;
    }
  }),

  /**
    Total count records.

    @property recordsTotalCount
    @type Number
    @readOnly
  */
  recordsTotalCount: Ember.computed('model', function() {
    let count = this.get('model.meta.count');
    if (count) {
      return count;
    } else {
      let mName = this.get('model.query.modelName');
      let _this = this;
      return this.get('store').findAll(mName)
      .then((result) => {
        _this.set('recordsTotalCount', result.content.length);
      });
    }
  }),

  /**
    If `true` next page exists.

    @property hasNextPage
    @type Boolean
    @readOnly
  */
  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  /**
    If `true` previous page exists.

    @property hasPreviousPage
    @type Boolean
    @readOnly
  */
  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  /**
    Array of objects corresponding to list of pages.

    Each page is presented as object with following properties:
    - **number** - Number of page.
    - **isCurrent** - Page is current.
    - **isEllipsis** - If `true` this page not showing in list.

    @property pages
    @type Array
    @readOnly
  */
  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] … [10] {11} [12] … [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] {3} [4] … [19] or [1] … [16] {17} [18] [19].
    const visiblePageCount = 5;
    const visibleEndPageCount = 1;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed.
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  /**
    Defines which query parameters the controller accepts. [More info.](http://emberjs.com/api/classes/Ember.Controller.html#property_queryParams).

    @property queryParams
    @type Array
    @default ['page', 'perPage']
  */
  queryParams: ['page', 'perPage'],

  actions: {
    /**
      Transition to page with number.

      @method actions.gotoPage
      @param {Number} pageNum Number of page.
    */
    gotoPage(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },

    /**
      Transition to next page.

      @method actions.nextPage
    */
    nextPage() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },

    /**
      Transition to previous page.

      @method actions.previousPage
    */
    previousPage() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },

    /**
      Transition to last page.

      @method actions.lastPage
    */
    lastPage() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },

    /**
      Transition to first page.

      @method actions.firstPage
    */
    firstPage() {
      this.set('page', 1);
    },
  },

  /**
    Add page number into array.

    @method _addPageNumberIntoArray
    @param {Array} arr Array pages.
    @param {Number} pageNumber Number of page.
    @param {Boolean} isEllipsis If `true` this page not showing in list.
    @private
  */
  _addPageNumberIntoArray(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  /**
    Get number last page.

    @method _getLastPage
    @param {Number} perPage Count records on page.
    @param {Number} count Total count records.
    @return {Number} Number last page.
    @private
  */
  _getLastPage(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  /**
    Check there is a page with this number.

    @method _checkPageNumber
    @param {Number} pageNum Number of page.
    @return {Boolean} If page exists, return `pageNum`, else, return `lastPage`.
    @private
  */
  _checkPageNumber(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import Settings from '../models/settings';

export default Ember.Mixin.create({
  queryParams: ['page', 'perPage'],
  page: 1,
  perPage: 5,

  // FIXME: Fix perPage loading from Settings.
  // perPage: Ember.computed(function() {
  //   let settings = Settings.create();
  //   let perPage = settings.get('perPage');
  //   return perPage;
  // }),

  actions: {
    gotoPage: function(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },
    nextPage: function() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },
    previousPage: function() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },
    lastPage: function() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },
    firstPage: function() {
      this.set('page', 1);
    }
  },

  perPageValues: [2, 3, 4, 5, 10, 20, 50],

  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },
    set(key, value) {
      let perPage = parseInt(value, 10);

      // Save setting.
      let settings = Settings.create();
      settings.set('perPage', perPage);

      // Changing perPage value reloads route automatically.
      this.set('perPage', perPage);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page value reloads route automatically.
        this.set('page', newLastPage);
      }

      return perPage;
    }
  }),

  recordsTotalCount: Ember.computed('model', function() {
    let model = this.get('model');
    let metadata = model.store.typeMapFor(model.type).metadata;
    return metadata.count;
  }),

  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] [2] … [10] {11} [12] … [18] [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] [3] {4} [5] … [18] [19] or [1] [2] … [15] {16} [17] [18] [19].
    const visiblePageCount = 7;
    const visibleEndPageCount = 2;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  _addPageNumberIntoArray: function(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  _getLastPage: function(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  _checkPageNumber: function(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<commit_msg>Fix pagination on List Forms for ember-data v2.4<commit_after>import Ember from 'ember';
import Settings from '../models/settings';

export default Ember.Mixin.create({
  queryParams: ['page', 'perPage'],
  page: 1,
  perPage: 5,

  // FIXME: Fix perPage loading from Settings.
  // perPage: Ember.computed(function() {
  //   let settings = Settings.create();
  //   let perPage = settings.get('perPage');
  //   return perPage;
  // }),

  actions: {
    gotoPage: function(pageNum) {
      let num = this._checkPageNumber(pageNum);
      this.set('page', num);
    },
    nextPage: function() {
      let page = this.get('page');
      let nextPage = this._checkPageNumber(page + 1);
      this.set('page', nextPage);
    },
    previousPage: function() {
      let page = this.get('page');
      let prevPage = this._checkPageNumber(page - 1);
      this.set('page', prevPage);
    },
    lastPage: function() {
      let lastPage = this._getLastPage();
      this.set('page', lastPage);
    },
    firstPage: function() {
      this.set('page', 1);
    }
  },

  perPageValues: [2, 3, 4, 5, 10, 20, 50],

  perPageValue: Ember.computed('perPage', {
    get(key) {
      let perPage = this.get('perPage');
      let perPageValues = this.get('perPageValues');
      if (perPageValues.indexOf(perPage) === -1) {
        // Если perPage не будет в perPageValues,
        // то в select-е будет выбрано undefined,
        // => perPage изменится undefined, т.к. на нем биндинг.
        perPageValues.push(perPage);
        perPageValues.sort((a, b) => a - b);
      }

      return perPage;
    },
    set(key, value) {
      let perPage = parseInt(value, 10);

      // Save setting.
      let settings = Settings.create();
      settings.set('perPage', perPage);

      // Changing perPage value reloads route automatically.
      this.set('perPage', perPage);

      // Check that the current page number does not exceed the last page number.
      let currentPage = this.get('page');
      let newLastPage = this._getLastPage(perPage);
      if (currentPage > newLastPage) {
        // Changing page value reloads route automatically.
        this.set('page', newLastPage);
      }

      return perPage;
    }
  }),

  recordsTotalCount: Ember.computed('model', function() {
    return this.get('model.meta.count');
  }),

  hasPreviousPage: Ember.computed('page', function() {
    return this.get('page') > 1;
  }),

  hasNextPage: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();
    return page < lastPage;
  }),

  pages: Ember.computed('page', 'perPage', 'recordsTotalCount', function() {
    let page = this.get('page');
    let lastPage = this._getLastPage();

    // Pages are shown via list like [1] [2] … [10] {11} [12] … [18] [19], initial and final pages are shown always,
    // and nearest neighbors are and displayed for the current page. In case, when the current page is located in close to the beginning or end
    // list of page is shown accordingly [1] [2] [3] {4} [5] … [18] [19] or [1] [2] … [15] {16} [17] [18] [19].
    const visiblePageCount = 7;
    const visibleEndPageCount = 2;
    let arr = [];

    if (visiblePageCount >= lastPage) {
      // If the total page number do not exceed the number of visible pages.
      for (let i = 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    } else {
      // Number of visible pages near current page.
      let visibleMidlePageHalfCount =  Math.floor((visiblePageCount - visibleEndPageCount * 2) / 2);

      // Number of visible pages to the left end.
      let leftEndPageCount = page < visibleEndPageCount + visibleMidlePageHalfCount + 1 ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Number of visible pages to the right end.
      let rightEndPageCount = page > lastPage - (visibleEndPageCount + visibleMidlePageHalfCount) ?
            visiblePageCount - visibleEndPageCount
            : visibleEndPageCount;

      // Add pages to the left edge.
      for (let i = 1; i <= Math.min(leftEndPageCount, lastPage); i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add left ellipsis if needed
      if (page > visibleEndPageCount + visibleMidlePageHalfCount + 1) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add middle pades including current page.
      let middleBlockStartPage = Math.max(leftEndPageCount + 1, page - visibleMidlePageHalfCount);
      let middleBlockEndPage = Math.min(page + visibleMidlePageHalfCount, lastPage - rightEndPageCount);
      for (let i = middleBlockStartPage; i <= middleBlockEndPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }

      // Add right ellipsis if needed.
      if (page < lastPage - (visibleEndPageCount + visibleMidlePageHalfCount)) {
        this._addPageNumberIntoArray(arr, 0, true);
      }

      // Add pages to the right edge.
      for (let i = lastPage - rightEndPageCount + 1; i <= lastPage; i++) {
        this._addPageNumberIntoArray(arr, i, false);
      }
    }

    return arr;
  }),

  _addPageNumberIntoArray: function(arr, pageNumber, isEllipsis) {
    let page = this.get('page');
    arr.push({
      number: pageNumber,
      isCurrent: (pageNumber === page),
      isEllipsis: isEllipsis
    });
  },

  _getLastPage: function(perPage = this.get('perPage'), count = this.get('recordsTotalCount')) {
    return Math.ceil(count / perPage);
  },

  _checkPageNumber: function(pageNum) {
    const firstPage = 1;
    let lastPage = this._getLastPage();
    return Math.max(firstPage, Math.min(pageNum, lastPage));
  }
});
<|endoftext|>


<commit_before>/*
	jQuery TextAreaResizer plugin
	Created on 17th January 2008 by Ryan O'Dell
	Version 1.0.4

	Converted from Drupal -> textarea.js
	Found source: http://plugins.jquery.com/misc/textarea.js
	$Id: textarea.js,v 1.11.2.1 2007/04/18 02:41:19 drumm Exp $

	1.0.1 Updates to missing global 'var', added extra global variables, fixed multiple instances, improved iFrame support
	1.0.2 Updates according to textarea.focus
	1.0.3 Further updates including removing the textarea.focus and moving private variables to top
	1.0.4 Re-instated the blur/focus events, according to information supplied by dec

*/
(function($) {
	/* private variable "oHover" used to determine if you're still hovering over the same element */
	var textarea, staticOffset;  // added the var declaration for 'staticOffset' thanks to issue logged by dec.
	var iLastMousePos = 0;
	var iMin = 32;
	var grip;
	/* TextAreaResizer plugin */
	$.fn.TextAreaResizer = function() {
		return this.each(function() {
		    textarea = $(this).addClass('processed'), staticOffset = null;

			// 18-01-08 jQuery bind to pass data element rather than direct mousedown - Ryan O'Dell
		    // When wrapping the text area, work around an IE margin bug.  See:
		    // http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout
		    $(this).wrap('

')
		      .parent().append($('

').bind("mousedown",{el: this} , startDrag));

		    var grippie = $('div.grippie', $(this).parent())[0];
		    grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';

		});
	};
	/* private functions */
	function startDrag(e) {
		textarea = $(e.data.el);
		textarea.blur();
		iLastMousePos = mousePosition(e).y;
		staticOffset = textarea.height() - iLastMousePos;
		textarea.css('opacity', 0.25);
		$(document).mousemove(performDrag).mouseup(endDrag);
		return false;
	}

	function performDrag(e) {
		var iThisMousePos = mousePosition(e).y;
		var iMousePos = staticOffset + iThisMousePos;
		if (iLastMousePos >= (iThisMousePos)) {
			iMousePos -= 5;
		}
		iLastMousePos = iThisMousePos;
		iMousePos = Math.max(iMin, iMousePos);
		textarea.height(iMousePos + 'px');
		if (iMousePos < iMin) {
			endDrag(e);
		}
		return false;
	}

	function endDrag(e) {
		$(document).unbind('mousemove', performDrag).unbind('mouseup', endDrag);
		textarea.css('opacity', 1);
		textarea.focus();
		textarea = null;
		staticOffset = null;
		iLastMousePos = 0;
	}

	function mousePosition(e) {
		return { x: e.clientX + document.documentElement.scrollLeft, y: e.clientY + document.documentElement.scrollTop };
	};
})(jQuery);

<commit_msg>COSMETIC Nuked fadout effect on re-size textarea grippie.<commit_after>/*
	jQuery TextAreaResizer plugin
	Created on 17th January 2008 by Ryan O'Dell
	Version 1.0.4

	Converted from Drupal -> textarea.js
	Found source: http://plugins.jquery.com/misc/textarea.js
	$Id: textarea.js,v 1.11.2.1 2007/04/18 02:41:19 drumm Exp $

	1.0.1 Updates to missing global 'var', added extra global variables, fixed multiple instances, improved iFrame support
	1.0.2 Updates according to textarea.focus
	1.0.3 Further updates including removing the textarea.focus and moving private variables to top
	1.0.4 Re-instated the blur/focus events, according to information supplied by dec

*/
(function($) {
	/* private variable "oHover" used to determine if you're still hovering over the same element */
	var textarea, staticOffset;  // added the var declaration for 'staticOffset' thanks to issue logged by dec.
	var iLastMousePos = 0;
	var iMin = 32;
	var grip;
	/* TextAreaResizer plugin */
	$.fn.TextAreaResizer = function() {
		return this.each(function() {
		    textarea = $(this).addClass('processed'), staticOffset = null;

			// 18-01-08 jQuery bind to pass data element rather than direct mousedown - Ryan O'Dell
		    // When wrapping the text area, work around an IE margin bug.  See:
		    // http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout
		    $(this).wrap('

')
		      .parent().append($('

').bind("mousedown",{el: this} , startDrag));

		    var grippie = $('div.grippie', $(this).parent())[0];
		    grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';

		});
	};
	/* private functions */
	function startDrag(e) {
		textarea = $(e.data.el);
		textarea.blur();
		iLastMousePos = mousePosition(e).y;
		staticOffset = textarea.height() - iLastMousePos;
		//textarea.css('opacity', 0.25);
		$(document).mousemove(performDrag).mouseup(endDrag);
		return false;
	}

	function performDrag(e) {
		var iThisMousePos = mousePosition(e).y;
		var iMousePos = staticOffset + iThisMousePos;
		if (iLastMousePos >= (iThisMousePos)) {
			iMousePos -= 5;
		}
		iLastMousePos = iThisMousePos;
		iMousePos = Math.max(iMin, iMousePos);
		textarea.height(iMousePos + 'px');
		if (iMousePos < iMin) {
			endDrag(e);
		}
		return false;
	}

	function endDrag(e) {
		$(document).unbind('mousemove', performDrag).unbind('mouseup', endDrag);
		//textarea.css('opacity', 1);
		textarea.focus();
		textarea = null;
		staticOffset = null;
		iLastMousePos = 0;
	}

	function mousePosition(e) {
		return { x: e.clientX + document.documentElement.scrollLeft, y: e.clientY + document.documentElement.scrollTop };
	};
})(jQuery);

<|endoftext|>


<commit_before>import {Tiled2DPixiTrack} from './Tiled2DPixiTrack.js';
import {tileProxy} from './TileProxy.js';

export class ArrowheadDomainsTrack extends Tiled2DPixiTrack {
    constructor(scene, server, uid) {
        super(scene, server, uid);

    }

    areAllVisibleTilesLoaded() {

        // we don't need to wait for any tiles to load before
        // drawing
        //
        return true;
    }

    calculateVisibleTiles() {
        super.calculateVisibleTiles(false);

    }

    initTile(tile) {
        /**
         * Create whatever is needed to draw this tile.
         */

        let graphics = tile.graphics;

        this.drawTile(tile, graphics);
    }

    destroyTile(tile, graphics) {

    }

    drawTile(tile) {
        if (!tile.graphics)
            return;

        //console.log('tile:', tile);
        //console.log('Id2DTiled drawTile...');
        let graphics = tile.graphics;
        let {tileX, tileY, tileWidth, tileHeight} = this.getTilePosAndDimensions(tile.tileData.zoomLevel,
                                                                                tile.tileData.tilePos);

        // the text needs to be scaled down so that it doesn't become huge
        // when we zoom in
        let tSX = 1 / ((this._xScale(1) - this._xScale(0)) / (this._refXScale(1) - this._refXScale(0)));
        let tSY = 1 / ((this._yScale(1) - this._yScale(0)) / (this._refYScale(1) - this._refYScale(0)));

        //console.log('tSX:', tSX, 'tSY:',tSY);

        graphics.clear();

        graphics.lineStyle(4 * tSX, 0x0000FF, 1);
        graphics.beginFill(0xFF700B, 0.4);
        graphics.alpha = 0.5;

        // line needs to be scaled down so that it doesn't become huge
        for (let line of tile.tileData) {
            let startX = this._refXScale(+line[1] + line[12]);
            let endX = this._refXScale(+line[2] + line[12]);

            let startY = this._refYScale(+line[4] + line[12]);
            let endY = this._refYScale(+line[5] + line[12]);

            //console.log(startX, endX, startY, endY);

            graphics.drawRect(startX, startY, endY - startY, endX - startX);
        }

    }
}
<commit_msg>Remove unused code<commit_after><|endoftext|>