<commit_before>(function (angular, Move) {

  'use strict';

  angular.module('birdyard.nodes')

  .controller('nodeController', [
    '$scope',
    '$routeParams',
    '$location',
    '$timeout',
    '$anchorScroll',
    '$window',
    'firebaseService',
    'nodeService',
    'roomService',
    'breadcrumbService',
    'stashService',
    'uiService',
    'activityService',
    'notificationService',
    'authService',
    '$mdToast',
    'meta',
    'backdropService',

  function (
    $scope,
    $routeParams,
    $location,
    $timeout,
    $anchorScroll,
    $window,
    firebaseService,
    nodeService,
    roomService,
    breadcrumbService,
    stashService,
    uiService,
    activityService,
    notificationService,
    authService,
    $mdToast,
    meta,
    backdropService) {

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // GLobals & Constants ////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    var $bottom;
    var SPEED = 200;
    var wasScrolling = false;
    var LAST_SELECTED_NODE = 'last_selected';
    var RECENT_NODES_PREFIX = '___recentNode_';
    var MODE = Object.freeze({
      REPLY: 0,
      EDIT: 1
    });

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Scope properties ///////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $scope.autoScroll =     true;
    $scope.loaded =         false;
    $scope.showDialog =     false;
    $scope.expand =         false;
    $scope.transitioning =  false;
    $scope.owned =          false;
    $scope.selected =       {};
    $scope.$children =      {};
    $scope.$activity =      {};
    $scope.reply =          '';
    $scope.mode =           MODE.REPLY;
    $scope.node =           getNode($routeParams.id);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Private functions //////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function loaded(isLoaded) {

      $timeout(function () {
        $scope.loaded = isLoaded;
        scrollToBottom();
      }, 500);

      var replyNow = stashService.get('replyNow') === "true";

      if (replyNow) {
        stashService.set('replyNow', false);
        $timeout(function () {
          $scope.toggleDialog();
        }, 500);
      }
    }

    function navigateToNode(nodeId) {
      $timeout(function() {
        $location.path('n/' + nodeId);
      });
    }

    function focusTextInput() {
      if ($scope.showDialog) {
        $timeout(function () {
          angular.element(document.getElementById('text-input')).focus();
        }, SPEED * 2);
      }
    }

    function addRecentNode() {

      // Todo: move this or rename this function?
      meta.setTitle('Talking about ' + $scope.node.name + '\'s Comment...')

      var prefix = RECENT_NODES_PREFIX + $scope.node.id;
      var key = prefix + $scope.node.id;

      if (!stashService.exists(key)) {
        stashService.set(key, {
          id: $scope.node.id,
          text: $scope.node.text.slice(0, 250) + '...',
          name: $scope.node.name,
          timestamp: new Date().getTime()
        });
      }
    }

    function doTransition(callback) {

      var options = {
        top: 285,
        speed: SPEED,
        context: Move.CONTEXT.VIEWPORT,
        easing: 'ease-in'
      };

      $scope.transitioning =  true;

      // Callback hell!
      Move.y('.keep', options, function () {

        var keepOptions = {top: 30, speed: SPEED, easing: 'linear'};
        var starWarsOptions = {top: -275, speed: SPEED, easing: 'linear'};

        Move.y('.keep', keepOptions, function () {
          var $keeper = angular.element(document.getElementsByClassName('keep'));
          $keeper[0].style.setProperty('display', 'none', 'important');
        });

        Move.y('.star-wars', starWarsOptions, callback);
      });
    }

    function setNodeChildrenFromFirebase(id) {
      nodeService.getChildren(id).$loaded(function (children) {

        $scope.$children = children;
        $scope.$children.$watch(babySitter);

        loaded(true);
      });
    }

    function getNode(id) {

      var lsn = stashService.get(LAST_SELECTED_NODE);
      var $node = nodeService.getById(id);

      $node.$loaded(function () {
        $scope.node = $node;
      });

      if (lsn && lsn.id === id) {
        return lsn;
      }
    }

    function resetDialog() {
      $timeout(function () {
        $scope.reply = '';
        $scope.mode = MODE.REPLY;
      });
    }

    function getScrollHeight() {
      return document.body.scrollHeight || document.documentElement.scrollHeight;
    }

    function scrollToBottom(callback) {
      if ($scope.autoScroll) {
        $timeout(function () {

          if (!$bottom) {
            $bottom = $window.document.getElementById('bottom');
          }

          try {
            $bottom.scrollIntoView({block: "end", behavior: "instant"});
          } catch (ex) {
            // Swallow exception
          }

          if (callback) {
            callback();
          }
         }, 100);
      }
    }

    function checkBottom() {

      $timeout(function() {

        var height = $window.innerHeight || document.documentElement.clientHeight;
        var scroll = document.body.scrollTop || document.documentElement.scrollTop;
        var scrollHeight = getScrollHeight();

        // If we're at the bottom & autoScroll is not enabled...
        if ((height + scroll) >= scrollHeight) {
          // enable it
          $scope.autoScroll = true;
        } else {
          // if we're not at the bottom & autoScroll is enabled, disable it.
          $scope.autoScroll = false;
        }
      }, SPEED);
    }

    function babySitter(snap) {
      if (snap.event === 'child_added') {
        scrollToBottom();
      }
    }

    function updateCommentCount(operand) {
      try {
        var operation = parseInt(operand, 10);
        var updatedCount = angular.copy(($scope.node.commentCount + operation));

        // Update node
        $scope.node.commentCount = updatedCount;
        $scope.node.$save();

        // Update the child (origin)
        if ($scope.node.origin) {
          nodeService.getByPath($scope.node.origin).$loaded(function ($snap) {
            $snap.commentCount = updatedCount;
            $snap.$save();
          });
        }

        // Update the associated room
        if ($scope.node.originRoom) {

          var $roomRef = firebaseService.getRef($scope.node.originRoom);

          $roomRef.once('value', function ($snap) {
            var room = $snap.val();
            var updatedRoomCount = room.commentCount + operation;
            room.commentCount = updatedRoomCount;
            return roomService.update(room);
          });
        }
      } catch (err) {
        console.error(err);
      }
    }

    function toggleDialog(force) {

      if (typeof force === 'boolean') {
        $scope.showDialog = force;
      } else {
        $scope.showDialog = !$scope.showDialog;
      }

      if ($scope.showDialog) {
        focusTextInput();
        backdropService.set(true, 4, $scope.toggleDialog);
      } else {
        // Just in case they exit by hitting the escape button
        backdropService.reset();
      }
    }

    function checkOwner() {
      authService.getUser().then(function (user) {
        // Check to see if current user owns the featured comment
        if (user.uid === $scope.node.uid) {
          $scope.owned = true;
        }
      });
    }

    function init() {

      meta.setTitle('Talking about...');

      // If the user switches autoscroll to true, scroll to the bottom
      $scope.$watch('autoScroll', function (newValue, oldValue) {
        if (newValue !== oldValue && newValue) {
          scrollToBottom();
        }
      });

      // Watch for the node load...
      $scope.$watch('node', function (value) {
        if (value && value.$loaded) {
          value.$loaded(addRecentNode);
          setNodeChildrenFromFirebase($routeParams.id);
          checkOwner();
        }
      });

      activityService.get().then(function ($activity) {
        $scope.$activity = $activity;
      }).catch(function (err) {
        console.error(err);
      });

      // Bind scroll events to a handler that checks to see if the user has
      // scrolled all the way to the bottom
      angular.element($window).bind('scroll', checkBottom);

      // Scroll to the bottom, plz
      $timeout(scrollToBottom);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Scope methods //////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $scope.handleReply = function () {
      if ($scope.mode === MODE.REPLY) {
        $scope.pushText();
      } else if ($scope.mode === MODE.EDIT) {
        $scope.update();
      }
    };

    // Add a comment
    $scope.pushText = function () {

      // Do not proceed if the user has not entered text
      if (!$scope.reply) {
        return;
      }

      var _formattedNode = {};
      var _$new = {};

      $scope.toggleDialog(false);

      return nodeService.format($scope.reply).then(function (formatted) {
        _formattedNode = formatted;
        return nodeService.push(formatted);
      }).then(function ($new) {
        _$new = $new;
        return _$new.$loaded();
      }).then(function () {
        _formattedNode.id = _$new.id;
        _formattedNode.originRoom = $scope.node.originRoom;
        return $scope.$children.$add(_formattedNode);
      }).then(function ($snapshot) {
        _$new.origin = 'nodes/' + $routeParams.id + '/children/' + $snapshot.key();
        _$new.originRoom = $scope.node.originRoom;
        _$new.breadcrumb = breadcrumbService.push(_$new.id, angular.copy($scope.node.breadcrumb));
        return _$new.$save();
      }).then(function() {
        resetDialog();
        return updateCommentCount('+1');
      }).then(function () {

        // Notify the user
        var copiedNode =    angular.copy($scope.node);
        var text =          copiedNode.text.slice(0,150);
        var nodeId =        copiedNode.id;
        var userToNotify =  copiedNode.uid;
        var location =      '/n/' + nodeId;

        return notificationService.notify(notificationService.TYPE.REPLY, text, userToNotify, nodeId, location);

      }).then(function () {

        // Display success message
        $mdToast.show(
          $mdToast.simple()
            .content('Posted!')
            .theme('toast-default')
            .position('bottom right')
            .hideDelay(1500)
          );

      }).catch(function(err) {

        var msg = 'Something went wrong, please try again.';

        console.error(err);

        if (err.code.indexOf('PERMISSION_DENIED') > -1) {
          msg = 'Slow down. You\'re doing that too much.';
        }

        // Display error message
        $mdToast.show(
          $mdToast.simple()
            .content(msg)
            .theme('toast-error')
            .position('bottom right')
            .hideDelay(3000)
          );
      });
    };

    $scope.update = function () {

      // Copy the new text
      var newText = angular.copy($scope.reply);
      var origin = angular.copy($scope.node.origin);

      // Update the text of the existing node
      $scope.node.text = newText;
      $scope.node.timestamp = $window.Firebase.ServerValue.TIMESTAMP;
      $scope.node.edited = true;

      // Toggle the dialog
      $scope.toggleDialog(false);

      // Save the change
      return $scope.node.$save().then(function ($ref) {
        // Save the origin node the exact same way
        if (origin) {
          var $originRef = nodeService.getByPath(origin);
          return $originRef.$loaded(function () {
            $originRef.text = newText;
            $originRef.timestamp = $window.Firebase.ServerValue.TIMESTAMP;
            $originRef.edited = true;
            return $originRef.$save();
          });
        } else {
          return;
        }
      }).then(function () {
        resetDialog();
        console.log('woo!');
      }).catch(function (err) {
        console.error(err);
      })
    };

    // Navigate to a specific node
    $scope.goToNode = navigateToNode;

    // Navigate up one level in the breadcrumb
    $scope.goUp = function () {
      var index = $scope.node.breadcrumb.length - 2;
      var nodeId = $scope.node.breadcrumb[index];
      navigateToNode(nodeId);
    };

    // Fade all child nodes... except one.
    $scope.selectChild = function (child) {

      // Flag as transitioning to the next node
      $scope.loaded = false;

      // Duplicated child node
      var selected = angular.copy(child);
      stashService.set(LAST_SELECTED_NODE, selected);

      $timeout(function () {
        $scope.selected = selected;
      });

      // Keep the clicked one
      var theChosenOne = angular.element(document.getElementById(child.id));
      theChosenOne.addClass('keep');

      // Move stuff
      doTransition(function () {
        // Navigate
        navigateToNode(child.id);
      });

      // Fade the rest
      var children = angular.element(document.querySelectorAll('div.child:not(.keep)'));
      children.css({'display': 'none'});
    };

    $scope.toggleDialog = function (force) {
      $scope.mode = MODE.REPLY;
      toggleDialog(force);
    };

    $scope.toggleEdit = function (force) {
      $scope.mode = MODE.EDIT;
      $scope.reply = $scope.node.text;
      toggleDialog(force);
    }

    $scope.pauseAutoScroll = function (pause) {
      if (pause) {
        wasScrolling = angular.copy($scope.autoScroll);
        $scope.autoScroll = false;
      } else if (!pause && wasScrolling) {
        $scope.autoScroll = true;
      }
    };

    $scope.expandFeature = function ($element) {
      $timeout(function () {
        $scope.expand = true;
      });
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Initialization /////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    init();

  }]);

})(angular, Move);<commit_msg>Toast notification for edit<commit_after>(function (angular, Move) {

  'use strict';

  angular.module('birdyard.nodes')

  .controller('nodeController', [
    '$scope',
    '$routeParams',
    '$location',
    '$timeout',
    '$anchorScroll',
    '$window',
    'firebaseService',
    'nodeService',
    'roomService',
    'breadcrumbService',
    'stashService',
    'uiService',
    'activityService',
    'notificationService',
    'authService',
    '$mdToast',
    'meta',
    'backdropService',

  function (
    $scope,
    $routeParams,
    $location,
    $timeout,
    $anchorScroll,
    $window,
    firebaseService,
    nodeService,
    roomService,
    breadcrumbService,
    stashService,
    uiService,
    activityService,
    notificationService,
    authService,
    $mdToast,
    meta,
    backdropService) {

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // GLobals & Constants ////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    var $bottom;
    var SPEED = 200;
    var wasScrolling = false;
    var LAST_SELECTED_NODE = 'last_selected';
    var RECENT_NODES_PREFIX = '___recentNode_';
    var MODE = Object.freeze({
      REPLY: 0,
      EDIT: 1
    });

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Scope properties ///////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $scope.autoScroll =     true;
    $scope.loaded =         false;
    $scope.showDialog =     false;
    $scope.expand =         false;
    $scope.transitioning =  false;
    $scope.owned =          false;
    $scope.selected =       {};
    $scope.$children =      {};
    $scope.$activity =      {};
    $scope.reply =          '';
    $scope.mode =           MODE.REPLY;
    $scope.node =           getNode($routeParams.id);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Private functions //////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    function loaded(isLoaded) {

      $timeout(function () {
        $scope.loaded = isLoaded;
        scrollToBottom();
      }, 500);

      var replyNow = stashService.get('replyNow') === "true";

      if (replyNow) {
        stashService.set('replyNow', false);
        $timeout(function () {
          $scope.toggleDialog();
        }, 500);
      }
    }

    function navigateToNode(nodeId) {
      $timeout(function() {
        $location.path('n/' + nodeId);
      });
    }

    function focusTextInput() {
      if ($scope.showDialog) {
        $timeout(function () {
          angular.element(document.getElementById('text-input')).focus();
        }, SPEED * 2);
      }
    }

    function addRecentNode() {

      // Todo: move this or rename this function?
      meta.setTitle('Talking about ' + $scope.node.name + '\'s Comment...')

      var prefix = RECENT_NODES_PREFIX + $scope.node.id;
      var key = prefix + $scope.node.id;

      if (!stashService.exists(key)) {
        stashService.set(key, {
          id: $scope.node.id,
          text: $scope.node.text.slice(0, 250) + '...',
          name: $scope.node.name,
          timestamp: new Date().getTime()
        });
      }
    }

    function doTransition(callback) {

      var options = {
        top: 285,
        speed: SPEED,
        context: Move.CONTEXT.VIEWPORT,
        easing: 'ease-in'
      };

      $scope.transitioning =  true;

      // Callback hell!
      Move.y('.keep', options, function () {

        var keepOptions = {top: 30, speed: SPEED, easing: 'linear'};
        var starWarsOptions = {top: -275, speed: SPEED, easing: 'linear'};

        Move.y('.keep', keepOptions, function () {
          var $keeper = angular.element(document.getElementsByClassName('keep'));
          $keeper[0].style.setProperty('display', 'none', 'important');
        });

        Move.y('.star-wars', starWarsOptions, callback);
      });
    }

    function setNodeChildrenFromFirebase(id) {
      nodeService.getChildren(id).$loaded(function (children) {

        $scope.$children = children;
        $scope.$children.$watch(babySitter);

        loaded(true);
      });
    }

    function getNode(id) {

      var lsn = stashService.get(LAST_SELECTED_NODE);
      var $node = nodeService.getById(id);

      $node.$loaded(function () {
        $scope.node = $node;
      });

      if (lsn && lsn.id === id) {
        return lsn;
      }
    }

    function resetDialog() {
      $timeout(function () {
        $scope.reply = '';
        $scope.mode = MODE.REPLY;
      });
    }

    function getScrollHeight() {
      return document.body.scrollHeight || document.documentElement.scrollHeight;
    }

    function scrollToBottom(callback) {
      if ($scope.autoScroll) {
        $timeout(function () {

          if (!$bottom) {
            $bottom = $window.document.getElementById('bottom');
          }

          try {
            $bottom.scrollIntoView({block: "end", behavior: "instant"});
          } catch (ex) {
            // Swallow exception
          }

          if (callback) {
            callback();
          }
         }, 100);
      }
    }

    function checkBottom() {

      $timeout(function() {

        var height = $window.innerHeight || document.documentElement.clientHeight;
        var scroll = document.body.scrollTop || document.documentElement.scrollTop;
        var scrollHeight = getScrollHeight();

        // If we're at the bottom & autoScroll is not enabled...
        if ((height + scroll) >= scrollHeight) {
          // enable it
          $scope.autoScroll = true;
        } else {
          // if we're not at the bottom & autoScroll is enabled, disable it.
          $scope.autoScroll = false;
        }
      }, SPEED);
    }

    function babySitter(snap) {
      if (snap.event === 'child_added') {
        scrollToBottom();
      }
    }

    function updateCommentCount(operand) {
      try {
        var operation = parseInt(operand, 10);
        var updatedCount = angular.copy(($scope.node.commentCount + operation));

        // Update node
        $scope.node.commentCount = updatedCount;
        $scope.node.$save();

        // Update the child (origin)
        if ($scope.node.origin) {
          nodeService.getByPath($scope.node.origin).$loaded(function ($snap) {
            $snap.commentCount = updatedCount;
            $snap.$save();
          });
        }

        // Update the associated room
        if ($scope.node.originRoom) {

          var $roomRef = firebaseService.getRef($scope.node.originRoom);

          $roomRef.once('value', function ($snap) {
            var room = $snap.val();
            var updatedRoomCount = room.commentCount + operation;
            room.commentCount = updatedRoomCount;
            return roomService.update(room);
          });
        }
      } catch (err) {
        console.error(err);
      }
    }

    function toggleDialog(force) {

      if (typeof force === 'boolean') {
        $scope.showDialog = force;
      } else {
        $scope.showDialog = !$scope.showDialog;
      }

      if ($scope.showDialog) {
        focusTextInput();
        backdropService.set(true, 4, $scope.toggleDialog);
      } else {
        // Just in case they exit by hitting the escape button
        backdropService.reset();
      }
    }

    function checkOwner() {
      authService.getUser().then(function (user) {
        // Check to see if current user owns the featured comment
        if (user.uid === $scope.node.uid) {
          $scope.owned = true;
        }
      });
    }

    function init() {

      meta.setTitle('Talking about...');

      // If the user switches autoscroll to true, scroll to the bottom
      $scope.$watch('autoScroll', function (newValue, oldValue) {
        if (newValue !== oldValue && newValue) {
          scrollToBottom();
        }
      });

      // Watch for the node load...
      $scope.$watch('node', function (value) {
        if (value && value.$loaded) {
          value.$loaded(addRecentNode);
          setNodeChildrenFromFirebase($routeParams.id);
          checkOwner();
        }
      });

      activityService.get().then(function ($activity) {
        $scope.$activity = $activity;
      }).catch(function (err) {
        console.error(err);
      });

      // Bind scroll events to a handler that checks to see if the user has
      // scrolled all the way to the bottom
      angular.element($window).bind('scroll', checkBottom);

      // Scroll to the bottom, plz
      $timeout(scrollToBottom);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Scope methods //////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $scope.handleReply = function () {
      if ($scope.mode === MODE.REPLY) {
        $scope.pushText();
      } else if ($scope.mode === MODE.EDIT) {
        $scope.update();
      }
    };

    // Add a comment
    $scope.pushText = function () {

      // Do not proceed if the user has not entered text
      if (!$scope.reply) {
        return;
      }

      var _formattedNode = {};
      var _$new = {};

      $scope.toggleDialog(false);

      return nodeService.format($scope.reply).then(function (formatted) {
        _formattedNode = formatted;
        return nodeService.push(formatted);
      }).then(function ($new) {
        _$new = $new;
        return _$new.$loaded();
      }).then(function () {
        _formattedNode.id = _$new.id;
        _formattedNode.originRoom = $scope.node.originRoom;
        return $scope.$children.$add(_formattedNode);
      }).then(function ($snapshot) {
        _$new.origin = 'nodes/' + $routeParams.id + '/children/' + $snapshot.key();
        _$new.originRoom = $scope.node.originRoom;
        _$new.breadcrumb = breadcrumbService.push(_$new.id, angular.copy($scope.node.breadcrumb));
        return _$new.$save();
      }).then(function() {
        resetDialog();
        return updateCommentCount('+1');
      }).then(function () {

        // Notify the user
        var copiedNode =    angular.copy($scope.node);
        var text =          copiedNode.text.slice(0,150);
        var nodeId =        copiedNode.id;
        var userToNotify =  copiedNode.uid;
        var location =      '/n/' + nodeId;

        return notificationService.notify(notificationService.TYPE.REPLY, text, userToNotify, nodeId, location);

      }).then(function () {

        // Display success message
        $mdToast.show(
          $mdToast.simple()
            .content('Posted!')
            .theme('toast-success')
            .position('bottom right')
            .hideDelay(1500)
          );

      }).catch(function(err) {

        var msg = 'Something went wrong, please try again.';

        console.error(err);

        if (err.code.indexOf('PERMISSION_DENIED') > -1) {
          msg = 'Slow down. You\'re doing that too much.';
        }

        // Display error message
        $mdToast.show(
          $mdToast.simple()
            .content(msg)
            .theme('toast-error')
            .position('bottom right')
            .hideDelay(3000)
          );
      });
    };

    $scope.update = function () {

      // Copy the new text
      var newText = angular.copy($scope.reply);
      var origin = angular.copy($scope.node.origin);

      // Update the text of the existing node
      $scope.node.text = newText;
      $scope.node.timestamp = $window.Firebase.ServerValue.TIMESTAMP;
      $scope.node.edited = true;

      // Toggle the dialog
      $scope.toggleDialog(false);

      // Save the change
      return $scope.node.$save().then(function ($ref) {
        // Save the origin node the exact same way
        if (origin) {
          var $originRef = nodeService.getByPath(origin);
          return $originRef.$loaded(function () {
            $originRef.text = newText;
            $originRef.timestamp = $window.Firebase.ServerValue.TIMESTAMP;
            $originRef.edited = true;
            return $originRef.$save();
          });
        } else {
          return;
        }
      }).then(function () {

        resetDialog();

        // Display success message
        $mdToast.show(
          $mdToast.simple()
            .content('Edited!')
            .theme('toast-success')
            .position('bottom right')
            .hideDelay(1500)
          );

      }).catch(function (err) {

        console.error(err);

        resetDialog();

        // Display error message
        $mdToast.show(
          $mdToast.simple()
            .content('Something went wrong, please try again.')
            .theme('toast-error')
            .position('bottom right')
            .hideDelay(3000)
          );
      })
    };

    // Navigate to a specific node
    $scope.goToNode = navigateToNode;

    // Navigate up one level in the breadcrumb
    $scope.goUp = function () {
      var index = $scope.node.breadcrumb.length - 2;
      var nodeId = $scope.node.breadcrumb[index];
      navigateToNode(nodeId);
    };

    // Fade all child nodes... except one.
    $scope.selectChild = function (child) {

      // Flag as transitioning to the next node
      $scope.loaded = false;

      // Duplicated child node
      var selected = angular.copy(child);
      stashService.set(LAST_SELECTED_NODE, selected);

      $timeout(function () {
        $scope.selected = selected;
      });

      // Keep the clicked one
      var theChosenOne = angular.element(document.getElementById(child.id));
      theChosenOne.addClass('keep');

      // Move stuff
      doTransition(function () {
        // Navigate
        navigateToNode(child.id);
      });

      // Fade the rest
      var children = angular.element(document.querySelectorAll('div.child:not(.keep)'));
      children.css({'display': 'none'});
    };

    $scope.toggleDialog = function (force) {
      $scope.mode = MODE.REPLY;
      toggleDialog(force);
    };

    $scope.toggleEdit = function (force) {
      $scope.mode = MODE.EDIT;
      $scope.reply = $scope.node.text;
      toggleDialog(force);
    }

    $scope.pauseAutoScroll = function (pause) {
      if (pause) {
        wasScrolling = angular.copy($scope.autoScroll);
        $scope.autoScroll = false;
      } else if (!pause && wasScrolling) {
        $scope.autoScroll = true;
      }
    };

    $scope.expandFeature = function ($element) {
      $timeout(function () {
        $scope.expand = true;
      });
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Initialization /////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    init();

  }]);

})(angular, Move);<|endoftext|>


