<commit_before>angular.module('roadmaps.ctrl', ['roadmaps.factory', 'services.server', 'services.user'])

.controller('RoadMapsController', [ '$scope', '$http', '$stateParams', 'RoadMapsFactory', 'Server', 'User', '$timeout', '$state', function($scope, $http, $stateParams, RoadMapsFactory, Server, User, $timeout, $state){
  angular.extend($scope, RoadMapsFactory);

  var roadmapId = $stateParams.roadmapID;
  $scope.currentRoadMapData = {};
  $scope.renderedNodes = [];
  $('.tooltipped').tooltip({delay: 50});

  $scope.showComments = false;
  $scope.currentIndex = 0;

  $scope.toggleComments = function(){
    $scope.showComments = true;
  };

<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    if( !$scope[elementID] ){
      return  false;
    } else {
      return true;
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    $scope.currentIndex = $index;
    if( !$scope.currentResourceURL ) {
      $scope.currentResourceURL = $scope.currentLinks[0];
    }
    if(boolean === false){
      $(elementID).val($scope.renderedNodes[$index][field]);
    }
    $scope[elementID] = boolean;
  };

  $scope.getPlaceholder = function($index, field){
    var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
    if( field === 'resourceURL'){
      console.log('capitalizedField', capitalizedField);
      console.log('current resourceURL getPlaceholder', $scope['current' + capitalizedField]);
    }
    return $scope['current' + capitalizedField];
  };

  $scope.saveEdit = function($index, field, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('elementID', $(elementID));
    var newProperty = $(elementID).val();
    console.log('newProperty', newProperty);
    var updateObj = {};
    updateObj['_id'] = $scope.renderedNodes[$index]._id;
    updateObj[field] = newProperty;
    Server.updateNode(updateObj)
      .then(function(node) {
      $scope.showEditor($index, field, false, idPrefix);
      $scope.renderedNodes[$index][field] = newProperty;
      var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
      console.log('capitalizedField', capitalizedField);
      $scope['current' + capitalizedField] = newProperty;
      if( field === 'resourceURL' ){
        $scope.currentLinks[0] = newProperty;
      }
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };
=======
  $scope.hideText = function ($index){
    var id = 'title-' + $index;
=======
  $scope.hideText = function ($index, field){
    var id = field + '-' + $index;
>>>>>>> (feat) Replace title with text input on click
    if( $scope[id] ){
      return  true;
=======
  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('hideText elementID', elementID);
    console.log('$scope[elementID]', $scope[elementID]);
    if( !$scope[elementID] ){
      console.log('hideText returning true');
      return  false;
>>>>>>> (fix) Fixed main-title editor after infobox refactor
    } else {
      console.log('hideText returning false');
      return true;
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    // console.log('CALLING SHOW EDITOR');
    // console.log('$index', $index);
    // console.log('field', field);
    // console.log('boolean', boolean);
    // console.log('idPrefix', idPrefix);
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('elementID', elementID);
    $scope.currentIndex = $index;
    if(boolean === false){
      $(elementID).val($scope.renderedNodes[$index][field]);
    }
    console.log('now updating boolean for scope at', elementID);
    $scope[elementID] = boolean;
  };

<<<<<<< HEAD
<<<<<<< HEAD
>>>>>>> (feat) Hide Titles if clicked

=======
  $scope.getPlaceholder = function(){
    return 'place-holder';
=======
  $scope.getPlaceholder = function($index, field){
    console.log("$index", $index);
    console.log('field', field);
    console.log('placeholder', $scope.renderedNodes[$index][field]);
    return $scope.renderedNodes[$index][field];
  };
  $scope.getInfoBoxPlaceholder = function($index, field){
    console.log("$index", $index);
    console.log('field', field);
    console.log('placeholder', $scope.renderedNodes[$index][field]);
    return $scope.renderedNodes[$index][field];
<<<<<<< HEAD
>>>>>>> (feat) Populate editor field with current title
  }
>>>>>>> (feat) Replace title with text input on click
=======
  };

  $scope.saveEdit = function($index, field, idPrefix){
    idPrefix = idPrefix || "";
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var newProperty = $(elementID).val();

    Server.updateNode({ _id: $scope.renderedNodes[$index]._id, title: newProperty})
      .then(function(node) {
      $scope.showEditor($index, field, false);
      $scope.renderedNodes[$index][field] = newProperty;
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };

>>>>>>> (feat) Work on updatenode API

 // Get the current number of upvotes from current map
 $scope.getCountVotes = function(votes){
    $scope.votesCount = 0;
    for(var i = 0; i < votes.length; i++){
      $scope.votesCount++;
    }
    return $scope.votesCount;
 }

 // Renders the nodes for the current roadmap to the page
  $scope.renderNodes = function(){
    var title = $scope.currentRoadMapData.title || 'test title';
    var nodes = $scope.currentRoadMapData.nodes || ['testnode1', 'testnode2'];
    // Add an index to nodes to make ng-clicking easier
    nodes.map(function(node,index){
      node.index = index;
    });

    $scope.renderedNodes = nodes;
    $scope.roadMapTitle = title;

    // User Logged in Data in the future
    // Some variable that holds that the user is logged in
    $scope.currentNode = nodes[0];
    $scope.renderCurrentNode();
  };
  // Make a $scope.renderComments()
  $scope.renderComments = function(){
    var comments = $scope.currentRoadMapData.comments;
    console.log(comments);
    comments.map(function(comment,index){
      comment.index = index;
    })
    $scope.renderedComments = comments;
  }

  // When roadmap (identified by its id) data is fetched, set it
  Server.getRoadmapById(roadmapId).then(function (res){
      $scope.currentRoadMapData = res;
      console.log($scope.currentRoadMapData,'I am the roadmap');
    }, function(err){
      if (err) return console.log(err);
    })
    .then(function(){
      $scope.renderNodes();
      $scope.renderComments();
      // Set the upvotes and downvotes
      var currentMapUpVotes = $scope.currentRoadMapData.upvotes;
      var currentMapDownVotes = $scope.currentRoadMapData.downvotes;
      $scope.upVoteCount = $scope.getCountVotes(currentMapUpVotes);
      $scope.downVoteCount = $scope.getCountVotes(currentMapDownVotes);
  });

  // Render Title
  // Assumes title links and description properties from get method
  $scope.renderCurrentNode = function(){
    // For now lets make $scope.loggedIn be false, if logged in we can change it to true later.
    $scope.loggedin = false;
    if($scope.loggedIn) {
      // Get node index
      // set currentNode into node at that index;
    } else {
      //links from a node
      var links = $scope.renderedNodes[0].resourceURL;
      //description of a node
      var description = $scope.renderedNodes[0].description;
      var title = $scope.renderedNodes[0].title;
    }

    $scope.currentTitle = title;
    $scope.currentLinks = [links];
    $scope.currentDescription = description;
  }

  $scope.selectNode = function($index) {

    var links = $scope.renderedNodes[$index].resourceURL;
    var description = $scope.renderedNodes[$index].description;
    var title = $scope.renderedNodes[$index].title;

    $scope.currentIndex = $index;
    $scope.currentTitle = title;
    $scope.currentLinks = links;
<<<<<<< HEAD
    $scope.currentResourceURL = $scope.currentLinks[0];
    $scope.currentDescription = description;
=======
    $scope.currentNodeDescription = description;
>>>>>>> (fix) Fixed main-title editor after infobox refactor
    $scope.currentNode = $scope.renderedNodes[$index];

  };
  // Submits a node to the user's inProgress.nodes array.
  $scope.submitCompletedNode = function() {
    var nodeId = $scope.currentNode._id;
    User.completeNodeById(nodeId);
    Materialize.toast('Node Complete!', 4000, 'orangeToast');
  }

  // Submits a roadmap to the user's completedRoadmaps array.
  $scope.submitCompletedRoadmap = function() {
    Materialize.toast('Map Complete!', 4000, 'orangeToast');
    User.completeRoadmapById(roadmapId);
    $state.go('home.dashboard', {type: 'completed'});
  }

  // After upvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.upVoteMap = function () {
    User.upvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    })
  }

  // After downvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.downVoteMap = function () {
    User.downvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    });
  };

  $scope.connectLines = function(){
    $('.endPointForConnection').connections();
  };

  // We need async because ng-repeat creates the nodes before this function runs set timeout changes the loop.
  $scope.asyncConnectLines = function(cb){
    setTimeout($scope.connectLines,0);
  };

  $scope.subject = '';
  $scope.content = '';

  $scope.postComment = function(){
    // Will probably need to refactor
    $scope.currentRoadMapData.comments = $scope.currentRoadMapData.comments || [];

    Server.createComment({
      subject: $scope.subject,
      content: $scope.content,
      roadmap: $scope.currentRoadMapData._id
    });
  };

}]);<commit_msg>(fix) Editor disappears on node save<commit_after>angular.module('roadmaps.ctrl', ['roadmaps.factory', 'services.server', 'services.user'])

.controller('RoadMapsController', [ '$scope', '$http', '$stateParams', 'RoadMapsFactory', 'Server', 'User', '$timeout', '$state', function($scope, $http, $stateParams, RoadMapsFactory, Server, User, $timeout, $state){
  angular.extend($scope, RoadMapsFactory);

  var roadmapId = $stateParams.roadmapID;
  $scope.currentRoadMapData = {};
  $scope.renderedNodes = [];
  $('.tooltipped').tooltip({delay: 50});

  $scope.showComments = false;
  $scope.currentIndex = 0;

  $scope.toggleComments = function(){
    $scope.showComments = true;
  };

<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    if( !$scope[elementID] ){
      return  false;
    } else {
      return true;
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    $scope.currentIndex = $index;
    if( !$scope.currentResourceURL ) {
      $scope.currentResourceURL = $scope.currentLinks[0];
    }
    if(boolean === false){
      $(elementID).val($scope.renderedNodes[$index][field]);
    }
    $scope[elementID] = boolean;
  };

  $scope.getPlaceholder = function($index, field){
    var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
    if( field === 'resourceURL'){
      console.log('capitalizedField', capitalizedField);
      console.log('current resourceURL getPlaceholder', $scope['current' + capitalizedField]);
    }
    return $scope['current' + capitalizedField];
  };

  $scope.saveEdit = function($index, field, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('elementID', $(elementID));
    var newProperty = $(elementID).val();
    console.log('newProperty', newProperty);
    var updateObj = {};
    updateObj['_id'] = $scope.renderedNodes[$index]._id;
    updateObj[field] = newProperty;
    Server.updateNode(updateObj)
      .then(function(node) {
      $scope.showEditor($index, field, false, idPrefix);
      $scope.renderedNodes[$index][field] = newProperty;
      var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
      console.log('capitalizedField', capitalizedField);
      $scope['current' + capitalizedField] = newProperty;
      if( field === 'resourceURL' ){
        $scope.currentLinks[0] = newProperty;
      }
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };
=======
  $scope.hideText = function ($index){
    var id = 'title-' + $index;
=======
  $scope.hideText = function ($index, field){
    var id = field + '-' + $index;
>>>>>>> (feat) Replace title with text input on click
    if( $scope[id] ){
      return  true;
=======
  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('hideText elementID', elementID);
    console.log('$scope[elementID]', $scope[elementID]);
    if( !$scope[elementID] ){
      console.log('hideText returning true');
      return  false;
>>>>>>> (fix) Fixed main-title editor after infobox refactor
    } else {
      console.log('hideText returning false');
      return true;
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    // console.log('CALLING SHOW EDITOR');
    // console.log('$index', $index);
    // console.log('field', field);
    // console.log('boolean', boolean);
    // console.log('idPrefix', idPrefix);
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    console.log('elementID', elementID);
    $scope.currentIndex = $index;
    if(boolean === false){
      $(elementID).val($scope.renderedNodes[$index][field]);
    }
    console.log('now updating boolean for scope at', elementID);
    $scope[elementID] = boolean;
  };

<<<<<<< HEAD
<<<<<<< HEAD
>>>>>>> (feat) Hide Titles if clicked

=======
  $scope.getPlaceholder = function(){
    return 'place-holder';
=======
  $scope.getPlaceholder = function($index, field){
    console.log("$index", $index);
    console.log('field', field);
    console.log('placeholder', $scope.renderedNodes[$index][field]);
    return $scope.renderedNodes[$index][field];
  };
  $scope.getInfoBoxPlaceholder = function($index, field){
    console.log("$index", $index);
    console.log('field', field);
    console.log('placeholder', $scope.renderedNodes[$index][field]);
    return $scope.renderedNodes[$index][field];
<<<<<<< HEAD
>>>>>>> (feat) Populate editor field with current title
  }
>>>>>>> (feat) Replace title with text input on click
=======
  };

  $scope.saveEdit = function($index, field, idPrefix){
    idPrefix = idPrefix || "";
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var newProperty = $(elementID).val();

    Server.updateNode({ _id: $scope.renderedNodes[$index]._id, title: newProperty})
      .then(function(node) {
      console.log('node saved !!!');
      $scope.showEditor($index, field, false, idPrefix);
      $scope.renderedNodes[$index][field] = newProperty;
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };

>>>>>>> (feat) Work on updatenode API

 // Get the current number of upvotes from current map
 $scope.getCountVotes = function(votes){
    $scope.votesCount = 0;
    for(var i = 0; i < votes.length; i++){
      $scope.votesCount++;
    }
    return $scope.votesCount;
 }

 // Renders the nodes for the current roadmap to the page
  $scope.renderNodes = function(){
    var title = $scope.currentRoadMapData.title || 'test title';
    var nodes = $scope.currentRoadMapData.nodes || ['testnode1', 'testnode2'];
    // Add an index to nodes to make ng-clicking easier
    nodes.map(function(node,index){
      node.index = index;
    });

    $scope.renderedNodes = nodes;
    $scope.roadMapTitle = title;

    // User Logged in Data in the future
    // Some variable that holds that the user is logged in
    $scope.currentNode = nodes[0];
    $scope.renderCurrentNode();
  };
  // Make a $scope.renderComments()
  $scope.renderComments = function(){
    var comments = $scope.currentRoadMapData.comments;
    console.log(comments);
    comments.map(function(comment,index){
      comment.index = index;
    })
    $scope.renderedComments = comments;
  }

  // When roadmap (identified by its id) data is fetched, set it
  Server.getRoadmapById(roadmapId).then(function (res){
      $scope.currentRoadMapData = res;
      console.log($scope.currentRoadMapData,'I am the roadmap');
    }, function(err){
      if (err) return console.log(err);
    })
    .then(function(){
      $scope.renderNodes();
      $scope.renderComments();
      // Set the upvotes and downvotes
      var currentMapUpVotes = $scope.currentRoadMapData.upvotes;
      var currentMapDownVotes = $scope.currentRoadMapData.downvotes;
      $scope.upVoteCount = $scope.getCountVotes(currentMapUpVotes);
      $scope.downVoteCount = $scope.getCountVotes(currentMapDownVotes);
  });

  // Render Title
  // Assumes title links and description properties from get method
  $scope.renderCurrentNode = function(){
    // For now lets make $scope.loggedIn be false, if logged in we can change it to true later.
    $scope.loggedin = false;
    if($scope.loggedIn) {
      // Get node index
      // set currentNode into node at that index;
    } else {
      //links from a node
      var links = $scope.renderedNodes[0].resourceURL;
      //description of a node
      var description = $scope.renderedNodes[0].description;
      var title = $scope.renderedNodes[0].title;
    }

    $scope.currentTitle = title;
    $scope.currentLinks = [links];
    $scope.currentDescription = description;
  }

  $scope.selectNode = function($index) {

    var links = $scope.renderedNodes[$index].resourceURL;
    var description = $scope.renderedNodes[$index].description;
    var title = $scope.renderedNodes[$index].title;

    $scope.currentIndex = $index;
    $scope.currentTitle = title;
    $scope.currentLinks = links;
<<<<<<< HEAD
    $scope.currentResourceURL = $scope.currentLinks[0];
    $scope.currentDescription = description;
=======
    $scope.currentNodeDescription = description;
>>>>>>> (fix) Fixed main-title editor after infobox refactor
    $scope.currentNode = $scope.renderedNodes[$index];

  };
  // Submits a node to the user's inProgress.nodes array.
  $scope.submitCompletedNode = function() {
    var nodeId = $scope.currentNode._id;
    User.completeNodeById(nodeId);
    Materialize.toast('Node Complete!', 4000, 'orangeToast');
  }

  // Submits a roadmap to the user's completedRoadmaps array.
  $scope.submitCompletedRoadmap = function() {
    Materialize.toast('Map Complete!', 4000, 'orangeToast');
    User.completeRoadmapById(roadmapId);
    $state.go('home.dashboard', {type: 'completed'});
  }

  // After upvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.upVoteMap = function () {
    User.upvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    })
  }

  // After downvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.downVoteMap = function () {
    User.downvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    });
  };

  $scope.connectLines = function(){
    $('.endPointForConnection').connections();
  };

  // We need async because ng-repeat creates the nodes before this function runs set timeout changes the loop.
  $scope.asyncConnectLines = function(cb){
    setTimeout($scope.connectLines,0);
  };

  $scope.subject = '';
  $scope.content = '';

  $scope.postComment = function(){
    // Will probably need to refactor
    $scope.currentRoadMapData.comments = $scope.currentRoadMapData.comments || [];

    Server.createComment({
      subject: $scope.subject,
      content: $scope.content,
      roadmap: $scope.currentRoadMapData._id
    });
  };

}]);<|endoftext|>


<commit_before>/*globals console sparks $ breadModel getBreadBoard */

(function() {

  /*
   * Sparks Activity Controller can be accessed by the
   * singleton variable sparks.sparksActivityController
   */
  sparks.SparksActivityController = function(){
    sparks.sparksActivity = new sparks.SparksActivity();

    this.currentSection = null;
    this.currentSectionIndex = 0;
    this.sectionMap = {};
  };

  sparks.SparksActivityController.prototype = {

    createActivity: function(activity, callback) {
      sparks.sparksActivity.id = activity._id;
      var self = this;
      var totalCreated = 0;
      $.each(activity.sections, function(i, jsonSection){
        if (!!jsonSection.pages){
          self.addSection(jsonSection, i);
          totalCreated++;
          if (totalCreated == activity.sections.length){
            callback();
          }
        } else {
          sparks.couchDS.loadActivity(jsonSectionName, function(jsonSection) {
            self.addSection(jsonSection, i);
            totalCreated++;
            if (totalCreated == activity.sections.length){
              callback();
            }
          });
        }
      });
    },

    addSection: function (jsonSection, index) {
      // var _id = jsonSection._id;
      // var sectionExists = false;
      // var index = -1;
      // $.each(sparks.sparksActivity.sections, function(i, section){
      //   if (section.id === _id){
      //     sectionExists = true;
      //     index = i;
      //   }
      // });

      // if we're just making a one-section activity
      if (!sparks.sparksActivity.id){
        sparks.sparksActivity.id = jsonSection._id;
      }

      var section = sparks.sparksSectionController.createSection(jsonSection);
      // this.currentSection = section;

      if (index !== undefined){
        sparks.sparksActivity.sections[index] = section;
      } else {
        sparks.sparksActivity.sections.push(section);
      }
      this.sectionMap[section.id] = section;

      return section;

      //
    },

    setCurrentSection: function(i) {
      this.currentSection = sparks.sparksActivity.sections[i];
      this.currentSectionIndex = i;
    },

    areMoreSections: function () {
      return !(this.currentSectionIndex >= sparks.sparksActivity.sections.length -1);
    },

    nextSection: function () {
      if (this.currentSectionIndex > sparks.sparksActivity.sections.length -1) {
        return;
      }
      this.setCurrentSection(this.currentSectionIndex + 1);
      sparks.sparksSectionController.currentPageIndex = 0;
      sparks.sparksSectionController.loadCurrentSection();
      sparks.sparksActivity.view.layoutCurrentSection();
      // this.currentSection.view.clear();
      //       breadModel('clear');
      //       window.location.hash = this.currentSection.nextSection;
      //       sparks.activity.onDocumentReady();
    },

    findSection: function(id){
      return this.sectionMap[id];
    },

    reset: function () {
      sparks.sparksActivity.sections = [];

      sparks.sparksSectionController.currentPage = null;
      sparks.sparksSectionController.currentPageIndex = -1;
      sparks.sparksSectionController.pageIndexMap = {};
    }

  };

  sparks.sparksActivityController = new sparks.SparksActivityController();
})();<commit_msg>Fix loading in of activity with named sections<commit_after>/*globals console sparks $ breadModel getBreadBoard */

(function() {

  /*
   * Sparks Activity Controller can be accessed by the
   * singleton variable sparks.sparksActivityController
   */
  sparks.SparksActivityController = function(){
    sparks.sparksActivity = new sparks.SparksActivity();

    this.currentSection = null;
    this.currentSectionIndex = 0;
    this.sectionMap = {};
  };

  sparks.SparksActivityController.prototype = {

    createActivity: function(activity, callback) {
      sparks.sparksActivity.id = activity._id;
      var self = this;
      var totalCreated = 0;
      $.each(activity.sections, function(i, jsonSection){
        if (!!jsonSection.pages){
          self.addSection(jsonSection, i);
          totalCreated++;
          if (totalCreated == activity.sections.length){
            callback();
          }
        } else {
          sparks.couchDS.loadActivity(jsonSection, function(jsonSection) {
            self.addSection(jsonSection, i);
            totalCreated++;
            if (totalCreated == activity.sections.length){
              callback();
            }
          });
        }
      });
    },

    addSection: function (jsonSection, index) {
      // var _id = jsonSection._id;
      // var sectionExists = false;
      // var index = -1;
      // $.each(sparks.sparksActivity.sections, function(i, section){
      //   if (section.id === _id){
      //     sectionExists = true;
      //     index = i;
      //   }
      // });

      // if we're just making a one-section activity
      if (!sparks.sparksActivity.id){
        sparks.sparksActivity.id = jsonSection._id;
      }

      var section = sparks.sparksSectionController.createSection(jsonSection);
      // this.currentSection = section;

      if (index !== undefined){
        sparks.sparksActivity.sections[index] = section;
      } else {
        sparks.sparksActivity.sections.push(section);
      }
      this.sectionMap[section.id] = section;

      return section;

      //
    },

    setCurrentSection: function(i) {
      this.currentSection = sparks.sparksActivity.sections[i];
      this.currentSectionIndex = i;
    },

    areMoreSections: function () {
      return !(this.currentSectionIndex >= sparks.sparksActivity.sections.length -1);
    },

    nextSection: function () {
      if (this.currentSectionIndex > sparks.sparksActivity.sections.length -1) {
        return;
      }
      this.setCurrentSection(this.currentSectionIndex + 1);
      sparks.sparksSectionController.currentPageIndex = 0;
      sparks.sparksSectionController.loadCurrentSection();
      sparks.sparksActivity.view.layoutCurrentSection();
      // this.currentSection.view.clear();
      //       breadModel('clear');
      //       window.location.hash = this.currentSection.nextSection;
      //       sparks.activity.onDocumentReady();
    },

    findSection: function(id){
      return this.sectionMap[id];
    },

    reset: function () {
      sparks.sparksActivity.sections = [];

      sparks.sparksSectionController.currentPage = null;
      sparks.sparksSectionController.currentPageIndex = -1;
      sparks.sparksSectionController.pageIndexMap = {};
    }

  };

  sparks.sparksActivityController = new sparks.SparksActivityController();
})();<|endoftext|>


<commit_before>'use strict';
angular.module('myApp')
.controller('ApproverApplicationCtrl', function ($scope, $state, $stateParams, DataService, $rootScope, $uibModal, $http) {

  if(!$stateParams.appId) {
    $state.go('approverHome', []);
  }
  DataService.getApplicationById($stateParams.appId).then(function (result) {
    if(result) {
      $rootScope.application = result;
    } else {
      //TODO: handle error
    }
  });

  $scope.open = function () {
    var modalInstance = $uibModal.open({
      animation: true,
      templateUrl: 'applicationReturnedModal.html',
      controller: 'ReturnModalCtrl',
      resolve: {
        comment: function () {
          return $scope.comment;
        }
      }
    });

    modalInstance.result.then(function (comment) {
      DataService.returnApplication($stateParams.appId).then(function (result) {
        if(result) {
          $rootScope.application = result;
          $rootScope.application.requestContent.reviewDetails.comments = comment;
          $state.go('approverHome');
        }
      });
    });
  };

  $scope.return = function () {
    $scope.open();
  };

  $scope.downloadFile = function (doc) {
    var id = $rootScope.application._id;
    var docId = doc.docId;
    function b64toBlob(b64Data, contentType, sliceSize) {
        contentType = contentType || '';
        sliceSize = sliceSize || 512;

        var byteCharacters = atob(b64Data);
        var byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);

            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
               byteNumbers[i] = slice.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        }
        var blob = new Blob(byteArrays, {type: contentType});
        return blob;
    }

    DataService.getAttachment(id, docId).then(function (result) {
        if(result) {
            var base64 = result.base64String;
            var fileName = result.fileName;
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            var blob = b64toBlob(base64, "octet/stream", 512);
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = fileName;
            a.click();
            window.URL.revokeObjectURL(url);
        }
    });
  };
});
<commit_msg>removed unused  from controller params<commit_after>'use strict';
angular.module('myApp')
.controller('ApproverApplicationCtrl', function ($scope, $state, $stateParams, DataService, $rootScope, $uibModal) {

  if(!$stateParams.appId) {
    $state.go('approverHome', []);
  }
  DataService.getApplicationById($stateParams.appId).then(function (result) {
    if(result) {
      $rootScope.application = result;
    } else {
      //TODO: handle error
    }
  });

  $scope.open = function () {
    var modalInstance = $uibModal.open({
      animation: true,
      templateUrl: 'applicationReturnedModal.html',
      controller: 'ReturnModalCtrl',
      resolve: {
        comment: function () {
          return $scope.comment;
        }
      }
    });

    modalInstance.result.then(function (comment) {
      DataService.returnApplication($stateParams.appId).then(function (result) {
        if(result) {
          $rootScope.application = result;
          $rootScope.application.requestContent.reviewDetails.comments = comment;
          $state.go('approverHome');
        }
      });
    });
  };

  $scope.return = function () {
    $scope.open();
  };

  $scope.downloadFile = function (doc) {
    var id = $rootScope.application._id;
    var docId = doc.docId;
    function b64toBlob(b64Data, contentType, sliceSize) {
        contentType = contentType || '';
        sliceSize = sliceSize || 512;

        var byteCharacters = atob(b64Data);
        var byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);

            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
               byteNumbers[i] = slice.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        }
        var blob = new Blob(byteArrays, {type: contentType});
        return blob;
    }

    DataService.getAttachment(id, docId).then(function (result) {
        if(result) {
            var base64 = result.base64String;
            var fileName = result.fileName;
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            var blob = b64toBlob(base64, "octet/stream", 512);
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = fileName;
            a.click();
            window.URL.revokeObjectURL(url);
        }
    });
  };
});
<|endoftext|>