<commit_before>'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// STDMATH //

var stdmath = {};
setReadOnly( stdmath, 'base', {} );

// Constants:
setReadOnly( stdmath, 'FLOAT64_PI', require( '@stdlib/math/constants/float64-pi' ) );
setReadOnly( stdmath, 'FLOAT64_TWO_PI', require( '@stdlib/math/constants/float64-two-pi' ) );
setReadOnly( stdmath, 'FLOAT64_PI_SQUARED', require( '@stdlib/math/constants/float64-pi-squared' ) );
setReadOnly( stdmath, 'FLOAT64_E', require( '@stdlib/math/constants/float64-e' ) );
setReadOnly( stdmath, 'FLOAT64_PHI', require( '@stdlib/math/constants/float64-phi' ) );
setReadOnly( stdmath, 'FLOAT64_SQRT_PHI', require( '@stdlib/math/constants/float64-sqrt-phi' ) );
setReadOnly( stdmath, 'FLOAT64_EULERGAMMA', require( '@stdlib/math/constants/float64-eulergamma' ) );
setReadOnly( stdmath, 'FLOAT64_GLAISHER', require( '@stdlib/math/constants/float64-glaisher-kinkelin' ) );
setReadOnly( stdmath, 'FLOAT64_CATALAN', require( '@stdlib/math/constants/float64-catalan' ) );
setReadOnly( stdmath, 'FLOAT64_LN2', require( '@stdlib/math/constants/float64-ln2' ) );
setReadOnly( stdmath, 'FLOAT64_LN_SQRT_TWO_PI', require( '@stdlib/math/constants/float64-ln-sqrt-two-pi' ) );