<commit_before>app.controller("RecommendationsController", function(
    $scope, $location, $timeout, cardService, recommendationService) {
  var deckUrl = $location.search().q;
  $scope.loading = true;

  recommendationService.getRecommendations(deckUrl)
      .then(function(recommendations) {
        $scope.loading = false;
        $scope.deckUrl = deckUrl;
        $scope.recommendations = recommendations;

        // Don't run Masonry until the next digest cycle so that the
        // sections have had a chance to render.
        $timeout(function() {
          var moreRecommendations = $("#moreRecommendations #adds");
          moreRecommendations.masonry({
            itemSelector: "more-recommendations"
          });
        }, 1000);
      }).catch(function(errorMessage) {
        $scope.loading = false;
        $scope.error = errorMessage;
      });

  $scope.getCardUrl = function(name) {
    return cardService.getCardUrl(name);
  };

  $scope.getCardImage = function(name) {
    return cardService.getCardImage(name);
  };
});
<commit_msg>Fix "your deck" link when user omits protocol<commit_after>app.controller("RecommendationsController", function(
    $scope, $location, $timeout, cardService, recommendationService) {
  var deckUrl = $location.search().q;
  $scope.loading = true;

  recommendationService.getRecommendations(deckUrl)
      .then(function(recommendations) {
        if (deckUrl.indexOf("http") < 0) {
          deckUrl = "http://" + deckUrl;
        }

        $scope.loading = false;
        $scope.deckUrl = deckUrl;
        $scope.recommendations = recommendations;

        // Don't run Masonry until the next digest cycle so that the
        // sections have had a chance to render.
        $timeout(function() {
          var moreRecommendations = $("#moreRecommendations #adds");
          moreRecommendations.masonry({
            itemSelector: "more-recommendations"
          });
        }, 1000);
      }).catch(function(errorMessage) {
        $scope.loading = false;
        $scope.error = errorMessage;
      });

  $scope.getCardUrl = function(name) {
    return cardService.getCardUrl(name);
  };

  $scope.getCardImage = function(name) {
    return cardService.getCardImage(name);
  };
});
<|endoftext|>


<commit_before>module.exports = function($target, room, $room_box) {
    var canvas_handler = require('../../../shared/canvas_handler');

    get_page('mini_black_board', function(page) {
        $target.append(page.$container);
        page.$container.attr('room_id', room.id);

        $room_box.prop('whewboard', page.$container);

        var canvas = page.$("#mini_black_board_canvas")[0];
        var ctx = canvas.getContext('2d');
        ctx.scale(0.2, 0.2);

        var ch = canvas_handler(ctx);

        page.$("#mini_black_board_canvas").on('click', function() {
            app.open_black_board();
        });

        var pass_it_up = function(data) {
            if (app.black_board && app.black_board.closed != true) {
                app.black_board.postMessage(data, app.domain);
            }
        };

        page.peepy('black_board.load', function(data) {
            data.type = 'load';
            pass_it_up(data);

            ch.handle_thing({type: 'colorful_clear', data: {color: data.bg_color, nuke: true}});

            data.data.forEach(function(thing) {
                ch.handle_thing(thing);
            });

        });

        page.peepy('black_board.draw', function(info) {
            pass_it_up(info);
            ch.handle_thing(info);
        });

        // Not hacky at all.
        if (app.is_mobile) {
            $("#mini_black_board").hide();
            $("#users").attr('style', 'height: 100%;');
        }

    });
};<commit_msg>Sandbox boards<commit_after>module.exports = function($target, room, $room_box) {
    var canvas_handler = require('../../../shared/canvas_handler');

    get_page('mini_black_board', function(page) {
        $target.append(page.$container);
        page.$container.attr('room_id', room.id);

        $room_box.prop('whewboard', page.$container);

        var canvas = page.$("#mini_black_board_canvas")[0];
        var ctx = canvas.getContext('2d');
        ctx.scale(0.2, 0.2);

        var ch = canvas_handler(ctx);

        page.$("#mini_black_board_canvas").on('click', function() {
            app.open_black_board();
        });

        var pass_it_up = function(data) {
            if (app.black_board && app.black_board.closed != true) {
                app.black_board.postMessage(data, app.domain);
            }
        };

        page.peepy('black_board.load', function(data) {
            if (data.room_id == room.id) {
                data.type = 'load';
                pass_it_up(data);

                ch.handle_thing({type: 'colorful_clear', data: {color: data.bg_color, nuke: true}});

                data.data.forEach(function(thing) {
                    ch.handle_thing(thing);
                });
            }
        });

        page.peepy('black_board.draw', function(info) {
            console.log(info);
            if (info.room_id == room.id) {
                pass_it_up(info);
                ch.handle_thing(info);
            }
        });

        // Not hacky at all.
        if (app.is_mobile) {
            $("#mini_black_board").hide();
            $("#users").attr('style', 'height: 100%;');
        }

    });
};<|endoftext|>