setReadOnly( stdmath, 'FLOAT32_PINF', require( '@stdlib/math/constants/float32-pinf' ) );
setReadOnly( stdmath, 'FLOAT32_NINF', require( '@stdlib/math/constants/float32-ninf' ) );
setReadOnly( stdmath, 'FLOAT64_PINF', require( '@stdlib/math/constants/float64-pinf' ) );
setReadOnly( stdmath, 'FLOAT64_NINF', require( '@stdlib/math/constants/float64-ninf' ) );

setReadOnly( stdmath, 'INT8_MAX', require( '@stdlib/math/constants/int8-max' ) );
setReadOnly( stdmath, 'INT8_MIN', require( '@stdlib/math/constants/int8-min' ) );
setReadOnly( stdmath, 'INT16_MAX', require( '@stdlib/math/constants/int16-max' ) );
setReadOnly( stdmath, 'INT16_MIN', require( '@stdlib/math/constants/int16-min' ) );
setReadOnly( stdmath, 'INT32_MAX', require( '@stdlib/math/constants/int32-max' ) );
setReadOnly( stdmath, 'INT32_MIN', require( '@stdlib/math/constants/int32-min' ) );
setReadOnly( stdmath, 'UINT32_MAX', require( '@stdlib/math/constants/uint32-max' ) );
setReadOnly( stdmath, 'FLOAT64_MAX', require( '@stdlib/math/constants/float64-max' ) );
setReadOnly( stdmath, 'FLOAT64_MAX_SAFE_INTEGER', require( '@stdlib/math/constants/float64-max-safe-integer' ) );
setReadOnly( stdmath, 'FLOAT64_MIN_SAFE_INTEGER', require( '@stdlib/math/constants/float64-min-safe-integer' ) );

setReadOnly( stdmath, 'FLOAT64_EPSILON', require( '@stdlib/math/constants/float64-eps' ) );
setReadOnly( stdmath, 'FLOAT64_SQRT_EPSILON', require( '@stdlib/math/constants/float64-sqrt-eps' ) );

setReadOnly( stdmath, 'FLOAT16_PRECISION', require( '@stdlib/math/constants/float16-precision' ) );
setReadOnly( stdmath, 'FLOAT32_PRECISION', require( '@stdlib/math/constants/float32-precision' ) );
setReadOnly( stdmath, 'FLOAT64_PRECISION', require( '@stdlib/math/constants/float64-precision' ) );