<commit_before>import { List as IList, Map as IMap } from 'immutable';
import axios from 'axios';
import AppRecord from '../records/app_record';
import IoRecord from '../records/io_record';
import IoResultRecord from '../records/io_result_record';
import RunRecord from '../records/run_record';
import WidgetRecord from '../records/widget_record';
import WidgetRunRecord from '../records/widget_run_record';
import ioUtils from './io_utils';

const API_URL = process.env.API_URL || '';

const apiUtils = {
  /**
   * Start a run
   * @param {String} appId
   * @param {String} email
   * @param {IList} inputs
   * @param {String} selectedLigand
   * @param {String} [inputString]
   * @returns {Promise}
   */
  run(appId, email, inputResults, inputString) {
    return axios.post(`${API_URL}/v1/run`, {
      appId,
      email,
      inputs: ioUtils.formatInputResultsForServer(inputResults),
      inputString,
    }).then(res => res.data.runId);
  },

  getApp(appId) {
    return axios.get(`${API_URL}/v1/app/${appId}`).then((res) => {
      const widgets = new IList(
        res.data.widgets.map((widgetData) => {
          const inputs = widgetData.inputs ? new IList(widgetData.inputs.map(
            input => new IoRecord(input),
          )) : new IList();
          const outputs = widgetData.outputs ? new IList(widgetData.outputs.map(
            output => new IoRecord(output),
          )) : new IList();

          return new WidgetRecord(
            Object.assign({}, widgetData, { inputs, outputs })
          );
        }),
      );
      return new AppRecord(Object.assign({}, res.data, {
        widgets,
        run: new RunRecord({
          widgetRuns: res.data.widgets.reduce((reduction, widget) =>
            reduction.set(widget.id, new WidgetRunRecord({
              widgetId: widget.id,
            })),
            new IMap(),
          ),
        }),
      }));
    });
  },

  getApps() {
    return axios.get(`${API_URL}/v1/app`).then(res =>
      res.data.map(appData => new AppRecord(appData)),
    );
  },

  getRun(runId) {
    return axios.get(`${API_URL}/v1/run/${runId}`).then(res =>
      res.data,
    ).then((runData) => {
      const widgets = new IList(
        runData.app.widgets.map((widgetData) => {
          const inputs = widgetData.inputs ? new IList(widgetData.inputs.map(
            input => new IoRecord(input),
          )) : new IList();
          const outputs = widgetData.outputs ? new IList(widgetData.outputs.map(
            output => new IoRecord(output),
          )) : new IList();

          return new WidgetRecord(
            Object.assign({}, widgetData, { inputs, outputs })
          );
        }),
      );
      let ioResults = new IMap();
      runData.inputs.forEach((inputData) => {
        const inputResult = new IoResultRecord(Object.assign({}, inputData, {
          ioId: inputData.name,
        }));
        ioResults = ioResults.set(inputResult.ioId, inputResult);
      });
      runData.outputs.forEach((outputData) => {
        const outputResult = new IoResultRecord(Object.assign({}, outputData, {
          ioId: outputData.name,
        }));
        ioResults = ioResults.set(outputResult.ioId, outputResult);
      });

      return new AppRecord(Object.assign({}, runData, runData.app, {
        widgets,
        run: new RunRecord(Object.assign({}, runData, { ioResults })),
      }));
    });
  },

  cancelRun(runId) {
    return axios.post(`${API_URL}/v1/run/cancel`, {
      runId,
    });
  },

  /**
   * Process the input given by the user and return processed input
   * @param appId {String}
   * @param input {String} PDB, IUPAC, InChi, SMILES
   * @param extension {String} Optional
   * @returns {Promise}
   */
  processInput(appId, input, extension) {
    /*
     * For PDB, a sent input looks like:
     *   {
     *     name: 'input.pdb',
     *     type: 'inline',
     *     value: 'imapdbstring',
     *   },
     * For other formats, sent inputs look like:
     *   {
     *     name: 'input.json',
     *     type: 'inline',
     *     value: '{"input":"acetylene"}',
     *   },
     */
    let value;
    let nameExtension;
    if (extension) {
      value = input;
      nameExtension = extension;
    } else {
      value = JSON.stringify({ input });
      nameExtension = 'json';
    }

    const data = {
      inputs: [
        {
          name: `input.${nameExtension}`,
          type: 'inline',
          value,
        },
      ],
    };
    return axios.post(`${API_URL}/v1/structure/executeApp${appId}Step0`, data)
      .then((res) => {
        if (!res.data.success) {
          const error = new Error('Failed to process this input, please try again.');
          error.result = res.data;
          throw error;
        }

        return new IList(res.data.outputs.map(output =>
          // Remap name to ioId for clarity
          new IoResultRecord(Object.assign({}, output, {
            ioId: output.name,
          })),
        ));
      });
  },

  /**
   * Fetch and parse the json file that is returned from step0 input processing
   * @param jsonUrl {String}
   * @returns {Promise}
   */
  getIoResultData(jsonUrl) {
    return axios.get(jsonUrl).then(res => res.data);
  },

  /**
   * Get the pdb data string from its url
   * @param pdbUrl {String}
   * @returns {String}
   */
  getPdb(pdbUrl) {
    return axios.get(pdbUrl).then(res => res.data);
  },
};

export default apiUtils;
<commit_msg>Can transition to thank you page properly<commit_after>import { List as IList, Map as IMap } from 'immutable';
import axios from 'axios';
import AppRecord from '../records/app_record';
import IoRecord from '../records/io_record';
import IoResultRecord from '../records/io_result_record';
import RunRecord from '../records/run_record';
import WidgetRecord from '../records/widget_record';
import WidgetRunRecord from '../records/widget_run_record';
import ioUtils from './io_utils';

const API_URL = process.env.API_URL || '';

const apiUtils = {
  /**
   * Start a run
   * @param {String} appId
   * @param {String} email
   * @param {IList} inputs
   * @param {String} selectedLigand
   * @param {String} [inputString]
   * @returns {Promise}
   */
  run(appId, email, inputResults, inputString) {
    return axios.post(`${API_URL}/v1/run`, {
      appId,
      email,
      inputs: ioUtils.formatInputResultsForServer(inputResults),
      inputString,
    }).then(res => res.data.runId);
  },

  getApp(appId) {
    return axios.get(`${API_URL}/v1/app/${appId}`).then((res) => {
      const widgets = new IList(
        res.data.widgets.map((widgetData) => {
          const inputs = widgetData.inputs ? new IList(widgetData.inputs.map(
            input => new IoRecord(input),
          )) : new IList();
          const outputs = widgetData.outputs ? new IList(widgetData.outputs.map(
            output => new IoRecord(output),
          )) : new IList();

          return new WidgetRecord(
            Object.assign({}, widgetData, { inputs, outputs })
          );
        }),
      );
      return new AppRecord(Object.assign({}, res.data, {
        widgets,
        run: new RunRecord({
          widgetRuns: res.data.widgets.reduce((reduction, widget) =>
            reduction.set(widget.id, new WidgetRunRecord({
              widgetId: widget.id,
            })),
            new IMap(),
          ),
        }),
      }));
    });
  },

  getApps() {
    return axios.get(`${API_URL}/v1/app`).then(res =>
      res.data.map(appData => new AppRecord(appData)),
    );
  },

  getRun(runId) {
    return axios.get(`${API_URL}/v1/run/${runId}`).then(res =>
      res.data,
    ).then((runData) => {
      const widgets = new IList(
        runData.app.widgets.map((widgetData) => {
          const inputs = widgetData.inputs ? new IList(widgetData.inputs.map(
            input => new IoRecord(input),
          )) : new IList();
          const outputs = widgetData.outputs ? new IList(widgetData.outputs.map(
            output => new IoRecord(output),
          )) : new IList();

          return new WidgetRecord(
            Object.assign({}, widgetData, { inputs, outputs })
          );
        }),
      );
      let ioResults = new IMap();
      const inputDatas = runData.inputs || [];
      const outputDatas = runData.outputs || [];
      inputDatas.forEach((inputData) => {
        const inputResult = new IoResultRecord(Object.assign({}, inputData, {
          ioId: inputData.name,
        }));
        ioResults = ioResults.set(inputResult.ioId, inputResult);
      });
      outputDatas.forEach((outputData) => {
        const outputResult = new IoResultRecord(Object.assign({}, outputData, {
          ioId: outputData.name,
        }));
        ioResults = ioResults.set(outputResult.ioId, outputResult);
      });

      return new AppRecord(Object.assign({}, runData, runData.app, {
        widgets,
        run: new RunRecord(Object.assign({}, runData, { ioResults })),
      }));
    });
  },

  cancelRun(runId) {
    return axios.post(`${API_URL}/v1/run/cancel`, {
      runId,
    });
  },

  /**
   * Process the input given by the user and return processed input
   * @param appId {String}
   * @param input {String} PDB, IUPAC, InChi, SMILES
   * @param extension {String} Optional
   * @returns {Promise}
   */
  processInput(appId, input, extension) {
    /*
     * For PDB, a sent input looks like:
     *   {
     *     name: 'input.pdb',
     *     type: 'inline',
     *     value: 'imapdbstring',
     *   },
     * For other formats, sent inputs look like:
     *   {
     *     name: 'input.json',
     *     type: 'inline',
     *     value: '{"input":"acetylene"}',
     *   },
     */
    let value;
    let nameExtension;
    if (extension) {
      value = input;
      nameExtension = extension;
    } else {
      value = JSON.stringify({ input });
      nameExtension = 'json';
    }

    const data = {
      inputs: [
        {
          name: `input.${nameExtension}`,
          type: 'inline',
          value,
        },
      ],
    };
    return axios.post(`${API_URL}/v1/structure/executeApp${appId}Step0`, data)
      .then((res) => {
        if (!res.data.success) {
          const error = new Error('Failed to process this input, please try again.');
          error.result = res.data;
          throw error;
        }

        return new IList(res.data.outputs.map(output =>
          // Remap name to ioId for clarity
          new IoResultRecord(Object.assign({}, output, {
            ioId: output.name,
          })),
        ));
      });
  },

  /**
   * Fetch and parse the json file that is returned from step0 input processing
   * @param jsonUrl {String}
   * @returns {Promise}
   */
  getIoResultData(jsonUrl) {
    return axios.get(jsonUrl).then(res => res.data);
  },

  /**
   * Get the pdb data string from its url
   * @param pdbUrl {String}
   * @returns {String}
   */
  getPdb(pdbUrl) {
    return axios.get(pdbUrl).then(res => res.data);
  },
};

export default apiUtils;
<|endoftext|>


<commit_before>import Constants from '../constants/constants';

const HeightSource = {
  post: function (data) {
    return $.ajax({
        method: "POST",
        url: Constants["SERVER_URL"] + "/goal",
        data: { goal: data.goal },
        'beforeSend': function(xhr) {
            if (localStorage.getItem('userToken')) {
              xhr.setRequestHeader('Authorization',
                    'Bearer ' + localStorage.getItem('userToken'));
            }
        },
        crossDomain: true
    })
  }
};

export default HeightSource;
<commit_msg>[client] Fixing a typo<commit_after>import Constants from '../constants/constants';

const GoalSource = {
  post: function (data) {
    return $.ajax({
        method: "POST",
        url: Constants["SERVER_URL"] + "/goal",
        data: { goal: data.goal },
        'beforeSend': function(xhr) {
            if (localStorage.getItem('userToken')) {
              xhr.setRequestHeader('Authorization',
                    'Bearer ' + localStorage.getItem('userToken'));
            }
        },
        crossDomain: true
    })
  }
};

export default GoalSource;
<|endoftext|>


<commit_before>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';
import ExpandableStatisticBox from 'Interface/Others/ExpandableStatisticBox';
import { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';

import SPELLS from 'common/SPELLS/index';
import SpellIcon from 'common/SpellIcon';

import { formatPercentage } from 'common/format';

const MS_BUFFER = 100;

class SpiritBombSoulConsume extends Analyzer {

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.SPIRIT_BOMB_TALENT.id);
  }

  castTimestamp = 0;
  castSoulsConsumed = 0;
  cast = 0;

  soulsConsumedByAmount = Array.from({length: 6}, x => 0);

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SPIRIT_BOMB_TALENT.id) {
      return;
    }
    if(this.cast > 0) {
      this.countHits();
    }
    this.castTimestamp = event.timestamp;
    this.cast += 1;
  }

  on_byPlayer_removebuffstack(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SOUL_FRAGMENT_STACK.id) {
      return;
    }
    if (event.timestamp - this.castTimestamp < MS_BUFFER) {
      this.castSoulsConsumed += 1;
    }
  }

  on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SOUL_FRAGMENT_STACK.id) {
      return;
    }
    if (event.timestamp - this.castTimestamp < MS_BUFFER) {
      this.castSoulsConsumed += 1;
    }
  }

  countHits() {
    if (!this.soulsConsumedByAmount[this.castSoulsConsumed]) {
      this.soulsConsumedByAmount[this.castSoulsConsumed] = 1;
      this.castSoulsConsumed = 0;
      return;
    }
    this.soulsConsumedByAmount[this.castSoulsConsumed] += 1;
    this.castSoulsConsumed = 0;
  }

  on_finished() {
    this.countHits();
  }

  statistic() {
    const totalGoodCasts = this.soulsConsumedByAmount[4] + this.soulsConsumedByAmount[5];
    const totalCasts = Object.values(this.soulsConsumedByAmount).reduce((a, b) => a+b, 0);
    const percentGoodCasts = totalGoodCasts / totalCasts;

    return (
      <ExpandableStatisticBox
        icon={<SpellIcon id={SPELLS.SPIRIT_BOMB_TALENT.id} />}
        value={`${formatPercentage(percentGoodCasts)} %`}
        label="Good Spirit Bomb casts"
      >

              Stacks
              Casts

            {Object.values(this.soulsConsumedByAmount).map((stackAmount, castAmount) => (

                {stackAmount}
                {castAmount}

            ))}

      </ExpandableStatisticBox>
    );
  }
  statisticOrder = STATISTIC_ORDER.CORE(6);

}

export default SpiritBombSoulConsume;
<commit_msg>had accidently reversed 2 values<commit_after>import React from 'react';
import Analyzer from 'Parser/Core/Analyzer';
import ExpandableStatisticBox from 'Interface/Others/ExpandableStatisticBox';
import { STATISTIC_ORDER } from 'Interface/Others/StatisticBox';

import SPELLS from 'common/SPELLS/index';
import SpellIcon from 'common/SpellIcon';

import { formatPercentage } from 'common/format';

const MS_BUFFER = 100;

class SpiritBombSoulConsume extends Analyzer {

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.SPIRIT_BOMB_TALENT.id);
  }

  castTimestamp = 0;
  castSoulsConsumed = 0;
  cast = 0;

  soulsConsumedByAmount = Array.from({length: 6}, x => 0);

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SPIRIT_BOMB_TALENT.id) {
      return;
    }
    if(this.cast > 0) {
      this.countHits();
    }
    this.castTimestamp = event.timestamp;
    this.cast += 1;
  }

  on_byPlayer_removebuffstack(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SOUL_FRAGMENT_STACK.id) {
      return;
    }
    if (event.timestamp - this.castTimestamp < MS_BUFFER) {
      this.castSoulsConsumed += 1;
    }
  }

  on_byPlayer_removebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SOUL_FRAGMENT_STACK.id) {
      return;
    }
    if (event.timestamp - this.castTimestamp < MS_BUFFER) {
      this.castSoulsConsumed += 1;
    }
  }

  countHits() {
    if (!this.soulsConsumedByAmount[this.castSoulsConsumed]) {
      this.soulsConsumedByAmount[this.castSoulsConsumed] = 1;
      this.castSoulsConsumed = 0;
      return;
    }
    this.soulsConsumedByAmount[this.castSoulsConsumed] += 1;
    this.castSoulsConsumed = 0;
  }

  on_finished() {
    this.countHits();
  }

  statistic() {
    const totalGoodCasts = this.soulsConsumedByAmount[4] + this.soulsConsumedByAmount[5];
    const totalCasts = Object.values(this.soulsConsumedByAmount).reduce((a, b) => a+b, 0);
    const percentGoodCasts = totalGoodCasts / totalCasts;

    return (
      <ExpandableStatisticBox
        icon={<SpellIcon id={SPELLS.SPIRIT_BOMB_TALENT.id} />}
        value={`${formatPercentage(percentGoodCasts)} %`}
        label="Good Spirit Bomb casts"
      >

              Stacks
              Casts

            {Object.values(this.soulsConsumedByAmount).map((castAmount, stackAmount) => (

                {stackAmount}
                {castAmount}

            ))}

      </ExpandableStatisticBox>
    );
  }
  statisticOrder = STATISTIC_ORDER.CORE(6);

}

export default SpiritBombSoulConsume;
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';

import AbilityTracker from 'Parser/Core/Modules/AbilityTracker';

const TIDAL_WAVES_SPELL_ID = 53390;
const TIDAL_WAVES_BUFF_EXPIRATION_BUFFER = 50; // the buff expiration can occur several MS before the heal event is logged, this is the buffer time that an IoL charge may have dropped during which it will still be considered active.
const TIDAL_WAVES_BUFF_MINIMAL_ACTIVE_TIME = 100; // Minimal duration for which you must have tidal waves. Prevents it from counting a HS/HW as buffed when you cast a riptide at the end.

class ShamanAbilityTracker extends AbilityTracker {
  on_byPlayer_heal(event) {
    if (super.on_byPlayer_heal) {
      super.on_byPlayer_heal(event);
    }
    const spellId = event.ability.guid;
    const cast = this.getAbility(spellId, event.ability);

    if (spellId === SPELLS.HEALING_WAVE.id || spellId === SPELLS.HEALING_SURGE.id) {
      const hasTw = this.owner.selectedCombatant.hasBuff(TIDAL_WAVES_SPELL_ID, event.timestamp, TIDAL_WAVES_BUFF_EXPIRATION_BUFFER,TIDAL_WAVES_BUFF_MINIMAL_ACTIVE_TIME);

      if (hasTw) {
        cast.healingTwHits = (cast.healingTwHits || 0) + 1;
        cast.healingTwHealing = (cast.healingTwHealing || 0) + (event.amount || 0);
        cast.healingTwAbsorbed = (cast.healingTwAbsorbed || 0) + (event.absorbed || 0);
        cast.healingTwOverheal = (cast.healingTwOverheal || 0) + (event.overheal || 0);
      }
    }

  }
}

export default ShamanAbilityTracker;