// Special functions (base):
setReadOnly( stdmath.base, 'round', require( '@stdlib/math/base/special/round' ) );
setReadOnly( stdmath.base, 'roundn', require( '@stdlib/math/base/special/roundn' ) );
setReadOnly( stdmath.base, 'floor', require( '@stdlib/math/base/special/floor' ) );
setReadOnly( stdmath.base, 'ceil', require( '@stdlib/math/base/special/ceil' ) );
setReadOnly( stdmath.base, 'truncate', require( '@stdlib/math/base/special/truncate' ) );
setReadOnly( stdmath.base, 'abs', require( '@stdlib/math/base/special/abs' ) );
setReadOnly( stdmath.base, 'pow', require( '@stdlib/math/base/special/pow' ) );
setReadOnly( stdmath.base, 'sqrt', require( '@stdlib/math/base/special/sqrt' ) );
setReadOnly( stdmath.base, 'exp', require( '@stdlib/math/base/special/exp' ) );
setReadOnly( stdmath.base, 'ln', require( '@stdlib/math/base/special/ln' ) );
setReadOnly( stdmath.base, 'signum', require( '@stdlib/math/base/special/signum' ) );
setReadOnly( stdmath.base, 'flipsign', require( '@stdlib/math/base/special/flipsign' ) );

// Utilities (base):
setReadOnly( stdmath.base, 'isNaN', require( '@stdlib/math/base/utils/is-nan' ) );
setReadOnly( stdmath.base, 'isFinite', require( '@stdlib/math/base/utils/is-finite' ) );
setReadOnly( stdmath.base, 'isInfinite', require( '@stdlib/math/base/utils/is-infinite' ) );
setReadOnly( stdmath.base, 'isNegativeZero', require( '@stdlib/math/base/utils/is-negative-zero' ) );
setReadOnly( stdmath.base, 'isPositiveZero', require( '@stdlib/math/base/utils/is-positive-zero' ) );
setReadOnly( stdmath.base, 'isInteger', require( '@stdlib/math/base/utils/is-integer' ) );

setReadOnly( stdmath.base, 'absoluteDifference', require( '@stdlib/math/base/utils/absolute-difference' ) );
setReadOnly( stdmath.base, 'relativeDifference', require( '@stdlib/math/base/utils/relative-difference' ) );

// Tools (base):
setReadOnly( stdmath.base, 'evalpoly', require( '@stdlib/math/base/tools/evalpoly' ) );
setReadOnly( stdmath.base, 'evalrational', require( '@stdlib/math/base/tools/evalrational' ) );

// Utilities (generics):
setReadOnly( stdmath, 'linspace', require( '@stdlib/math/generics/utils/linspace' ) );
setReadOnly( stdmath, 'logspace', require( '@stdlib/math/generics/utils/logspace' ) );
setReadOnly( stdmath, 'incrspace', require( '@stdlib/math/generics/utils/incrspace' ) );

// EXPORTS //

module.exports = stdmath;
<commit_msg>Export methods to test for integer values<commit_after>'use strict';

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// STDMATH //

var stdmath = {};
setReadOnly( stdmath, 'base', {} );

// Constants:
setReadOnly( stdmath, 'FLOAT64_PI', require( '@stdlib/math/constants/float64-pi' ) );
setReadOnly( stdmath, 'FLOAT64_TWO_PI', require( '@stdlib/math/constants/float64-two-pi' ) );
setReadOnly( stdmath, 'FLOAT64_PI_SQUARED', require( '@stdlib/math/constants/float64-pi-squared' ) );
setReadOnly( stdmath, 'FLOAT64_E', require( '@stdlib/math/constants/float64-e' ) );
setReadOnly( stdmath, 'FLOAT64_PHI', require( '@stdlib/math/constants/float64-phi' ) );
setReadOnly( stdmath, 'FLOAT64_SQRT_PHI', require( '@stdlib/math/constants/float64-sqrt-phi' ) );
setReadOnly( stdmath, 'FLOAT64_EULERGAMMA', require( '@stdlib/math/constants/float64-eulergamma' ) );
setReadOnly( stdmath, 'FLOAT64_GLAISHER', require( '@stdlib/math/constants/float64-glaisher-kinkelin' ) );
setReadOnly( stdmath, 'FLOAT64_CATALAN', require( '@stdlib/math/constants/float64-catalan' ) );
setReadOnly( stdmath, 'FLOAT64_LN2', require( '@stdlib/math/constants/float64-ln2' ) );
setReadOnly( stdmath, 'FLOAT64_LN_SQRT_TWO_PI', require( '@stdlib/math/constants/float64-ln-sqrt-two-pi' ) );

setReadOnly( stdmath, 'FLOAT32_PINF', require( '@stdlib/math/constants/float32-pinf' ) );
setReadOnly( stdmath, 'FLOAT32_NINF', require( '@stdlib/math/constants/float32-ninf' ) );
setReadOnly( stdmath, 'FLOAT64_PINF', require( '@stdlib/math/constants/float64-pinf' ) );
setReadOnly( stdmath, 'FLOAT64_NINF', require( '@stdlib/math/constants/float64-ninf' ) );

setReadOnly( stdmath, 'INT8_MAX', require( '@stdlib/math/constants/int8-max' ) );
setReadOnly( stdmath, 'INT8_MIN', require( '@stdlib/math/constants/int8-min' ) );
setReadOnly( stdmath, 'INT16_MAX', require( '@stdlib/math/constants/int16-max' ) );
setReadOnly( stdmath, 'INT16_MIN', require( '@stdlib/math/constants/int16-min' ) );
setReadOnly( stdmath, 'INT32_MAX', require( '@stdlib/math/constants/int32-max' ) );
setReadOnly( stdmath, 'INT32_MIN', require( '@stdlib/math/constants/int32-min' ) );
setReadOnly( stdmath, 'UINT32_MAX', require( '@stdlib/math/constants/uint32-max' ) );
setReadOnly( stdmath, 'FLOAT64_MAX', require( '@stdlib/math/constants/float64-max' ) );
setReadOnly( stdmath, 'FLOAT64_MAX_SAFE_INTEGER', require( '@stdlib/math/constants/float64-max-safe-integer' ) );
setReadOnly( stdmath, 'FLOAT64_MIN_SAFE_INTEGER', require( '@stdlib/math/constants/float64-min-safe-integer' ) );

setReadOnly( stdmath, 'FLOAT64_EPSILON', require( '@stdlib/math/constants/float64-eps' ) );
setReadOnly( stdmath, 'FLOAT64_SQRT_EPSILON', require( '@stdlib/math/constants/float64-sqrt-eps' ) );

setReadOnly( stdmath, 'FLOAT16_PRECISION', require( '@stdlib/math/constants/float16-precision' ) );
setReadOnly( stdmath, 'FLOAT32_PRECISION', require( '@stdlib/math/constants/float32-precision' ) );
setReadOnly( stdmath, 'FLOAT64_PRECISION', require( '@stdlib/math/constants/float64-precision' ) );

// Special functions (base):
setReadOnly( stdmath.base, 'round', require( '@stdlib/math/base/special/round' ) );
setReadOnly( stdmath.base, 'roundn', require( '@stdlib/math/base/special/roundn' ) );
setReadOnly( stdmath.base, 'floor', require( '@stdlib/math/base/special/floor' ) );
setReadOnly( stdmath.base, 'ceil', require( '@stdlib/math/base/special/ceil' ) );
setReadOnly( stdmath.base, 'truncate', require( '@stdlib/math/base/special/truncate' ) );
setReadOnly( stdmath.base, 'abs', require( '@stdlib/math/base/special/abs' ) );
setReadOnly( stdmath.base, 'pow', require( '@stdlib/math/base/special/pow' ) );
setReadOnly( stdmath.base, 'sqrt', require( '@stdlib/math/base/special/sqrt' ) );
setReadOnly( stdmath.base, 'exp', require( '@stdlib/math/base/special/exp' ) );
setReadOnly( stdmath.base, 'ln', require( '@stdlib/math/base/special/ln' ) );
setReadOnly( stdmath.base, 'signum', require( '@stdlib/math/base/special/signum' ) );
setReadOnly( stdmath.base, 'flipsign', require( '@stdlib/math/base/special/flipsign' ) );

// Utilities (base):
setReadOnly( stdmath.base, 'isNaN', require( '@stdlib/math/base/utils/is-nan' ) );
setReadOnly( stdmath.base, 'isFinite', require( '@stdlib/math/base/utils/is-finite' ) );
setReadOnly( stdmath.base, 'isInfinite', require( '@stdlib/math/base/utils/is-infinite' ) );
setReadOnly( stdmath.base, 'isNegativeZero', require( '@stdlib/math/base/utils/is-negative-zero' ) );
setReadOnly( stdmath.base, 'isPositiveZero', require( '@stdlib/math/base/utils/is-positive-zero' ) );
setReadOnly( stdmath.base, 'isInteger', require( '@stdlib/math/base/utils/is-integer' ) );
setReadOnly( stdmath.base, 'isPositiveInteger', require( '@stdlib/math/base/utils/is-positive-integer' ) );
setReadOnly( stdmath.base, 'isNonNegativeInteger', require( '@stdlib/math/base/utils/is-nonnegative-integer' ) );
setReadOnly( stdmath.base, 'isNegativeInteger', require( '@stdlib/math/base/utils/is-negative-integer' ) );
setReadOnly( stdmath.base, 'isNonPositiveInteger', require( '@stdlib/math/base/utils/is-nonpositive-integer' ) );

setReadOnly( stdmath.base, 'absoluteDifference', require( '@stdlib/math/base/utils/absolute-difference' ) );
setReadOnly( stdmath.base, 'relativeDifference', require( '@stdlib/math/base/utils/relative-difference' ) );

// Tools (base):
setReadOnly( stdmath.base, 'evalpoly', require( '@stdlib/math/base/tools/evalpoly' ) );
setReadOnly( stdmath.base, 'evalrational', require( '@stdlib/math/base/tools/evalrational' ) );

// Utilities (generics):
setReadOnly( stdmath, 'linspace', require( '@stdlib/math/generics/utils/linspace' ) );
setReadOnly( stdmath, 'logspace', require( '@stdlib/math/generics/utils/logspace' ) );
setReadOnly( stdmath, 'incrspace', require( '@stdlib/math/generics/utils/incrspace' ) );