<commit_msg>Remove unused class ShamanIndirectHealing<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2018
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	var FileMultiSelectMenu = OC.Backbone.View.extend({
		tagName: 'div',
		className: 'filesSelectMenu popovermenu bubble menu-center',
		_scopes: null,
		initialize: function(menuItems) {
			this._scopes = menuItems;
		},
		events: {
			'click a.action': '_onClickAction'
		},

		/**
		 * Renders the menu with the currently set items
		 */
		render: function() {
			this.$el.html(OCA.Files.Templates['filemultiselectmenu']({
				items: this._scopes
			}));
		},
		/**
		 * Displays the menu under the given element
		 *
		 * @param {OCA.Files.FileActionContext} context context
		 * @param {Object} $trigger trigger element
		 */
		show: function(context) {
			this._context = context;
			this.render();
			this.$el.removeClass('hidden');
			if (window.innerWidth < 480) {
				this.$el.removeClass('menu-center').addClass('menu-right');
			} else {
				this.$el.removeClass('menu-right').addClass('menu-center');
			}
			OC.showMenu(null, this.$el);
			return false;
		},
		toggleItemVisibility: function (itemName, show) {
			if (show) {
				this.$el.find('.item-' + itemName).removeClass('hidden');
			} else {
				this.$el.find('.item-' + itemName).addClass('hidden');
			}
		},
		updateItemText: function (itemName, translation) {
			this.$el.find('.item-' + itemName).find('.label').text(translation);
		},
		toggleLoading: function (itemName, showLoading) {
			var $actionElement = this.$el.find('.item-' + itemName);
			if ($actionElement.length === 0) {
				return;
			}
			var $icon = $actionElement.find('.icon');
			if (showLoading) {
				var $loadingIcon = $('');
				$icon.after($loadingIcon);
				$icon.addClass('hidden');
				$actionElement.addClass('disabled');
			} else {
				$actionElement.find('.icon-loading-small').remove();
				$actionElement.find('.icon').removeClass('hidden');
				$actionElement.removeClass('disabled');
			}
		},
		isDisabled: function (itemName) {
			var $actionElement = this.$el.find('.item-' + itemName);
			return $actionElement.hasClass('disabled');
		},
		/**
		 * Event handler whenever an action has been clicked within the menu
		 *
		 * @param {Object} event event object
		 */
		_onClickAction: function (event) {
			var $target = $(event.currentTarget);
			if (!$target.hasClass('menuitem')) {
				$target = $target.closest('.menuitem');
			}

			OC.hideMenus();
			this._context.multiSelectMenuClick(event, $target.data('action'));
			return false;
		}
	});

	OCA.Files.FileMultiSelectMenu = FileMultiSelectMenu;
})(OC, OCA);
<commit_msg>Do not rerender the selection menu on show<commit_after>/*
 * Copyright (c) 2018
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	var FileMultiSelectMenu = OC.Backbone.View.extend({
		tagName: 'div',
		className: 'filesSelectMenu popovermenu bubble menu-center',
		_scopes: null,
		initialize: function(menuItems) {
			this._scopes = menuItems;
		},
		events: {
			'click a.action': '_onClickAction'
		},

		/**
		 * Renders the menu with the currently set items
		 */
		render: function() {
			this.$el.html(OCA.Files.Templates['filemultiselectmenu']({
				items: this._scopes
			}));
		},
		/**
		 * Displays the menu under the given element
		 *
		 * @param {OCA.Files.FileActionContext} context context
		 * @param {Object} $trigger trigger element
		 */
		show: function(context) {
			this._context = context;
			this.$el.removeClass('hidden');
			if (window.innerWidth < 480) {
				this.$el.removeClass('menu-center').addClass('menu-right');
			} else {
				this.$el.removeClass('menu-right').addClass('menu-center');
			}
			OC.showMenu(null, this.$el);
			return false;
		},
		toggleItemVisibility: function (itemName, show) {
			if (show) {
				this.$el.find('.item-' + itemName).removeClass('hidden');
			} else {
				this.$el.find('.item-' + itemName).addClass('hidden');
			}
		},
		updateItemText: function (itemName, translation) {
			this.$el.find('.item-' + itemName).find('.label').text(translation);
		},
		toggleLoading: function (itemName, showLoading) {
			var $actionElement = this.$el.find('.item-' + itemName);
			if ($actionElement.length === 0) {
				return;
			}
			var $icon = $actionElement.find('.icon');
			if (showLoading) {
				var $loadingIcon = $('');
				$icon.after($loadingIcon);
				$icon.addClass('hidden');
				$actionElement.addClass('disabled');
			} else {
				$actionElement.find('.icon-loading-small').remove();
				$actionElement.find('.icon').removeClass('hidden');
				$actionElement.removeClass('disabled');
			}
		},
		isDisabled: function (itemName) {
			var $actionElement = this.$el.find('.item-' + itemName);
			return $actionElement.hasClass('disabled');
		},
		/**
		 * Event handler whenever an action has been clicked within the menu
		 *
		 * @param {Object} event event object
		 */
		_onClickAction: function (event) {
			var $target = $(event.currentTarget);
			if (!$target.hasClass('menuitem')) {
				$target = $target.closest('.menuitem');
			}

			OC.hideMenus();
			this._context.multiSelectMenuClick(event, $target.data('action'));
			return false;
		}
	});

	OCA.Files.FileMultiSelectMenu = FileMultiSelectMenu;
})(OC, OCA);
<|endoftext|>