// EXPORTS //

module.exports = stdmath;
<|endoftext|>


<commit_before>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Handler.js
 * @requires OpenLayers/Geometry/Point.js
 */

/**
 * Class: OpenLayers.Handler.Point
 * Handler to draw a point on the map. Point is displayed on activation,
 *     moves on mouse move, and is finished on mouse up. The handler triggers
 *     callbacks for 'done', 'cancel', and 'modify'. The modify callback is
 *     called with each change in the sketch and will receive the latest point
 *     drawn.  Create a new instance with the <OpenLayers.Handler.Point>
 *     constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {

    /**
     * Property: point
     * {<OpenLayers.Feature.Vector>} The currently drawn point
     */
    point: null,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
     */
    layer: null,

    /**
     * APIProperty: multi
     * {Boolean} Cast features to multi-part geometries before passing to the
     *     layer.  Default is false.
     */
    multi: false,

    /**
     * Property: mouseDown
     * {Boolean} The mouse is down
     */
    mouseDown: false,

    /**
     * Property: stoppedDown
     * {Boolean} Indicate whether the last mousedown stopped the event
     * propagation.
     */
    stoppedDown: null,

    /**
     * Property: lastDown
     * {<OpenLayers.Pixel>} Location of the last mouse down
     */
    lastDown: null,

    /**
     * Property: lastUp
     * {<OpenLayers.Pixel>}
     */
    lastUp: null,

    /**
     * APIProperty: persist
     * {Boolean} Leave the feature rendered until destroyFeature is called.
     *     Default is false.  If set to true, the feature remains rendered until
     *     destroyFeature is called, typically by deactivating the handler or
     *     starting another drawing.
     */
    persist: false,

    /**
     * APIProperty: stopDown
     * {Boolean} Stop event propagation on mousedown. Must be false to
     *     allow "pan while drawing". Defaults to false.
     */
    stopDown: false,

    /**
     * APIPropery: stopUp
     * {Boolean} Stop event propagation on mouse. Must be false to
     *     allow "pan while dragging". Defaults to fase.
     */
    stopUp: false,

    /**
     * Property: layerOptions
     * {Object} Any optional properties to be set on the sketch layer.
     */
    layerOptions: null,

    /**
     * APIProperty: pixelTolerance
     * {Number} Maximum number of pixels between down and up (mousedown
     *     and mouseup, or touchstart and touchend) for the handler to
     *     add a new point. If set to an integer value, if the
     *     displacement between down and up is great to this value
     *     no point will be added. Default value is 5.
     */
    pixelTolerance: 5,

    /**
     * APIProperty: dblclickTolerance
     * {Number} Maximum number of pixels between two touchend for an
     *     event to be considered a dblclick.  Default is 20.
     */
    dblclickTolerance: 20,

    /**
     * Property: touch
     * {Boolean} Indcates the support of touch events.
     */
    touch: false,

    /**
     * Property: lastTouchPx
     * {<OpenLayers.Pixel>} The last pixel used to know the distance between
     * two touches (for double touch).
     */
    lastTouchPx: null,

    /**
     * Constructor: OpenLayers.Handler.Point
     * Create a new point handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the point geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {
        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
        }

        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
    },

    /**
     * APIMethod: activate
     * turn on the handler
     */
    activate: function() {
        if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
            return false;
        }
        // create temporary vector layer for rendering geometry sketch
        // TBD: this could be moved to initialize/destroy - setting visibility here
        var options = OpenLayers.Util.extend({
            displayInLayerSwitcher: false,
            // indicate that the temp vector layer will never be out of range
            // without this, resolution properties must be specified at the
            // map-level for this temporary layer to init its resolutions
            // correctly
            calculateInRange: OpenLayers.Function.True
        }, this.layerOptions);
        this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
        this.map.addLayer(this.layer);
        this.createFeature();
        return true;
    },

    /**
     * Method: createFeature
     * Add temporary features
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    createFeature: function(pixel) {
        var geometry;
        if(pixel) {
            var lonlat = this.map.getLonLatFromPixel(pixel);
            geometry = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
        } else {
            geometry = new OpenLayers.Geometry.Point();
        }
        this.point = new OpenLayers.Feature.Vector(geometry);
        this.callback("create", [this.point.geometry, this.point]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.point], {silent: true});
    },

    /**
     * APIMethod: deactivate
     * turn off the handler
     */
    deactivate: function() {
        if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
            return false;
        }
        this.cancel(true);
        // If a layer's map property is set to null, it means that that layer
        // isn't added to the map. Since we ourself added the layer to the map
        // in activate(), we can assume that if this.layer.map is null it means
        // that the layer has been destroyed (as a result of map.destroy() for
        // example.
        if (this.layer.map != null) {
            this.destroyFeature();
            this.layer.destroy(false);
        }
        this.layer = null;
        this.touch = false;
        return true;
    },

    /**
     * Method: destroyFeature
     * Destroy the temporary geometries
     */
    destroyFeature: function() {
        if(this.layer) {
            this.layer.destroyFeatures();
        }
        this.point = null;
    },

    /**
     * Method: destroyPersistedFeature
     * Destroy the persisted feature.
     */
    destroyPersistedFeature: function() {
        var layer = this.layer;
        if(layer && layer.features.length > 1) {
            this.layer.features[0].destroy();
        }
    },

    /**
     * Method: finishTouchGeometry
     * Finish the geometry and send it back to the control.
     */
    finishTouchGeometry: function() {
        this.finalize();
    },

    /**
     * Method: finalize
     * Finish the geometry and call the "done" callback.
     *
     * Parameters:
     * cancel - {Boolean} Call cancel instead of done callback.  Default is
     *     false.
     * noNew - {Boolean} Do not create a new feature after
     *     finalization.  Default is false.
     */
    finalize: function(cancel, noNew) {
        var key = cancel ? "cancel" : "done";
        this.drawing = false;
        this.mouseDown = false;
        this.lastDown = null;
        this.lastUp = null;
        this.lastTouchPx = null;
        this.callback(key, [this.geometryClone()]);
        if(cancel || !this.persist) {
            this.destroyFeature();
        }
        if(!noNew && this.active) {
            this.createFeature();
        }
    },

    /**
     * APIMethod: cancel
     * Finish the geometry and call the "cancel" callback.
     *
     * Parameters:
     * noNew - {Boolean} Do not create a new feature after
     *     cancelation.  Default is false.
     */
    cancel: function(noNew) {
        this.finalize(true, noNew);
    },

    /**
     * Method: click
     * Handle clicks.  Clicks are stopped from propagating to other listeners
     *     on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    click: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Double-clicks are stopped from propagating to other
     *     listeners on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    dblclick: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given a pixel location.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    modifyFeature: function(pixel) {
        var lonlat = this.map.getLonLatFromPixel(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;
        this.callback("modify", [this.point.geometry, this.point, false]);
        this.point.geometry.clearBounds();
        this.drawFeature();
    },

    /**
     * Method: drawFeature
     * Render features on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Point>}
     */
    getGeometry: function() {
        var geometry = this.point && this.point.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
        }
        return geometry;
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry>}
     */
    geometryClone: function() {
        var geom = this.getGeometry();
        return geom && geom.clone();
    },

    /**
     * Method: mousedown
     * Handle mousedown.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        return this.down(evt);
    },

    /**
     * Method: touchstart
     * Handle touchstart.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchstart: function(evt) {
        if (!this.touch) {
            this.touch = true;
            // unregister mouse listeners
            this.map.events.un({
                mousedown: this.mousedown,
                mouseup: this.mouseup,
                mousemove: this.mousemove,
                click: this.click,
                dblclick: this.dblclick,
                scope: this
            });
        }
        this.lastTouchPx = evt.xy;
        return this.down(evt);
    },

    /**
     * Method: mousemove
     * Handle mousemove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousemove: function(evt) {
        return this.move(evt);
    },

    /**
     * Method: touchmove
     * Handle touchmove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchmove: function(evt) {
        this.lastTouchPx = evt.xy;
        return this.move(evt);
    },

    /**
     * Method: mouseup
     * Handle mouseup.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mouseup: function(evt) {
        return this.up(evt);
    },

    /**
     * Method: touchend
     * Handle touchend.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchend: function(evt) {
        evt.xy = this.lastTouchPx;
        return this.up(evt);
    },

    /**
     * Method: down
     * Handle mousedown and touchstart.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    down: function(evt) {
        this.mouseDown = true;
        this.lastDown = evt.xy;
        if(!this.touch) { // no point displayed until up on touch devices
            this.modifyFeature(evt.xy);
        }
        this.stoppedDown = this.stopDown;
        return !this.stopDown;
    },

    /**
     * Method: move
     * Handle mousemove and touchmove.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    move: function (evt) {
        if(!this.touch // no point displayed until up on touch devices
           && (!this.mouseDown || this.stoppedDown)) {
            this.modifyFeature(evt.xy);
        }
        return true;
    },

    /**
     * Method: up
     * Handle mouseup and touchend.  Send the latest point in the geometry to the control.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    up: function (evt) {
        this.mouseDown = false;
        this.stoppedDown = this.stopDown;

        // check keyboard modifiers
        if(!this.checkModifiers(evt)) {
            return true;
        }
        // ignore double-clicks
        if (this.lastUp && this.passesTolerance(this.lastUp, evt.xy,
                                                this.dblclickTolerance)) {
            return true;
        }
        if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy,
                                                  this.pixelTolerance)) {
            if (this.touch) {
                this.modifyFeature(evt.xy);
            }
            if(this.persist) {
                this.destroyPersistedFeature();
            }
            this.lastUp = evt.xy;
            this.finalize();
            return !this.stopUp;
        } else {
            return true;
        }
    },

    /**
     * Method: mouseout
     * Handle mouse out.  For better user experience reset mouseDown
     * and stoppedDown when the mouse leaves the map viewport.
     *
     * Parameters:
     * evt - {Event} The browser event
     */
    mouseout: function(evt) {
        if(OpenLayers.Util.mouseLeft(evt, this.map.eventsDiv)) {
            this.stoppedDown = this.stopDown;
            this.mouseDown = false;
        }
    },

    /**
     * Method: passesTolerance
     * Determine whether the event is within the optional pixel tolerance.
     * Note that the pixel tolerance check only works if mousedown events get
     * to the listeners registered here.  If they are stopped by other
     * elements, <pixelTolerance> and <dblclickTolerance> will have no effect
     * here (this method will always return true).
     *
     * Returns:
     * {Boolean} The click is within the pixel tolerance (if specified).
     */
    passesTolerance: function(pixel1, pixel2, tolerance) {
        var passes = true;

        if (tolerance != null && pixel1 && pixel2) {
            var dist = pixel1.distanceTo(pixel2);
            if (dist > tolerance) {
                passes = false;
            }
        }
        return passes;
    },

    CLASS_NAME: "OpenLayers.Handler.Point"
});
<commit_msg>point handler - remove the ununsed finishTouchGeometry function, no functional change<commit_after>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Handler.js
 * @requires OpenLayers/Geometry/Point.js
 */

/**
 * Class: OpenLayers.Handler.Point
 * Handler to draw a point on the map. Point is displayed on activation,
 *     moves on mouse move, and is finished on mouse up. The handler triggers
 *     callbacks for 'done', 'cancel', and 'modify'. The modify callback is
 *     called with each change in the sketch and will receive the latest point
 *     drawn.  Create a new instance with the <OpenLayers.Handler.Point>
 *     constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {

    /**
     * Property: point
     * {<OpenLayers.Feature.Vector>} The currently drawn point
     */
    point: null,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
     */
    layer: null,

    /**
     * APIProperty: multi
     * {Boolean} Cast features to multi-part geometries before passing to the
     *     layer.  Default is false.
     */
    multi: false,

    /**
     * Property: mouseDown
     * {Boolean} The mouse is down
     */
    mouseDown: false,

    /**
     * Property: stoppedDown
     * {Boolean} Indicate whether the last mousedown stopped the event
     * propagation.
     */
    stoppedDown: null,

    /**
     * Property: lastDown
     * {<OpenLayers.Pixel>} Location of the last mouse down
     */
    lastDown: null,

    /**
     * Property: lastUp
     * {<OpenLayers.Pixel>}
     */
    lastUp: null,

    /**
     * APIProperty: persist
     * {Boolean} Leave the feature rendered until destroyFeature is called.
     *     Default is false.  If set to true, the feature remains rendered until
     *     destroyFeature is called, typically by deactivating the handler or
     *     starting another drawing.
     */
    persist: false,

    /**
     * APIProperty: stopDown
     * {Boolean} Stop event propagation on mousedown. Must be false to
     *     allow "pan while drawing". Defaults to false.
     */
    stopDown: false,

    /**
     * APIPropery: stopUp
     * {Boolean} Stop event propagation on mouse. Must be false to
     *     allow "pan while dragging". Defaults to fase.
     */
    stopUp: false,

    /**
     * Property: layerOptions
     * {Object} Any optional properties to be set on the sketch layer.
     */
    layerOptions: null,

    /**
     * APIProperty: pixelTolerance
     * {Number} Maximum number of pixels between down and up (mousedown
     *     and mouseup, or touchstart and touchend) for the handler to
     *     add a new point. If set to an integer value, if the
     *     displacement between down and up is great to this value
     *     no point will be added. Default value is 5.
     */
    pixelTolerance: 5,

    /**
     * APIProperty: dblclickTolerance
     * {Number} Maximum number of pixels between two touchend for an
     *     event to be considered a dblclick.  Default is 20.
     */
    dblclickTolerance: 20,

    /**
     * Property: touch
     * {Boolean} Indcates the support of touch events.
     */
    touch: false,

    /**
     * Property: lastTouchPx
     * {<OpenLayers.Pixel>} The last pixel used to know the distance between
     * two touches (for double touch).
     */
    lastTouchPx: null,

    /**
     * Constructor: OpenLayers.Handler.Point
     * Create a new point handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the point geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {
        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
        }

        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
    },

    /**
     * APIMethod: activate
     * turn on the handler
     */
    activate: function() {
        if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
            return false;
        }
        // create temporary vector layer for rendering geometry sketch
        // TBD: this could be moved to initialize/destroy - setting visibility here
        var options = OpenLayers.Util.extend({
            displayInLayerSwitcher: false,
            // indicate that the temp vector layer will never be out of range
            // without this, resolution properties must be specified at the
            // map-level for this temporary layer to init its resolutions
            // correctly
            calculateInRange: OpenLayers.Function.True
        }, this.layerOptions);
        this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
        this.map.addLayer(this.layer);
        this.createFeature();
        return true;
    },

    /**
     * Method: createFeature
     * Add temporary features
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    createFeature: function(pixel) {
        var geometry;
        if(pixel) {
            var lonlat = this.map.getLonLatFromPixel(pixel);
            geometry = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
        } else {
            geometry = new OpenLayers.Geometry.Point();
        }
        this.point = new OpenLayers.Feature.Vector(geometry);
        this.callback("create", [this.point.geometry, this.point]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.point], {silent: true});
    },

    /**
     * APIMethod: deactivate
     * turn off the handler
     */
    deactivate: function() {
        if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
            return false;
        }
        this.cancel(true);
        // If a layer's map property is set to null, it means that that layer
        // isn't added to the map. Since we ourself added the layer to the map
        // in activate(), we can assume that if this.layer.map is null it means
        // that the layer has been destroyed (as a result of map.destroy() for
        // example.
        if (this.layer.map != null) {
            this.destroyFeature();
            this.layer.destroy(false);
        }
        this.layer = null;
        this.touch = false;
        return true;
    },

    /**
     * Method: destroyFeature
     * Destroy the temporary geometries
     */
    destroyFeature: function() {
        if(this.layer) {
            this.layer.destroyFeatures();
        }
        this.point = null;
    },

    /**
     * Method: destroyPersistedFeature
     * Destroy the persisted feature.
     */
    destroyPersistedFeature: function() {
        var layer = this.layer;
        if(layer && layer.features.length > 1) {
            this.layer.features[0].destroy();
        }
    },

    /**
     * Method: finalize
     * Finish the geometry and call the "done" callback.
     *
     * Parameters:
     * cancel - {Boolean} Call cancel instead of done callback.  Default is
     *     false.
     * noNew - {Boolean} Do not create a new feature after
     *     finalization.  Default is false.
     */
    finalize: function(cancel, noNew) {
        var key = cancel ? "cancel" : "done";
        this.drawing = false;
        this.mouseDown = false;
        this.lastDown = null;
        this.lastUp = null;
        this.lastTouchPx = null;
        this.callback(key, [this.geometryClone()]);
        if(cancel || !this.persist) {
            this.destroyFeature();
        }
        if(!noNew && this.active) {
            this.createFeature();
        }
    },

    /**
     * APIMethod: cancel
     * Finish the geometry and call the "cancel" callback.
     *
     * Parameters:
     * noNew - {Boolean} Do not create a new feature after
     *     cancelation.  Default is false.
     */
    cancel: function(noNew) {
        this.finalize(true, noNew);
    },

    /**
     * Method: click
     * Handle clicks.  Clicks are stopped from propagating to other listeners
     *     on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    click: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Double-clicks are stopped from propagating to other
     *     listeners on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    dblclick: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given a pixel location.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    modifyFeature: function(pixel) {
        var lonlat = this.map.getLonLatFromPixel(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;
        this.callback("modify", [this.point.geometry, this.point, false]);
        this.point.geometry.clearBounds();
        this.drawFeature();
    },

    /**
     * Method: drawFeature
     * Render features on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Point>}
     */
    getGeometry: function() {
        var geometry = this.point && this.point.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
        }
        return geometry;
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry>}
     */
    geometryClone: function() {
        var geom = this.getGeometry();
        return geom && geom.clone();
    },

    /**
     * Method: mousedown
     * Handle mousedown.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        return this.down(evt);
    },

    /**
     * Method: touchstart
     * Handle touchstart.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchstart: function(evt) {
        if (!this.touch) {
            this.touch = true;
            // unregister mouse listeners
            this.map.events.un({
                mousedown: this.mousedown,
                mouseup: this.mouseup,
                mousemove: this.mousemove,
                click: this.click,
                dblclick: this.dblclick,
                scope: this
            });
        }
        this.lastTouchPx = evt.xy;
        return this.down(evt);
    },

    /**
     * Method: mousemove
     * Handle mousemove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousemove: function(evt) {
        return this.move(evt);
    },

    /**
     * Method: touchmove
     * Handle touchmove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchmove: function(evt) {
        this.lastTouchPx = evt.xy;
        return this.move(evt);
    },

    /**
     * Method: mouseup
     * Handle mouseup.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mouseup: function(evt) {
        return this.up(evt);
    },

    /**
     * Method: touchend
     * Handle touchend.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchend: function(evt) {
        evt.xy = this.lastTouchPx;
        return this.up(evt);
    },

    /**
     * Method: down
     * Handle mousedown and touchstart.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    down: function(evt) {
        this.mouseDown = true;
        this.lastDown = evt.xy;
        if(!this.touch) { // no point displayed until up on touch devices
            this.modifyFeature(evt.xy);
        }
        this.stoppedDown = this.stopDown;
        return !this.stopDown;
    },

    /**
     * Method: move
     * Handle mousemove and touchmove.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    move: function (evt) {
        if(!this.touch // no point displayed until up on touch devices
           && (!this.mouseDown || this.stoppedDown)) {
            this.modifyFeature(evt.xy);
        }
        return true;
    },

    /**
     * Method: up
     * Handle mouseup and touchend.  Send the latest point in the geometry to the control.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    up: function (evt) {
        this.mouseDown = false;
        this.stoppedDown = this.stopDown;

        // check keyboard modifiers
        if(!this.checkModifiers(evt)) {
            return true;
        }
        // ignore double-clicks
        if (this.lastUp && this.passesTolerance(this.lastUp, evt.xy,
                                                this.dblclickTolerance)) {
            return true;
        }
        if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy,
                                                  this.pixelTolerance)) {
            if (this.touch) {
                this.modifyFeature(evt.xy);
            }
            if(this.persist) {
                this.destroyPersistedFeature();
            }
            this.lastUp = evt.xy;
            this.finalize();
            return !this.stopUp;
        } else {
            return true;
        }
    },

    /**
     * Method: mouseout
     * Handle mouse out.  For better user experience reset mouseDown
     * and stoppedDown when the mouse leaves the map viewport.
     *
     * Parameters:
     * evt - {Event} The browser event
     */
    mouseout: function(evt) {
        if(OpenLayers.Util.mouseLeft(evt, this.map.eventsDiv)) {
            this.stoppedDown = this.stopDown;
            this.mouseDown = false;
        }
    },

    /**
     * Method: passesTolerance
     * Determine whether the event is within the optional pixel tolerance.
     * Note that the pixel tolerance check only works if mousedown events get
     * to the listeners registered here.  If they are stopped by other
     * elements, <pixelTolerance> and <dblclickTolerance> will have no effect
     * here (this method will always return true).
     *
     * Returns:
     * {Boolean} The click is within the pixel tolerance (if specified).
     */
    passesTolerance: function(pixel1, pixel2, tolerance) {
        var passes = true;

        if (tolerance != null && pixel1 && pixel2) {
            var dist = pixel1.distanceTo(pixel2);
            if (dist > tolerance) {
                passes = false;
            }
        }
        return passes;
    },

    CLASS_NAME: "OpenLayers.Handler.Point"
});
<|endoftext|>