<commit_before>define(['jquery',
    'arches',
    'models/abstract',
    'knockout',
    'knockout-mapping',
    'underscore',
    'report-templates'
], function($, arches, AbstractModel, ko, koMapping, _, reportLookup) {
    var ReportModel = AbstractModel.extend({
        /**
         * A backbone model to manage report data
         * @augments AbstractModel
         * @constructor
         * @name ReportModel
         */

        url: arches.urls.graph,

        initialize: function(options) {
            var self = this;

            this.reportLookup = reportLookup || options.templates;
            console.log('report model init', self, options, self.reportLookup)

            this.templateId = ko.observable(self.get('graph').template_id);
            this.cards = options.cards || [];
            this.preview = options.preview;
            this.userisreviewer = options.userisreviewer;

            this.set('graphid', ko.observable());
            this.set('config', {});
            self.configKeys = ko.observableArray();

            this._data = ko.observable('{}');

            this.configJSON = ko.observable({});
            this.configState = {};
            this.configKeys.subscribe(function(val){
                var config;

                console.log(reportLookup, options)

                if (self.reportLookup[self.templateId()]) {
                    self.defaultConfig = JSON.parse(self.reportLookup[self.templateId()].defaultconfig);
                }
                else {
                    self.defaultConfig = {};
                }

                if (val.length) {
                    self.configState = {};
                    config = self.get('config');
                    _.each(val, function(key) {
                        if (self.defaultConfig.hasOwnProperty(key)) {
                            self.configState[key] = ko.unwrap(config[key]);
                        }
                    });
                    self.configState = koMapping.fromJS(self.configState);
                }
            });

            this.resetConfigs = function(previousConfigs) {
                this.configKeys().forEach(function(key){
                    if (self.defaultConfig.hasOwnProperty(key)) {
                        if (JSON.stringify(self.configState[key]()) !== JSON.stringify(previousConfigs[key])) {
                            koMapping.fromJS(previousConfigs, self.configState);
                        }
                    }
                });
            };

            this.relatedResourcesLookup = ko.observable({});

            if (options.related_resources) {
                this.updateRelatedResourcesLookup(options.related_resources);
            }

            this.graph = options.graph;
            this.parse(options.graph);
        },

        /**
         * parse - parses the passed in attributes into a {@link ReportModel}
         * @memberof ReportModel.prototype
         * @param  {object} attributes - the properties to seed a {@link ReportModel} with
         */
        parse: function(attributes) {
            var self = this;
            this._attributes = attributes;

            _.each(attributes, function(value, key) {
                switch (key) {
                case 'graphid':
                    this.set('id', value);
                    this.get('graphid')(value);
                    break;
                case 'template_id':
                    self.templateId(value);
                    this.set(key, ko.computed({
                        read: function() {
                            return self.templateId();
                        },
                        write: function(value) {
                            var key;
                            var configKeys = [];
                            var defaultConfig = JSON.parse(self.reportLookup[value].defaultconfig);
                            for (key in defaultConfig) {
                                defaultConfig[key] = ko.observable(defaultConfig[key]);
                            }
                            var currentConfig = this.get('config');
                            this.set('config', _.defaults(currentConfig, defaultConfig));
                            for (key in defaultConfig) {
                                if (_.contains(self.configKeys(), key) === false) {
                                    configKeys.push(key);
                                }
                            }
                            self.templateId(value);
                            self.configKeys(self.configKeys().concat(configKeys));
                        },
                        owner: this
                    }));
                    break;
                case 'config':
                    var config = {};
                    var configKeys = [];
                    self.configKeys.removeAll();
                    _.each(value, function(configVal, configKey) {
                        config[configKey] = configVal;
                        configKeys.push(configKey);
                    });
                    this.set(key, config);
                    self.configKeys(configKeys);
                    break;
                default:
                    this.set(key, value);
                }
            }, this);

            this._data(JSON.stringify(this.toJSON()));
        },

        updateRelatedResourcesLookup: function(json) {
            var relatedResourcesLookup = this.relatedResourcesLookup();

            for (var [graphId, value] of Object.entries(json)) {
                var relatedResources;
                var paginator;
                var remainingResources;

                if (!relatedResourcesLookup[graphId]) {
                    // add graphId to lookup if we haven't added it yet
                    relatedResources = ko.observableArray();
                    remainingResources = ko.observable();
                    paginator = ko.observable();

                    relatedResourcesLookup[graphId] = {
                        'graphId': graphId,
                        'loadedRelatedResources': relatedResources,
                        'name': value['name'] || value['related_resources']['node_config_lookup'][graphId]['name'],
                        'paginator': paginator,
                        'remainingResources': remainingResources,
                        'totalRelatedResources': value['related_resources'] ? value['related_resources']['total']['value'] : 0,
                    };
                } else {
                    // else get pertinent references
                    relatedResources = relatedResourcesLookup[graphId]['loadedRelatedResources'];
                    paginator = relatedResourcesLookup[graphId]['paginator'];
                    remainingResources = relatedResourcesLookup[graphId]['remainingResources'];
                }

                paginator(value['paginator']);

                /*
                    if there's no paginator, the incoming json is all related resource instances,
                    and we should remove the ones we already have so as not to duplicate them
                */
                if (!value['paginator']) {relatedResources.removeAll();}

                if (value['related_resources']) {
                    // add new resource relationships to lookup entry
                    for (var resourceRelationship of value['related_resources']['resource_relationships']) {
                        var relatedResource = value['related_resources']['related_resources'].find(function(resource) {
                            return (
                                resource.resourceinstanceid === resourceRelationship.resourceinstanceidto
                                || resource.resourceinstanceid === resourceRelationship.resourceinstanceidfrom
                                || this.attributes && resource.resourceinstanceid === this.attributes.graph.graphid  // self
                            );
                        });

                        if (relatedResource) {
                            relatedResources.push({
                                'displayName': relatedResource.displayname,
                                'relationship': resourceRelationship.relationshiptype_label,
                                'link': arches.urls.resource_report + relatedResource.resourceinstanceid,
                            });
                        }
                    }

                    var resourceLimit = value['related_resources']['resource_relationships'].length;  /* equivalent to settings.py RELATED_RESOURCES_PER_PAGE */
                    var remainingResourcesCount = value['related_resources']['total']['value'] - relatedResources().length;

                    remainingResources(remainingResourcesCount < resourceLimit ? remainingResourcesCount : resourceLimit);
                }
            }

            this.relatedResourcesLookup(relatedResourcesLookup);
        },

        getRelatedResources: function(loadAll, resource) {
            $.ajax({
                context: this,
                url: (
                    arches.urls.related_resources
                    + this.attributes.resourceid
                    + `?resourceinstance_graphid=${resource.graphId}`
                    + (loadAll ? `&paginate=false` : `&page=${resource.paginator().next_page_number}`)
                ),
            }).done(function(json) {
                this.updateRelatedResourcesLookup({
                    // coerces expected shape
                    [resource.graphId]: json['paginator'] ? json : {'related_resources': json, 'paginator': null }
                });
            });
        },

        reset: function() {
            this._attributes = JSON.parse(this._data());
            this.parse(this._attributes);
        },

        toJSON: function() {
            var ret = {};
            var self = this;
            for (var key in ['template_id', 'config']) {
                if (ko.isObservable(this.attributes[key])) {
                    ret[key] = this.attributes[key]();
                } else if (key === 'config') {
                    var configKeys = this.configKeys();
                    var config = null;
                    if (configKeys.length > 0) {
                        config = {};
                        _.each(configKeys, function(configKey) {
                            config[configKey] = ko.unwrap(self.get('config')[configKey]);
                        });
                    }
                    ret[key] = config;
                } else {
                    ret[key] = this.attributes[key];
                }
            }
            return ret;
        },

        save: function() {
            AbstractModel.prototype.save.call(this, function(request, status, self) {
                if (status === 'success') {
                    this._data(JSON.stringify(this.toJSON()));
                }
            }, this);
        }
    });
    return ReportModel;
});
<commit_msg>undo report model edit #7388<commit_after>define(['jquery',
    'arches',
    'models/abstract',
    'knockout',
    'knockout-mapping',
    'underscore',
    'report-templates'
], function($, arches, AbstractModel, ko, koMapping, _, reportLookup) {
    var ReportModel = AbstractModel.extend({
        /**
         * A backbone model to manage report data
         * @augments AbstractModel
         * @constructor
         * @name ReportModel
         */

        url: arches.urls.graph,

        initialize: function(options) {
            var self = this;

            console.log('report model init', self, options)

            this.templateId = ko.observable(self.get('graph').template_id);
            this.cards = options.cards || [];
            this.preview = options.preview;
            this.userisreviewer = options.userisreviewer;

            this.set('graphid', ko.observable());
            this.set('config', {});
            self.configKeys = ko.observableArray();

            this._data = ko.observable('{}');

            this.configJSON = ko.observable({});
            this.configState = {};
            this.configKeys.subscribe(function(val){
                var config;

                if (reportLookup[self.templateId()]) {
                    self.defaultConfig = JSON.parse(reportLookup[self.templateId()].defaultconfig);
                }
                else {
                    self.defaultConfig = {};
                }

                if (val.length) {
                    self.configState = {};
                    config = self.get('config');
                    _.each(val, function(key) {
                        if (self.defaultConfig.hasOwnProperty(key)) {
                            self.configState[key] = ko.unwrap(config[key]);
                        }
                    });
                    self.configState = koMapping.fromJS(self.configState);
                }
            });

            this.resetConfigs = function(previousConfigs) {
                this.configKeys().forEach(function(key){
                    if (self.defaultConfig.hasOwnProperty(key)) {
                        if (JSON.stringify(self.configState[key]()) !== JSON.stringify(previousConfigs[key])) {
                            koMapping.fromJS(previousConfigs, self.configState);
                        }
                    }
                });
            };

            this.relatedResourcesLookup = ko.observable({});

            if (options.related_resources) {
                this.updateRelatedResourcesLookup(options.related_resources);
            }

            this.graph = options.graph;
            this.parse(options.graph);
        },

        /**
         * parse - parses the passed in attributes into a {@link ReportModel}
         * @memberof ReportModel.prototype
         * @param  {object} attributes - the properties to seed a {@link ReportModel} with
         */
        parse: function(attributes) {
            var self = this;
            this._attributes = attributes;

            _.each(attributes, function(value, key) {
                switch (key) {
                case 'graphid':
                    this.set('id', value);
                    this.get('graphid')(value);
                    break;
                case 'template_id':
                    self.templateId(value);
                    this.set(key, ko.computed({
                        read: function() {
                            return self.templateId();
                        },
                        write: function(value) {
                            var key;
                            var configKeys = [];
                            var defaultConfig = JSON.parse(reportLookup[value].defaultconfig);
                            for (key in defaultConfig) {
                                defaultConfig[key] = ko.observable(defaultConfig[key]);
                            }
                            var currentConfig = this.get('config');
                            this.set('config', _.defaults(currentConfig, defaultConfig));
                            for (key in defaultConfig) {
                                if (_.contains(self.configKeys(), key) === false) {
                                    configKeys.push(key);
                                }
                            }
                            self.templateId(value);
                            self.configKeys(self.configKeys().concat(configKeys));
                        },
                        owner: this
                    }));
                    break;
                case 'config':
                    var config = {};
                    var configKeys = [];
                    self.configKeys.removeAll();
                    _.each(value, function(configVal, configKey) {
                        config[configKey] = configVal;
                        configKeys.push(configKey);
                    });
                    this.set(key, config);
                    self.configKeys(configKeys);
                    break;
                default:
                    this.set(key, value);
                }
            }, this);

            this._data(JSON.stringify(this.toJSON()));
        },

        updateRelatedResourcesLookup: function(json) {
            var relatedResourcesLookup = this.relatedResourcesLookup();

            for (var [graphId, value] of Object.entries(json)) {
                var relatedResources;
                var paginator;
                var remainingResources;

                if (!relatedResourcesLookup[graphId]) {
                    // add graphId to lookup if we haven't added it yet
                    relatedResources = ko.observableArray();
                    remainingResources = ko.observable();
                    paginator = ko.observable();

                    relatedResourcesLookup[graphId] = {
                        'graphId': graphId,
                        'loadedRelatedResources': relatedResources,
                        'name': value['name'] || value['related_resources']['node_config_lookup'][graphId]['name'],
                        'paginator': paginator,
                        'remainingResources': remainingResources,
                        'totalRelatedResources': value['related_resources'] ? value['related_resources']['total']['value'] : 0,
                    };
                } else {
                    // else get pertinent references
                    relatedResources = relatedResourcesLookup[graphId]['loadedRelatedResources'];
                    paginator = relatedResourcesLookup[graphId]['paginator'];
                    remainingResources = relatedResourcesLookup[graphId]['remainingResources'];
                }

                paginator(value['paginator']);

                /*
                    if there's no paginator, the incoming json is all related resource instances,
                    and we should remove the ones we already have so as not to duplicate them
                */
                if (!value['paginator']) {relatedResources.removeAll();}

                if (value['related_resources']) {
                    // add new resource relationships to lookup entry
                    for (var resourceRelationship of value['related_resources']['resource_relationships']) {
                        var relatedResource = value['related_resources']['related_resources'].find(function(resource) {
                            return (
                                resource.resourceinstanceid === resourceRelationship.resourceinstanceidto
                                || resource.resourceinstanceid === resourceRelationship.resourceinstanceidfrom
                                || this.attributes && resource.resourceinstanceid === this.attributes.graph.graphid  // self
                            );
                        });

                        if (relatedResource) {
                            relatedResources.push({
                                'displayName': relatedResource.displayname,
                                'relationship': resourceRelationship.relationshiptype_label,
                                'link': arches.urls.resource_report + relatedResource.resourceinstanceid,
                            });
                        }
                    }

                    var resourceLimit = value['related_resources']['resource_relationships'].length;  /* equivalent to settings.py RELATED_RESOURCES_PER_PAGE */
                    var remainingResourcesCount = value['related_resources']['total']['value'] - relatedResources().length;

                    remainingResources(remainingResourcesCount < resourceLimit ? remainingResourcesCount : resourceLimit);
                }
            }

            this.relatedResourcesLookup(relatedResourcesLookup);
        },

        getRelatedResources: function(loadAll, resource) {
            $.ajax({
                context: this,
                url: (
                    arches.urls.related_resources
                    + this.attributes.resourceid
                    + `?resourceinstance_graphid=${resource.graphId}`
                    + (loadAll ? `&paginate=false` : `&page=${resource.paginator().next_page_number}`)
                ),
            }).done(function(json) {
                this.updateRelatedResourcesLookup({
                    // coerces expected shape
                    [resource.graphId]: json['paginator'] ? json : {'related_resources': json, 'paginator': null }
                });
            });
        },

        reset: function() {
            this._attributes = JSON.parse(this._data());
            this.parse(this._attributes);
        },

        toJSON: function() {
            var ret = {};
            var self = this;
            for (var key in ['template_id', 'config']) {
                if (ko.isObservable(this.attributes[key])) {
                    ret[key] = this.attributes[key]();
                } else if (key === 'config') {
                    var configKeys = this.configKeys();
                    var config = null;
                    if (configKeys.length > 0) {
                        config = {};
                        _.each(configKeys, function(configKey) {
                            config[configKey] = ko.unwrap(self.get('config')[configKey]);
                        });
                    }
                    ret[key] = config;
                } else {
                    ret[key] = this.attributes[key];
                }
            }
            return ret;
        },

        save: function() {
            AbstractModel.prototype.save.call(this, function(request, status, self) {
                if (status === 'success') {
                    this._data(JSON.stringify(this.toJSON()));
                }
            }, this);
        }
    });
    return ReportModel;
});
<|endoftext|>