<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';

import { Abelito75 } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

export default [
  change(date(2019, 11, 9),<>Fixed a bugged where precasted <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> would break a few modules. </>,Abelito75),
  change(date(2019, 10, 28),<>Added bad <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> cast highlighting to the timeline. </>,Abelito75),
  change(date(2019, 10, 3),<>Spell reflect is now based off of damage reduced. </>,Abelito75),
  change(date(2019, 9, 30),<>Removed Arcane Torrent from suggestions. </>,Abelito75),
  change(date(2019, 9, 27),<>Officially supported! </>,Abelito75),
  change(date(2019, 9, 27),<>Update to date for 8.2.5 </>,Abelito75),
  change(date(2019, 9, 18),<>Physical hits blocked now only checks blockable hits. </>,Abelito75),
  change(date(2019, 9, 4),<>Fixed a bug in <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} />. </>,Abelito75),
  change(date(2019, 9, 4),<>Changed timeformat for <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} />. </>,Abelito75),
  change(date(2019, 9, 4),<>Updated wording for <SpellLink id={SPELLS.AVATAR_TALENT.id} />.</>,Abelito75),
  change(date(2019, 8, 26),<>Added support for <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} /></>,Abelito75),
  change(date(2019, 8, 26),<>Updated spells for prot warrior to include <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} /> buff. </>,Abelito75),
  change(date(2019, 8, 24),<>Updated possible uptime on <SpellLink id={SPELLS.AVATAR_TALENT.id} /> if you are taking <SpellLink id={SPELLS.VISION_OF_PERFECTION.id} /> </>,Abelito75),
  change(date(2019, 8, 24),<>Added new <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> logic to be able to determine if a shield block is good or bad from either a defensive or offensive POV.</>,Abelito75),
  change(date(2019, 8, 23),<>Updated threshold for <SpellLink id={SPELLS.HEAVY_REPERCUSSIONS_TALENT.id} /> to be humanly possible. </>,Abelito75),
  change(date(2019, 8, 22),<>Updated cooldown tracking when <SpellLink id={SPELLS.ANGER_MANAGEMENT_TALENT.id} /> is talented. Also added visions of perfection so we have no more missing spell.  </>,Abelito75),
  change(date(2019, 8, 15),<>Buff tracking changed for timeline.</>,Abelito75),
  change(date(2019, 8, 15),<>Shield Slam module created for assuming possible casts.</>,Abelito75),
  change(date(2019, 8, 9),<>Big overhaul to checklist. We also have a working checklist again</>,Abelito75),
  change(date(2019, 7, 31),<>We have a supporter</>,Abelito75),
];
<commit_msg>changelog<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';

import { Abelito75 } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

export default [
  change(date(2019, 1, 5),<>Included Lucid dream statistic. </>,Abelito75),
  change(date(2019, 11, 9),<>Fixed a bugged where precasted <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> would break a few modules. </>,Abelito75),
  change(date(2019, 10, 28),<>Added bad <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> cast highlighting to the timeline. </>,Abelito75),
  change(date(2019, 10, 3),<>Spell reflect is now based off of damage reduced. </>,Abelito75),
  change(date(2019, 9, 30),<>Removed Arcane Torrent from suggestions. </>,Abelito75),
  change(date(2019, 9, 27),<>Officially supported! </>,Abelito75),
  change(date(2019, 9, 27),<>Update to date for 8.2.5 </>,Abelito75),
  change(date(2019, 9, 18),<>Physical hits blocked now only checks blockable hits. </>,Abelito75),
  change(date(2019, 9, 4),<>Fixed a bug in <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} />. </>,Abelito75),
  change(date(2019, 9, 4),<>Changed timeformat for <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} />. </>,Abelito75),
  change(date(2019, 9, 4),<>Updated wording for <SpellLink id={SPELLS.AVATAR_TALENT.id} />.</>,Abelito75),
  change(date(2019, 8, 26),<>Added support for <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} /></>,Abelito75),
  change(date(2019, 8, 26),<>Updated spells for prot warrior to include <SpellLink id={SPELLS.BRACE_FOR_IMPACT.id} /> buff. </>,Abelito75),
  change(date(2019, 8, 24),<>Updated possible uptime on <SpellLink id={SPELLS.AVATAR_TALENT.id} /> if you are taking <SpellLink id={SPELLS.VISION_OF_PERFECTION.id} /> </>,Abelito75),
  change(date(2019, 8, 24),<>Added new <SpellLink id={SPELLS.SHIELD_BLOCK.id} /> logic to be able to determine if a shield block is good or bad from either a defensive or offensive POV.</>,Abelito75),
  change(date(2019, 8, 23),<>Updated threshold for <SpellLink id={SPELLS.HEAVY_REPERCUSSIONS_TALENT.id} /> to be humanly possible. </>,Abelito75),
  change(date(2019, 8, 22),<>Updated cooldown tracking when <SpellLink id={SPELLS.ANGER_MANAGEMENT_TALENT.id} /> is talented. Also added visions of perfection so we have no more missing spell.  </>,Abelito75),
  change(date(2019, 8, 15),<>Buff tracking changed for timeline.</>,Abelito75),
  change(date(2019, 8, 15),<>Shield Slam module created for assuming possible casts.</>,Abelito75),
  change(date(2019, 8, 9),<>Big overhaul to checklist. We also have a working checklist again</>,Abelito75),
  change(date(2019, 7, 31),<>We have a supporter</>,Abelito75),
];
<|endoftext|>


<commit_before>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Joel Denning @joeldenning
 */

"use strict";

const { ConcatSource } = require("webpack-sources");
const Template = require("./Template");

/** @typedef {import("./Compilation")} Compilation */

/**
 * @typedef {Object} SystemMainTemplatePluginOptions
 * @param {string=} name the library name
 */

class SystemMainTemplatePlugin {
	/**
	 * @param {SystemMainTemplatePluginOptions} options the plugin options
	 */
	constructor(options) {
		this.name = options.name;
	}

	/**
	 * @param {Compilation} compilation the compilation instance
	 * @returns {void}
	 */
	apply(compilation) {
		const { mainTemplate, chunkTemplate } = compilation;

		const onRenderWithEntry = (source, chunk, hash) => {
			const externals = chunk.getModules().filter(m => m.external);

			// The name this bundle should be registered as with System
			const name = this.name ? `"${this.name}", ` : "";

			// The array of dependencies that are external to webpack and will be provided by System
			const systemDependencies = JSON.stringify(
				externals.map(m =>
					typeof m.request === "object" ? m.request.amd : m.request
				)
			);

			// The name of the variable provided by System for exporting
			const dynamicExport = "__WEBPACK_DYNAMIC_EXPORT__";

			// An array of the internal variable names for the webpack externals
			const externalWebpackNames = externals.map(
				m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
			);

			// Declaring variables for the internal variable names for the webpack externals
			const externalVarDeclarations =
				externalWebpackNames.length > 0
					? `var ${externalWebpackNames.join(", ")};`
					: "";

			// The system.register format requires an array of setter functions for externals.
			const setters =
				externalWebpackNames.length === 0
					? ""
					: Template.asString([
							"setters: [",
							Template.indent(
								externalWebpackNames.map((external, index) =>
									Template.asString([
										"function(module) {",
										Template.indent(`${external} = module;`),
										`}${index < externalWebpackNames.length - 1 ? "," : ""}`
									])
								)
							),
							"],"
					  ]);

			return new ConcatSource(
				Template.asString([
					`System.register(${name}${systemDependencies}, function(${dynamicExport}) {`,
					Template.indent([
						externalVarDeclarations,
						"return {",
						Template.indent([
							setters,
							"execute: function() {",
							Template.indent(`${dynamicExport}(`)
						])
					])
				]),
				source,
				Template.asString([
					Template.indent([
						Template.indent([Template.indent([");"]), "}"]),
						"};"
					]),
					"})"
				])
			);
		};

		for (const template of [mainTemplate, chunkTemplate]) {
			template.hooks.renderWithEntry.tap(
				"SystemMainTemplatePlugin",
				onRenderWithEntry
			);
		}

		mainTemplate.hooks.globalHashPaths.tap(
			"SystemMainTemplatePlugin",
			paths => {
				if (this.name) {
					paths.push(this.name);
				}
				return paths;
			}
		);

		mainTemplate.hooks.hash.tap("SystemMainTemplatePlugin", hash => {
			hash.update("exports system");
			if (this.name) {
				hash.update(this.name);
			}
		});
	}
}

module.exports = SystemMainTemplatePlugin;
<commit_msg>formating of output code<commit_after>/*
 MIT License http://www.opensource.org/licenses/mit-license.php
 Author Joel Denning @joeldenning
 */

"use strict";

const { ConcatSource } = require("webpack-sources");
const Template = require("./Template");

/** @typedef {import("./Compilation")} Compilation */

/**
 * @typedef {Object} SystemMainTemplatePluginOptions
 * @param {string=} name the library name
 */

class SystemMainTemplatePlugin {
	/**
	 * @param {SystemMainTemplatePluginOptions} options the plugin options
	 */
	constructor(options) {
		this.name = options.name;
	}

	/**
	 * @param {Compilation} compilation the compilation instance
	 * @returns {void}
	 */
	apply(compilation) {
		const { mainTemplate, chunkTemplate } = compilation;

		const onRenderWithEntry = (source, chunk, hash) => {
			const externals = chunk.getModules().filter(m => m.external);

			// The name this bundle should be registered as with System
			const name = this.name ? `${JSON.stringify(this.name)}, ` : "";

			// The array of dependencies that are external to webpack and will be provided by System
			const systemDependencies = JSON.stringify(
				externals.map(m =>
					typeof m.request === "object" ? m.request.amd : m.request
				)
			);

			// The name of the variable provided by System for exporting
			const dynamicExport = "__WEBPACK_DYNAMIC_EXPORT__";

			// An array of the internal variable names for the webpack externals
			const externalWebpackNames = externals.map(
				m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
			);

			// Declaring variables for the internal variable names for the webpack externals
			const externalVarDeclarations =
				externalWebpackNames.length > 0
					? `var ${externalWebpackNames.join(", ")};`
					: "";

			// The system.register format requires an array of setter functions for externals.
			const setters =
				externalWebpackNames.length === 0
					? ""
					: Template.asString([
							"setters: [",
							Template.indent(
								externalWebpackNames
									.map(external =>
										Template.asString([
											"function(module) {",
											Template.indent(`${external} = module;`),
											"}"
										])
									)
									.join(",\n")
							),
							"],"
					  ]);

			return new ConcatSource(
				Template.asString([
					`System.register(${name}${systemDependencies}, function(${dynamicExport}) {`,
					Template.indent([
						externalVarDeclarations,
						"return {",
						Template.indent([
							setters,
							"execute: function() {",
							Template.indent(`${dynamicExport}(`)
						])
					])
				]) + "\n",
				source,
				"\n" +
					Template.asString([
						Template.indent([
							Template.indent([Template.indent([");"]), "}"]),
							"};"
						]),
						"})"
					])
			);
		};

		for (const template of [mainTemplate, chunkTemplate]) {
			template.hooks.renderWithEntry.tap(
				"SystemMainTemplatePlugin",
				onRenderWithEntry
			);
		}

		mainTemplate.hooks.globalHashPaths.tap(
			"SystemMainTemplatePlugin",
			paths => {
				if (this.name) {
					paths.push(this.name);
				}
				return paths;
			}
		);

		mainTemplate.hooks.hash.tap("SystemMainTemplatePlugin", hash => {
			hash.update("exports system");
			if (this.name) {
				hash.update(this.name);
			}
		});
	}
}

module.exports = SystemMainTemplatePlugin;
<|endoftext|>


<commit_before>'use strict';

var diff         = require('es5-ext/lib/Array/prototype/diff')
  , d            = require('es5-ext/lib/Object/descriptor')
  , extend       = require('es5-ext/lib/Object/extend')
  , ParentSet    = require('./name-set')
  , getTagFilter = require('./property-tag-filter')
  , proto        = require('./')

  , defineProperty = Object.defineProperty
  , getPrototypeOf = Object.getPrototypeOf
  , objTypes = { namespace: true, prototype: true, object: true }
  , NameSet;

NameSet = function (obj) {
	var master, set;
	if (obj === proto) return obj.getOwnPropertyNames();
	ParentSet.call(this, obj);
	defineProperty(this, '_map', d({}));
	this._addSet(set = obj.getOwnPropertyNames());
	set.forEach(this._add, this);
	defineProperty(this, '_proto', d(getPrototypeOf(obj)));
	this._addSet(set = this._proto.getPropertyNames());
	set.forEach(this._add, this);

	master = obj;
	while (master && !objTypes.hasOwnProperty(master._type_)) master = master.obj;
	if (!master) return;
	if (master._type_ === 'prototype') master = master.ns;
	master.on('selfupdate', this._onSelfUpdate);
};

NameSet.prototype = Object.create(ParentSet.prototype, extend({
	constructor: d(NameSet),
	_addSet: d(function (set) {
		set.on('add', this._onAdd);
		set.on('delete', this._onDelete);
	}),
	_deleteSet: d(function (set) {
		set.off('add', this._onAdd);
		set.off('delete', this._onDelete);
	}),
	_add: d(function (name) {
		if (!this._map.hasOwnProperty(name)) this._map[name] = 0;
		if (++this._map[name] === 1) {
			this[this._serialize(name)] = name;
			++this.count;
			return true;
		}
		return false;
	}),
	_delete: d(function (name) {
		if (!--this._map[name]) {
			delete this[this._serialize(name)];
			--this.count;
			return true;
		}
		return false;
	})
}, d.binder({
	_onAdd: d(function (name) {
		if (this._add(name)) this.emit('add', name);
	}),
	_onDelete: d(function (name) {
		if (this._delete(name)) this.emit('delete', name);
	}),
	_onSelfUpdate: d(function () {
		var nuProto = getPrototypeOf(this.obj), old, nu;
		if (nuProto === this._proto) return;
		this._deleteSet(old = this._proto.getPropertyNames());
		this._proto = nuProto;
		this._addSet(nu = nuProto.getPropertyNames());
		old = this.values;
		nu = this.values;
		diff.call(old, nu).forEach(this._onDelete);
		diff.call(nu, old).forEach(this._onAdd);
	})
})));

defineProperty(proto, 'getPropertyNames', d(function (tag) {
	if (tag != null) {
		return this.getPropertyNames().filter(getTagFilter(String(tag)));
	}
	if (!this.hasOwnProperty('_propertyNames_')) {
		defineProperty(this, '_propertyNames_', d(new NameSet(this)));
	}
	return this._propertyNames_;
}));
<commit_msg>Expose properties set via `getProperties`<commit_after>'use strict';

var diff         = require('es5-ext/lib/Array/prototype/diff')
  , d            = require('es5-ext/lib/Object/descriptor')
  , extend       = require('es5-ext/lib/Object/extend')
  , ParentSet    = require('./name-set')
  , getTagFilter = require('./property-tag-filter')
  , proto        = require('./')

  , defineProperty = Object.defineProperty
  , getPrototypeOf = Object.getPrototypeOf
  , objTypes = { namespace: true, prototype: true, object: true }
  , NameSet;

NameSet = function (obj) {
	var master, set;
	if (obj === proto) return obj.getOwnPropertyNames();
	ParentSet.call(this, obj);
	defineProperty(this, '_map', d({}));
	this._addSet(set = obj.getOwnPropertyNames());
	set.forEach(this._add, this);
	defineProperty(this, '_proto', d(getPrototypeOf(obj)));
	this._addSet(set = this._proto.getPropertyNames());
	set.forEach(this._add, this);

	master = obj;
	while (master && !objTypes.hasOwnProperty(master._type_)) master = master.obj;
	if (!master) return;
	if (master._type_ === 'prototype') master = master.ns;
	master.on('selfupdate', this._onSelfUpdate);
};

NameSet.prototype = Object.create(ParentSet.prototype, extend({
	constructor: d(NameSet),
	_addSet: d(function (set) {
		set.on('add', this._onAdd);
		set.on('delete', this._onDelete);
	}),
	_deleteSet: d(function (set) {
		set.off('add', this._onAdd);
		set.off('delete', this._onDelete);
	}),
	_add: d(function (name) {
		if (!this._map.hasOwnProperty(name)) this._map[name] = 0;
		if (++this._map[name] === 1) {
			this[this._serialize(name)] = name;
			++this.count;
			return true;
		}
		return false;
	}),
	_delete: d(function (name) {
		if (!--this._map[name]) {
			delete this[this._serialize(name)];
			--this.count;
			return true;
		}
		return false;
	})
}, d.binder({
	_onAdd: d(function (name) {
		if (this._add(name)) this.emit('add', name);
	}),
	_onDelete: d(function (name) {
		if (this._delete(name)) this.emit('delete', name);
	}),
	_onSelfUpdate: d(function () {
		var nuProto = getPrototypeOf(this.obj), old, nu;
		if (nuProto === this._proto) return;
		this._deleteSet(old = this._proto.getPropertyNames());
		this._proto = nuProto;
		this._addSet(nu = nuProto.getPropertyNames());
		old = this.values;
		nu = this.values;
		diff.call(old, nu).forEach(this._onDelete);
		diff.call(nu, old).forEach(this._onAdd);
	})
})));

defineProperty(proto, 'getPropertyNames', d(function (tag) {
	if (tag != null) {
		return this.getPropertyNames().filter(getTagFilter(String(tag)));
	}
	if (!this.hasOwnProperty('_propertyNames_')) {
		defineProperty(this, '_propertyNames_', d(new NameSet(this)));
	}
	return this._propertyNames_;
}));

defineProperty(proto, 'getProperties', d(function (tag) {
	return this.getPropertyNames(tag).relMap();
}));
<|endoftext|>