<commit_before><commit_msg>RTI-299 - fixed exception in chart instance example<commit_after><|endoftext|>


<commit_before>class WorkflowService {
    /*@ngInject*/
    constructor(experimentsService, processesService, mcbus, templates, toast, $mdDialog) {
        this.experimentsService = experimentsService;
        this.processesService = processesService;
        this.mcbus = mcbus;
        this.templates = templates;
        this.toast = toast;
        this.$mdDialog = $mdDialog;
    }

    addProcessFromTemplate(templateId, projectId, experimentId, multiple = true) {
        this.experimentsService.createProcessFromTemplate(projectId, experimentId, `global_${templateId}`)
            .then(
                (process) => {
                    let p = this.templates.loadTemplateFromProcess(process.template_name, process);
                    this.$mdDialog.show({
                        templateUrl: 'app/project/experiments/experiment/components/workflow/new-process-dialog.html',
                        controllerAs: '$ctrl',
                        controller: NewProcessDialogController,
                        bindToController: true,
                        multiple: multiple,
                        locals: {
                            process: p
                        }
                    }).then(
                        () => this.sendProcessChangeEvent(projectId, experimentId)
                    );
                },
                () => this.toast.error('Unable to add samples')
            );
    }

    cloneProcess(projectId, experimentId, process) {
        let p = angular.copy(process);
        p.input_samples.forEach(s => s.selected = true);
        p.output_samples.forEach(s => s.selected = true);
        p.files.forEach(f => f.selected = true);
        return this.$mdDialog.show({
            templateUrl: 'app/project/experiments/experiment/components/workflow/services/clone-process-dialog.html',
            controllerAs: '$ctrl',
            controller: CloneProcessDialogController,
            bindToController: true,
            locals: {
                process: p
            }
        }).then(
            (cloneArgs) => {
                return this.experimentsService.cloneProcess(projectId, experimentId, p.id, cloneArgs).then(
                    (process) => this.sendProcessChangeEvent(projectId, experimentId),
                    () => this.toast.error('Error cloning process')
                )
            }
        );
    }

    sendProcessChangeEvent(projectId, experimentId) {
        this.experimentsService.getProcessesForExperiment(projectId, experimentId)
            .then(
                (processes) => this.mcbus.send('PROCESSES$CHANGE', processes),
                () => this.toast.error('Error retrieving processes for experiment')
            );
    }

    deleteNodeAndProcess(projectId, experimentId, processId) {
        this.processesService.getDeleteProcessPreConditions(projectId, processId)
            .then(
                process => {
                    let numberOfSamples = process.output_samples.length;
                    if (numberOfSamples == 0) {
                        this.deleteNodeAndProcess();
                    } else {
                        this.confirmAndDeleteProcess(projectId, experimentId, process);
                    }
                },
                error => this.toast.error(error.data.error)
            );
    }

    confirmAndDeleteProcess(projectId, experimentId, process) {
        let processName = process.name;
        let numberOfSamples = process.output_samples.length;
        let samples = " output sample" + ((numberOfSamples != 1) ? "s" : "");
        let processInfo = processName + " - has " + numberOfSamples + samples + ".";
        let confirm = this.$mdDialog.confirm()
            .title('This process has output samples: Delete node and Samples?')
            .textContent(processInfo)
            .ariaLabel('Please confirm - deleting node')
            .ok('Delete')
            .cancel('Cancel');

        this.$mdDialog.show(confirm).then(() => this.deleteNodeAndProcess(projectId, experimentId, process.id));
    }

    deleteNodeAndProcess(projectId, experimentId, processId) {
        //NOTE: currently the graph is redisplayed after the process is deleted;
        // so, currently we do not delete the node from the graph itself; the problem
        // with this approach is that redrawing the graph "blows away"
        // any local layout that the user has created. Hence, this needs to be
        // updated so that only the process is deleted, and the node is deleted
        // from the graph without disturbing the layout. Terry Weymouth - Sept 29, 2016
        this.processesService.deleteProcess(projectId, processId)
            .then(
                () => {
                    this.experimentsService.getProcessesForExperiment(projectId, experimentId)
                        .then(
                            (processes) => {
                                this.mcbus.send('PROCESSES$CHANGE', processes);
                            },
                            () => this.toast.error('Error retrieving processes for experiment')
                        );
                },

                error => this.toast.error(error.data.error)
            );
    }
}

class NewProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog, processesService, $stateParams) {
        this.$mdDialog = $mdDialog;
        this.processesService = processesService;
        this.projectId = $stateParams.project_id;
        this.processName = this.process.name;
    }

    done() {
        this.$mdDialog.hide();
    }

    cancel() {
        this.processesService.deleteProcess(this.projectId, this.process.id).then(
            () => this.$mdDialog.cancel(),
            () => this.$mdDialog.cancel()
        );
    }
}

class CloneProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog) {
        this.$mdDialog = $mdDialog;
    }

    done() {
        let files = this.process.files.filter(f => f.selected);
        let inputSamples = this.process.input_samples.filter(s => s.selected);
        this.$mdDialog.hide({name: this.process.name, files: files, samples: inputSamples});
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

angular.module('materialscommons').service('workflowService', WorkflowService);<commit_msg>Remove warning in build about unused variable (process).<commit_after>class WorkflowService {
    /*@ngInject*/
    constructor(experimentsService, processesService, mcbus, templates, toast, $mdDialog) {
        this.experimentsService = experimentsService;
        this.processesService = processesService;
        this.mcbus = mcbus;
        this.templates = templates;
        this.toast = toast;
        this.$mdDialog = $mdDialog;
    }

    addProcessFromTemplate(templateId, projectId, experimentId, multiple = true) {
        this.experimentsService.createProcessFromTemplate(projectId, experimentId, `global_${templateId}`)
            .then(
                (process) => {
                    let p = this.templates.loadTemplateFromProcess(process.template_name, process);
                    this.$mdDialog.show({
                        templateUrl: 'app/project/experiments/experiment/components/workflow/new-process-dialog.html',
                        controllerAs: '$ctrl',
                        controller: NewProcessDialogController,
                        bindToController: true,
                        multiple: multiple,
                        locals: {
                            process: p
                        }
                    }).then(
                        () => this.sendProcessChangeEvent(projectId, experimentId)
                    );
                },
                () => this.toast.error('Unable to add samples')
            );
    }

    cloneProcess(projectId, experimentId, process) {
        let p = angular.copy(process);
        p.input_samples.forEach(s => s.selected = true);
        p.output_samples.forEach(s => s.selected = true);
        p.files.forEach(f => f.selected = true);
        return this.$mdDialog.show({
            templateUrl: 'app/project/experiments/experiment/components/workflow/services/clone-process-dialog.html',
            controllerAs: '$ctrl',
            controller: CloneProcessDialogController,
            bindToController: true,
            locals: {
                process: p
            }
        }).then(
            (cloneArgs) => {
                return this.experimentsService.cloneProcess(projectId, experimentId, p.id, cloneArgs).then(
                    () => this.sendProcessChangeEvent(projectId, experimentId),
                    () => this.toast.error('Error cloning process')
                )
            }
        );
    }

    sendProcessChangeEvent(projectId, experimentId) {
        this.experimentsService.getProcessesForExperiment(projectId, experimentId)
            .then(
                (processes) => this.mcbus.send('PROCESSES$CHANGE', processes),
                () => this.toast.error('Error retrieving processes for experiment')
            );
    }

    deleteNodeAndProcess(projectId, experimentId, processId) {
        this.processesService.getDeleteProcessPreConditions(projectId, processId)
            .then(
                process => {
                    let numberOfSamples = process.output_samples.length;
                    if (numberOfSamples == 0) {
                        this.deleteNodeAndProcess();
                    } else {
                        this.confirmAndDeleteProcess(projectId, experimentId, process);
                    }
                },
                error => this.toast.error(error.data.error)
            );
    }

    confirmAndDeleteProcess(projectId, experimentId, process) {
        let processName = process.name;
        let numberOfSamples = process.output_samples.length;
        let samples = " output sample" + ((numberOfSamples != 1) ? "s" : "");
        let processInfo = processName + " - has " + numberOfSamples + samples + ".";
        let confirm = this.$mdDialog.confirm()
            .title('This process has output samples: Delete node and Samples?')
            .textContent(processInfo)
            .ariaLabel('Please confirm - deleting node')
            .ok('Delete')
            .cancel('Cancel');

        this.$mdDialog.show(confirm).then(() => this.deleteNodeAndProcess(projectId, experimentId, process.id));
    }

    deleteNodeAndProcess(projectId, experimentId, processId) {
        //NOTE: currently the graph is redisplayed after the process is deleted;
        // so, currently we do not delete the node from the graph itself; the problem
        // with this approach is that redrawing the graph "blows away"
        // any local layout that the user has created. Hence, this needs to be
        // updated so that only the process is deleted, and the node is deleted
        // from the graph without disturbing the layout. Terry Weymouth - Sept 29, 2016
        this.processesService.deleteProcess(projectId, processId)
            .then(
                () => {
                    this.experimentsService.getProcessesForExperiment(projectId, experimentId)
                        .then(
                            (processes) => {
                                this.mcbus.send('PROCESSES$CHANGE', processes);
                            },
                            () => this.toast.error('Error retrieving processes for experiment')
                        );
                },

                error => this.toast.error(error.data.error)
            );
    }
}

class NewProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog, processesService, $stateParams) {
        this.$mdDialog = $mdDialog;
        this.processesService = processesService;
        this.projectId = $stateParams.project_id;
        this.processName = this.process.name;
    }

    done() {
        this.$mdDialog.hide();
    }

    cancel() {
        this.processesService.deleteProcess(this.projectId, this.process.id).then(
            () => this.$mdDialog.cancel(),
            () => this.$mdDialog.cancel()
        );
    }
}

class CloneProcessDialogController {
    /*@ngInject*/
    constructor($mdDialog) {
        this.$mdDialog = $mdDialog;
    }

    done() {
        let files = this.process.files.filter(f => f.selected);
        let inputSamples = this.process.input_samples.filter(s => s.selected);
        this.$mdDialog.hide({name: this.process.name, files: files, samples: inputSamples});
    }

    cancel() {
        this.$mdDialog.cancel();
    }
}

angular.module('materialscommons').service('workflowService', WorkflowService);<|endoftext|>