<commit_before>(function () {
  'use strict';

  var module = angular.module('sticky', []);

  // Directive: sticky
  //
  module.directive('sticky', ['$window', function ($window) {
      return {
        restrict: 'A', // this directive can only be used as an attribute.
        scope: {
          disabled: '=disabledSticky'
        },
        link: function linkFn($scope, $elem, $attrs) {
          // Setting scope
          var stickyLine;
          var stickyBottomLine;
          var placeholder;
          var isSticking = false;
          var originalOffset;

          // Optional Classes
          var stickyClass = $attrs.stickyClass || '';
          var unstickyClass = $attrs.unstickyClass || '';
          var bodyClass = $attrs.bodyClass || '';

          // Find scrollbar
          var scrollbar = deriveScrollingViewport($elem);

          // Define elements
          var windowElement = angular.element($window);
          var scrollbarElement = angular.element(scrollbar);
          var $body = angular.element(document.body);

          // Define options
          var usePlaceholder = ($attrs.usePlaceholder !== 'false');
          var anchor = $attrs.anchor === 'bottom' ? 'bottom' : 'top';
          var confine = ($attrs.confine === 'true');
          // flag: can react to recalculating the initial CSS dimensions later as link executes prematurely. defaults to immediate checking
          var isStickyLayoutDeferred = $attrs.isStickyLayoutDeferred !== undefined ? ($attrs.isStickyLayoutDeferred === 'true') : false;

          // flag: is sticky content constantly observed for changes. Should be true if content uses ngBind to show text that may vary in size over time
          var isStickyLayoutWatched =$attrs.isStickyLayoutWatched !== undefined ? ($attrs.isStickyLayoutWatched === 'true') : true;

          var offset = $attrs.offset ? parseInt($attrs.offset.replace(/px;?/, '')) : 0;
          var onStickyContentLayoutHeightWatchUnbind;

          // initial style
          var initialStyle = $elem.attr('style') || '';
          var initialCSS;

          /**
           * Initialize Sticky
           */
          var initSticky = function () {
            // Listeners
            scrollbarElement.on('scroll', checkIfShouldStick);
            windowElement.on('resize', $scope.$apply.bind($scope, onResize));

            memorizeDimensions(); // remember sticky's layout dimensions

           // Clean up
            $scope.$on('$destroy', onDestroy);
          };

          /**
           * need to recall sticky's DOM attributes ( make sure layout has occured)
           */
          function memorizeDimensions() {

            // option to calculate the dimensions when layout is "ready"
            if (isStickyLayoutDeferred) {

              // logic: when this directive link() runs before the content has had a chance to layout on browser, height could be 0
              if (!$elem[0].getBoundingClientRect().height) {

                onStickyContentLayoutHeightWatchUnbind = $scope.$watch(
                    function() {
                      return $elem.height();
                    },

                    // state change: sticky content's height set
                    function onStickyContentLayoutInitialHeightSet(newValue, oldValue) {
                      if (newValue > 0) {
                        // now can memorize
                        calculateStickyContentInitialDimensions ();

                        if (!isStickyLayoutWatched) {
                          // preference was to do just a one-time async watch on the sticky's content; now stop watching
                          onStickyContentLayoutHeightWatchUnbind ();
                        }

                      }

                    }
                );
              }
            }
            // default to immediate assignment as normal
            else {
              calculateStickyContentInitialDimensions ();
            }

          }

          /**
           * set the dimensions for the defaults of the content block occupied by the sticky element
           */
          function calculateStickyContentInitialDimensions() {

            initialCSS = {
              zIndex: $elem.css('z-index'),
              top: $elem.css('top'),
              position: $elem.css('position'),
              marginTop: $elem.css('margin-top'),
              marginBottom: $elem.css('margin-bottom'),
              cssLeft: $elem.css('left'),
              height: $elem.css('height')
            };

          }

          /**
           * Determine if the element should be sticking or not.
           */
          var checkIfShouldStick = function () {

            // Check media query and disabled attribute
            if (($scope.disabled === true || mediaQueryMatches()) && isSticking) {
              return unStickElement();
            }

            // What's the document client top for?
            var scrollbarPosition = scrollbarYPos() - (document.documentElement.clientTop || 0);
            var shouldStick;

            if (anchor === 'top') {
              if (confine === true) {
                shouldStick = scrollbarPosition > stickyLine && scrollbarPosition <= stickyBottomLine;
              } else {
                shouldStick = scrollbarPosition > stickyLine;
              }
            } else {
              shouldStick = scrollbarPosition <= stickyLine;
            }

            // Switch the sticky mode if the element crosses the sticky line
            // $attrs.stickLimit - when it's equal to true it enables the user
            // to turn off the sticky function when the elem height is
            // bigger then the viewport
            var closestLine = getClosest(scrollbarPosition, stickyLine, stickyBottomLine);
            if (shouldStick && !shouldStickWithLimit($attrs.stickLimit) && !isSticking) {
              stickElement(closestLine);
            } else if (!shouldStick && isSticking) {
              unStickElement(closestLine, scrollbarPosition);
            } else if (confine && !shouldStick && closestLine === 'bottom' && $elem.css('position') !== 'absolute') {
              // If we are confined to the parent, refresh, and past the stickyBottomLine
              // We should "remember" the original offset and unstick the element which places it at the stickyBottomLine
              originalOffset = elementsOffsetFromTop($elem[0]);

              unStickElement(closestLine, scrollbarPosition);
            }
          };

          /**
           * determine the respective node that handles scrolling, defaulting to browser window
           */
          function deriveScrollingViewport(stickyNode) {
            // derive relevant scrolling by ascending the DOM tree
            var match = stickyNode.closest("sticky-scroll");
            return (match.length === 1) ? match.get(0) : $window;
          }

          /**
           * Seems to be undocumented functionality
           */
          function shouldStickWithLimit(shouldApplyWithLimit) {
            if (shouldApplyWithLimit === 'true') {
              return ($window.innerHeight - ($elem[0].offsetHeight + parseInt(offset)) < 0);
            } else {
              return false;
            }
          }

          /**
           * Finds the closest value from a set of numbers in an array.
           */
          function getClosest(scrollTop, stickyLine, stickyBottomLine) {
            var closest = 'top';
            var topDistance = Math.abs(scrollTop - stickyLine);
            var bottomDistance = Math.abs(scrollTop - stickyBottomLine);

            if (topDistance > bottomDistance) {
              closest = 'bottom';
            }

            return closest;
          }

          /**
           * Unsticks the element
           */
          function unStickElement(fromDirection) {
            $elem.attr('style', initialStyle);
            isSticking = false;

            $body.removeClass(bodyClass);
            $elem.removeClass(stickyClass);
            $elem.removeClass(stickyClass);
            $elem.addClass(unstickyClass);

            if (fromDirection === 'top') {
              $elem
                .css('z-index', 10)
                .css('width', $elem[0].offsetWidth)
                .css('top', initialCSS.top)
                .css('position', initialCSS.position)
                .css('left', initialCSS.cssLeft)
                .css('margin-top', initialCSS.marginTop)
                .css('height', initialCSS.height);
            } else if (fromDirection === 'bottom' && confine === true) {
              $elem
                .css('z-index', 10)
                .css('width', $elem[0].offsetWidth)
                .css('top', '')
                .css('bottom', 0)
                .css('position', 'absolute')
                .css('left', initialCSS.cssLeft)
                .css('margin-top', initialCSS.marginTop)
                .css('margin-bottom', initialCSS.marginBottom)
                .css('height', initialCSS.height);
            }

            if (placeholder && fromDirection === anchor) {
              placeholder.remove();
            }
          }

          /**
           * Sticks the element
           */
          function stickElement(closestLine) {
            // Set sticky state
            isSticking = true;

            initialCSS.offsetWidth = $elem[0].offsetWidth;

            $body.addClass(bodyClass);
            $elem.removeClass(unstickyClass);
            $elem.addClass(stickyClass);

            if (usePlaceholder && closestLine === anchor) {
              placeholder = angular.element('<div>');
              placeholder.css('height', $elem[0].offsetHeight + 'px');
              $elem.after(placeholder);
            }

            $elem
              .css('z-index', '10')
              .css('width', $elem[0].offsetWidth + 'px')
              .css('position', 'fixed')
              .css('left', $elem.css('left').replace('px', '') + 'px')
              .css(anchor, (offset + elementsOffsetFromTop(scrollbar)) + 'px')
              .css('margin-top', 0);

            if (anchor === 'bottom') {
              $elem.css('margin-bottom', 0);
            }
          }

          /**
           * Clean up directive
           */
          var onDestroy = function () {
            scrollbarElement.off('scroll', checkIfShouldStick);
            windowElement.off('resize', onResize);

            $body.removeClass(bodyClass);

            if (placeholder) {
              placeholder.remove();
            }
          };

          /**
           * Updates on resize.
           */
          var onResize = function () {
            unStickElement(anchor);
            checkIfShouldStick();
          };

          /**
           * Triggered on load / digest cycle
           */
          var onDigest = function () {
            if ($scope.disabled === true){
              return unStickElement();
            }

            if (anchor === 'top') {
              return (originalOffset || elementsOffsetFromTop($elem[0])) - elementsOffsetFromTop(scrollbar) + scrollbarYPos();
            } else {
              return elementsOffsetFromTop($elem[0]) - scrollbarHeight() + $elem[0].offsetHeight + scrollbarYPos();
            }
          };

          /**
           * Triggered on change
           */
          var onChange = function (newVal, oldVal) {
            if (( newVal !== oldVal || typeof stickyLine === 'undefined' ) && !isSticking) {
              stickyLine = newVal - offset;

              // IF the sticky is confined, we want to make sure the parent is relatively positioned,
              // otherwise it won't bottom out properly

              if (confine) {
                $elem.parent().css({
                  'position': 'relative'
                });
              }

              // Get Parent height, so we know when to bottom out for confined stickies
              var parent = $elem.parent()[0];
              // Offset parent height by the elements height, if we're not using a placeholder
              var parentHeight = parseInt(parent.offsetHeight) - (usePlaceholder ? 0 : $elem[0].offsetHeight);

              // and now lets ensure we adhere to the bottom margins
              // TODO: make this an attribute? Maybe like ignore-margin?
              var marginBottom = parseInt($elem.css('margin-bottom').replace(/px;?/, '')) || 0;

              // specify the bottom out line for the sticky to unstick
              var elementsDistanceFromTop = elementsOffsetFromTop($elem[0]);
              var parentsDistanceFromTop = elementsOffsetFromTop(parent)
              var scrollbarDistanceFromTop = elementsOffsetFromTop(scrollbar);

              var elementsDistanceFromScrollbarStart = elementsDistanceFromTop - scrollbarDistanceFromTop;
              var elementsDistanceFromBottom = parentsDistanceFromTop + parentHeight - elementsDistanceFromTop;

              stickyBottomLine = elementsDistanceFromScrollbarStart + elementsDistanceFromBottom - $elem[0].offsetHeight - marginBottom - offset +  + scrollbarYPos();

              checkIfShouldStick();
            }
          };

          /**
           * Helper Functions
           */

          /**
           * Fetch top offset of element
           */
          function elementsOffsetFromTop(element) {
            var offset = 0;

            if (element.getBoundingClientRect) {
              offset = element.getBoundingClientRect().top;
            }

            return offset;
          }

          /**
           * Retrieves top scroll distance
           */
          function scrollbarYPos() {
            var position;

            if (typeof scrollbar.scrollTop !== 'undefined') {
              position = scrollbar.scrollTop;
            } else if (typeof scrollbar.pageYOffset !== 'undefined') {
              position = scrollbar.pageYOffset;
            } else {
              position = document.documentElement.scrollTop;
            }

            return position;
          }

          /**
           * Determine scrollbar's height
           */
          function scrollbarHeight() {
            var height;

            if (scrollbarElement[0] instanceof HTMLElement) {
              // isn't bounding client rect cleaner than insane regex mess?
              height = $window.getComputedStyle(scrollbarElement[0], null)
                          .getPropertyValue('height')
                          .replace(/px;?/, '');
            } else {
              height = $window.innerHeight;
            }

            return parseInt(height) || 0;
          }

          /**
           * Checks if the media matches
           */
          function mediaQueryMatches() {
            var mediaQuery = $attrs.mediaQuery || false;
            var matchMedia = $window.matchMedia;

            return mediaQuery && !(matchMedia('(' + mediaQuery + ')').matches || matchMedia(mediaQuery).matches);
          }

          // Setup watcher on digest and change
          $scope.$watch(onDigest, onChange);

          // Init the directive
          initSticky();
        }
      };
    }]
  );

  // Shiv: matchMedia
  //
  window.matchMedia = window.matchMedia || (function () {
      var warning = 'angular-sticky: This browser does not support ' +
        'matchMedia, therefore the minWidth option will not work on ' +
        'this browser. Polyfill matchMedia to fix this issue.';

      if (window.console && console.warn) {
        console.warn(warning);
      }

      return function () {
        return {
          matches: true
        };
      };
    }());
}());
<commit_msg>exposed another public method stickResetLayout<commit_after>(function () {
  'use strict';

  var module = angular.module('sticky', []);

  // Directive: sticky
  //
  module.directive('sticky', ['$window', function ($window) {
      return {
        restrict: 'A', // this directive can only be used as an attribute.
        scope: {
          disabled: '=disabledSticky'
        },
        link: function linkFn($scope, $elem, $attrs) {
          // Setting scope
          var stickyLine;
          var stickyBottomLine;
          var placeholder;
          var isSticking = false;
          var originalOffset;

          // Optional Classes
          var stickyClass = $attrs.stickyClass || '';
          var unstickyClass = $attrs.unstickyClass || '';
          var bodyClass = $attrs.bodyClass || '';

          // Find scrollbar
          var scrollbar = deriveScrollingViewport ($elem);

          // Define elements
          var windowElement = angular.element($window);
          var scrollbarElement = angular.element(scrollbar);
          var $body = angular.element(document.body);

          // Define options
          var usePlaceholder = ($attrs.usePlaceholder !== 'false');
          var anchor = $attrs.anchor === 'bottom' ? 'bottom' : 'top';
          var confine = ($attrs.confine === 'true');
          // flag: can react to recalculating the initial CSS dimensions later as link executes prematurely. defaults to immediate checking
          var isStickyLayoutDeferred = $attrs.isStickyLayoutDeferred !== undefined ? ($attrs.isStickyLayoutDeferred === 'true') : false;

          // flag: is sticky content constantly observed for changes. Should be true if content uses ngBind to show text that may vary in size over time
          var isStickyLayoutWatched = $attrs.isStickyLayoutWatched !== undefined ? ($attrs.isStickyLayoutWatched === 'true') : true;

          var offset = $attrs.offset ? parseInt ($attrs.offset.replace(/px;?/, '')) : 0;
          var onStickyContentLayoutHeightWatchUnbind;

          // initial style
          var initialStyle = $elem.attr('style') || '';
          var initialCSS;

          /**
           * Initialize Sticky
           */
          var initSticky = function() {
            // Listeners
            scrollbarElement.on('scroll', checkIfShouldStick);
            windowElement.on('resize', $scope.$apply.bind($scope, onResize));

            memorizeDimensions (); // remember sticky's layout dimensions

            // Clean up
            $scope.$on('$destroy', onDestroy);
          };

          /**
           * need to recall sticky's DOM attributes ( make sure layout has occured)
           */
          function memorizeDimensions() {
            // immediate assignment, but there is the potential for wrong values if content not ready
            calculateStickyContentInitialDimensions ();

            // option to calculate the dimensions when layout is "ready"
            if (isStickyLayoutDeferred) {

              // logic: when this directive link() runs before the content has had a chance to layout on browser, height could be 0
              if (!$elem[0].getBoundingClientRect().height) {

                onStickyContentLayoutHeightWatchUnbind = $scope.$watch(
                    function() {
                      return $elem.height();
                    },

                    // state change: sticky content's height set
                    function onStickyContentLayoutInitialHeightSet(newValue, oldValue) {
                      if (newValue > 0) {
                        // now can memorize
                        calculateStickyContentInitialDimensions ();

                        if (!isStickyLayoutWatched) {
                          // preference was to do just a one-time async watch on the sticky's content; now stop watching
                          onStickyContentLayoutHeightWatchUnbind ();
                        }

                      }

                    }
                );
              }

              // any processing for when sticky layout is immediate
            } else {

            }

          }

          /**
           * set the dimensions for the defaults of the content block occupied by the sticky element
           */
          function calculateStickyContentInitialDimensions() {

            initialCSS = {
              zIndex: $elem.css('z-index'),
              top: $elem.css('top'),
              position: $elem.css('position'),
              marginTop: $elem.css('margin-top'),
              marginBottom: $elem.css('margin-bottom'),
              cssLeft: $elem.css('left'),
              height: $elem.css('height')
            };

          }

          /**
           * only change content box dimensions
           */
          function calculateStickyContentUpdateDimensions() {
            initialCSS.width = $elem.css('width');
            initialCSS.height = $elem.css('height');
          }

          /**
           * Determine if the element should be sticking or not.
           */
          var checkIfShouldStick = function() {

            // Check media query and disabled attribute
            if (($scope.disabled === true || mediaQueryMatches ()) && isSticking) {
              return unStickElement ();
            }

            // What's the document client top for?
            var scrollbarPosition = scrollbarYPos () - (document.documentElement.clientTop || 0);
            var shouldStick;

            if (anchor === 'top') {
              if (confine === true) {
                shouldStick = scrollbarPosition > stickyLine && scrollbarPosition <= stickyBottomLine;
              } else {
                shouldStick = scrollbarPosition > stickyLine;
              }
            } else {
              shouldStick = scrollbarPosition <= stickyLine;
            }

            // Switch the sticky mode if the element crosses the sticky line
            // $attrs.stickLimit - when it's equal to true it enables the user
            // to turn off the sticky function when the elem height is
            // bigger then the viewport
            var closestLine = getClosest (scrollbarPosition, stickyLine, stickyBottomLine);
            if (shouldStick && !shouldStickWithLimit ($attrs.stickLimit) && !isSticking) {
              stickElement (closestLine);
            } else if (!shouldStick && isSticking) {
              unStickElement (closestLine, scrollbarPosition);
            } else if (confine && !shouldStick && closestLine === 'bottom' && $elem.css('position') !== 'absolute') {
              // If we are confined to the parent, refresh, and past the stickyBottomLine
              // We should "remember" the original offset and unstick the element which places it at the stickyBottomLine
              originalOffset = elementsOffsetFromTop ($elem[0]);

              unStickElement (closestLine, scrollbarPosition);
            }
          };

          /**
           * determine the respective node that handles scrolling, defaulting to browser window
           */
          function deriveScrollingViewport(stickyNode) {
            // derive relevant scrolling by ascending the DOM tree
            var match = stickyNode.closest("sticky-scroll");
            return (match.length === 1) ? match.get(0) : $window;
          }

          /**
           * Seems to be undocumented functionality
           */
          function shouldStickWithLimit(shouldApplyWithLimit) {
            if (shouldApplyWithLimit === 'true') {
              return ($window.innerHeight - ($elem[0].offsetHeight + parseInt (offset)) < 0);
            } else {
              return false;
            }
          }

          /**
           * Finds the closest value from a set of numbers in an array.
           */
          function getClosest(scrollTop, stickyLine, stickyBottomLine) {
            var closest = 'top';
            var topDistance = Math.abs(scrollTop - stickyLine);
            var bottomDistance = Math.abs(scrollTop - stickyBottomLine);

            if (topDistance > bottomDistance) {
              closest = 'bottom';
            }

            return closest;
          }

          /**
           * Unsticks the element
           */
          function unStickElement(fromDirection) {
            $elem.attr('style', initialStyle);
            isSticking = false;

            $body.removeClass(bodyClass);
            $elem.removeClass(stickyClass);
            $elem.removeClass(stickyClass);
            $elem.addClass(unstickyClass);

            if (fromDirection === 'top') {
              $elem
                  .css('z-index', 10)
                  .css('width', $elem[0].offsetWidth)
                  .css('top', initialCSS.top)
                  .css('position', initialCSS.position)
                  .css('left', initialCSS.cssLeft)
                  .css('margin-top', initialCSS.marginTop)
                  .css('height', initialCSS.height);
            } else if (fromDirection === 'bottom' && confine === true) {
              $elem
                  .css('z-index', 10)
                  .css('width', $elem[0].offsetWidth)
                  .css('top', '')
                  .css('bottom', 0)
                  .css('position', 'absolute')
                  .css('left', initialCSS.cssLeft)
                  .css('margin-top', initialCSS.marginTop)
                  .css('margin-bottom', initialCSS.marginBottom)
                  .css('height', initialCSS.height);
            }

            if (placeholder && fromDirection === anchor) {
              placeholder.remove();
            }
          }

          /**
           * Sticks the element
           */
          function stickElement(closestLine) {
            // Set sticky state
            isSticking = true;

            initialCSS.offsetWidth = $elem[0].offsetWidth;

            $body.addClass(bodyClass);
            $elem.removeClass(unstickyClass);
            $elem.addClass(stickyClass);

            if (usePlaceholder && closestLine === anchor) {
              placeholder = angular.element('<div>');
              placeholder.css('height', $elem[0].offsetHeight + 'px');
              $elem.after(placeholder);
            }

            $elem
                .css('z-index', '10')
                .css('width', $elem[0].offsetWidth + 'px')
                .css('position', 'fixed')
                .css('left', $elem.css('left').replace('px', '') + 'px')
                .css(anchor, (offset + elementsOffsetFromTop (scrollbar)) + 'px')
                .css('margin-top', 0);

            if (anchor === 'bottom') {
              $elem.css('margin-bottom', 0);
            }
          }

          /**
           * Clean up directive
           */
          var onDestroy = function() {
            scrollbarElement.off('scroll', checkIfShouldStick);
            windowElement.off('resize', onResize);

            $body.removeClass(bodyClass);

            if (placeholder) {
              placeholder.remove();
            }
          };

          /**
           * Updates on resize.
           */
          var onResize = function() {
            unStickElement (anchor);
            checkIfShouldStick ();
          };

          /**
           * Triggered on load / digest cycle
           */
          var onDigest = function() {
            if ($scope.disabled === true) {
              return unStickElement ();
            }

            if (anchor === 'top') {
              return (originalOffset || elementsOffsetFromTop ($elem[0])) - elementsOffsetFromTop (scrollbar) + scrollbarYPos ();
            } else {
              return elementsOffsetFromTop ($elem[0]) - scrollbarHeight () + $elem[0].offsetHeight + scrollbarYPos ();
            }
          };

          /**
           * Triggered on change
           */
          var onChange = function(newVal, oldVal) {
            if (( newVal !== oldVal || typeof stickyLine === 'undefined' ) && !isSticking) {
              stickyLine = newVal - offset;

              // IF the sticky is confined, we want to make sure the parent is relatively positioned,
              // otherwise it won't bottom out properly

              if (confine) {
                $elem.parent().css({
                  'position': 'relative'
                });
              }

              // Get Parent height, so we know when to bottom out for confined stickies
              var parent = $elem.parent()[0];
              // Offset parent height by the elements height, if we're not using a placeholder
              var parentHeight = parseInt (parent.offsetHeight) - (usePlaceholder ? 0 : $elem[0].offsetHeight);

              // and now lets ensure we adhere to the bottom margins
              // TODO: make this an attribute? Maybe like ignore-margin?
              var marginBottom = parseInt ($elem.css('margin-bottom').replace(/px;?/, '')) || 0;

              // specify the bottom out line for the sticky to unstick
              var elementsDistanceFromTop = elementsOffsetFromTop ($elem[0]);
              var parentsDistanceFromTop = elementsOffsetFromTop (parent)
              var scrollbarDistanceFromTop = elementsOffsetFromTop (scrollbar);

              var elementsDistanceFromScrollbarStart = elementsDistanceFromTop - scrollbarDistanceFromTop;
              var elementsDistanceFromBottom = parentsDistanceFromTop + parentHeight - elementsDistanceFromTop;

              stickyBottomLine = elementsDistanceFromScrollbarStart + elementsDistanceFromBottom - $elem[0].offsetHeight - marginBottom - offset + +scrollbarYPos ();

              checkIfShouldStick ();
            }
          };

          /**
           * Helper Functions
           */

          /**
           * Fetch top offset of element
           */
          function elementsOffsetFromTop(element) {
            var offset = 0;

            if (element.getBoundingClientRect) {
              offset = element.getBoundingClientRect().top;
            }

            return offset;
          }

          /**
           * Retrieves top scroll distance
           */
          function scrollbarYPos() {
            var position;

            if (typeof scrollbar.scrollTop !== 'undefined') {
              position = scrollbar.scrollTop;
            } else if (typeof scrollbar.pageYOffset !== 'undefined') {
              position = scrollbar.pageYOffset;
            } else {
              position = document.documentElement.scrollTop;
            }

            return position;
          }

          /**
           * Determine scrollbar's height
           */
          function scrollbarHeight() {
            var height;

            if (scrollbarElement[0] instanceof HTMLElement) {
              // isn't bounding client rect cleaner than insane regex mess?
              height = $window.getComputedStyle(scrollbarElement[0], null)
                  .getPropertyValue('height')
                  .replace(/px;?/, '');
            } else {
              height = $window.innerHeight;
            }

            return parseInt (height) || 0;
          }

          /**
           * Checks if the media matches
           */
          function mediaQueryMatches() {
            var mediaQuery = $attrs.mediaQuery || false;
            var matchMedia = $window.matchMedia;

            return mediaQuery && !(matchMedia ('(' + mediaQuery + ')').matches || matchMedia (mediaQuery).matches);
          }

          // Setup watcher on digest and change
          $scope.$watch(onDigest, onChange);

          // Init the directive
          initSticky ();

          /**
           * +++++++++ public methods ( via parent ) +++++++++++++
           */

          /**
           * manually trigger a recalculation of the directive's private state of initial dimensions
           * Used when there are external factors that affect layout of the children DOM nodes of this element
           * Method exported into presumed parent scope, since this very directive uses isolate mode
           * long name chosen as to not collide with shared scope
           * Is this a common practice in Angular when battling isolate directives?
           */
            $scope.$parent.stickyUpdateModel = function() {
              calculateStickyContentUpdateDimensions();
            };

          /**
           * integration method allows for an outside client to reset the pinned state back to unpinned.
           * Useful for when refreshing the scrollable DIV content completely
           */

          /**
           * integration method allows for an outside client to reset the pinned state back to unpinned.
           * Useful for when refreshing the scrollable DIV content completely
           */
          $scope.$parent.stickyResetLayout = function() {

            function _resetScrollPosition() {

              // reset means content is scrolled to anchor position
              if (anchor === "top") {
                // window based scroller
                if (scrollbar === $window) {
                  $window.scrollTo(0, 0);
                  // DIV based sticky scroller
                } else {
                  if (scrollbar.scrollTop > 0) {
                    scrollbar.scrollTop = 0;
                  }
                }
              }
            }

            // only if pinned, force unpinning, otherwise height is inadvertently reset to 0
            if (isSticking) {
              unStickElement (anchor);
            }
            // remove hardcoded height
            $elem.css({"width": "", "height": "", "position": "", "top": ""});

            calculateStickyContentUpdateDimensions ();
            _resetScrollPosition ();
          };

        }
      };
    }]
  );

  // Shiv: matchMedia
  //
  window.matchMedia = window.matchMedia || (function () {
      var warning = 'angular-sticky: This browser does not support ' +
        'matchMedia, therefore the minWidth option will not work on ' +
        'this browser. Polyfill matchMedia to fix this issue.';

      if (window.console && console.warn) {
        console.warn(warning);
      }

      return function () {
        return {
          matches: true
        };
      };
    }());
}());
<|endoftext|>


<commit_before>'use strict'

let BasicDocument = require('./basic.js');

class Workstation extends BasicDocument {
  static description() {
    return {
      "key": "{counter}",
      "counter": "workstation-counter"
    };
  }
}

module.exports = Workstation;<commit_msg>attach service to ws<commit_after>'use strict'

let BasicDocument = require('./basic.js');

class Workstation extends BasicDocument {
  static description() {
    return {
      "key": "{counter}",
      "counter": "workstation-counter"
    };
  }
  attachService(services) {
    let provides = this.get('provides');

    this.set('provides', _.concat(services, provides))

    return this;
  }

}

module.exports = Workstation;
<|endoftext|>


<commit_before>/**
 * tbwdjs -- TestingBotWebDriverJS
 * @author tom@goochesa.de (Tom Regner)
 *
 * based on the example code formerly provided by the testingbot.com
 * website (end-replacement).
 */

'use strict';

var webdriverjs = require('webdriverjs');
var http = require('http');
var qs = require('querystring');
var assert = require('assert');

/**
 * create a testingbot webdriver client
 */
exports.remote = function(options) {
  var client = webdriverjs.remote(options);

  // replace the end function, so that the
  // testingbot session will be deleted
  var webjsEnd = client.end;
  client._errors = [];
  client.end = function(fn) {
    webjsEnd(function() {
      var name = options.name || 'unnamed';
      if (fn) { fn(); }
      var postData = qs.stringify({
        client_key: client.desiredCapabilities.api_key,
        client_secret: client.desiredCapabilities.api_secret,
        session_id: client.sessionId,
        success: client._errors.length === 0,
        name: name,
        kind: 10
      });

      var post_options = {
        host: 'testingbot.com',
        port: '80',
        path: '/hq',
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': postData.length
        }
      };

      // Set up the request
      var post_req = http.request(post_options, function(res) {
                       res.setEncoding('utf8');
                     });

      // post the data
      post_req.write(postData);
      post_req.end();
    });
  };

  /* additional protocol commands */
  client.addCommand('windowHandle', function(callback) {
    var commandOptions = {
      path: '/session/:sessionId/window_handle',
      method: 'GET'
    };

    var data = {};

    this.executeProtocolCommand(
        commandOptions,
        this.proxyResponse(callback),
        data
    );
  });

  /* commands that push to client._error */
  client.addCommand('titleEquals', function(expected, callback) {
    var self = this;
    self.direct.title(function(title) {
      try {
        assert.equal(title.value, expected);
      } catch (e) {
        self._errors.push(e);
      }
      self.showTest(title.value === expected,
                    title.value, expected,
                    'Title is "' + expected + '"'
      );
      if (typeof callback === 'function') {
        callback(title.value === expected);
      }
    });
  });
  client.addCommand('cssVisible', function(cssSelector, visible, callback) {
    var self = this;
    self.isVisible(cssSelector,
                   function(result) {
                     try {
                       assert.equal(result, visible);
                     } catch (e) {
                       self._errors.push(e);
                     }
                     self.showTest(result === visible, result, visible,
                                   cssSelector +
                                   (visible ? ' ' : ' not ') +
                                   'visible');
                     if (typeof callback === 'function') {
                       callback(result);
                     }
                   }
    );
  });
  client.addCommand('evaluate', function(fun, expected, message, callback) {
    var self = this;
    self.direct.execute(fun, function(result) {
      try {
        assert(result.value, expected);
      } catch (e) {
        self._errors.push(e);
      }
      self.showTest(result.value === expected, result.value, expected, message);
      if (typeof callback === 'function') {
        callback(result);
      }
    });
  });
  client.addCommand('waitForVar',
                    function(varname, expected, timeout, equality, callback) {
                      var self = this;
                      var startTime = new Date().getTime();
                      function checkValue(val) {
                        return equality ? val === expected : val !== expected;
                      }
                      function checkVariable() {
                        var now = new Date().getTime();
                        self.direct.execute('return ' +
                                            varname + ';', function(result) {
                          if (result.status == 0 && checkValue(result.value)) {
                            if (typeof callback === 'function') {
                              callback(true);
                            }
                          } else {
                            if (now - startTime < timeout) {
                              console.log('sleeping ' + result.value);
                              setTimeout(checkVariable, 500);
                            } else if (typeof callback === 'function') {
                              callback(false);
                            }
                          }
                        });
                      }
                      checkVariable();
                    }
                   );

  return client;
};
<commit_msg>waitForVar() calls callback with value.<commit_after>/**
 * tbwdjs -- TestingBotWebDriverJS
 * @author tom@goochesa.de (Tom Regner)
 *
 * based on the example code formerly provided by the testingbot.com
 * website (end-replacement).
 */

'use strict';

var webdriverjs = require('webdriverjs');
var http = require('http');
var qs = require('querystring');
var assert = require('assert');

/**
 * create a testingbot webdriver client
 */
exports.remote = function(options) {
  var client = webdriverjs.remote(options);

  // replace the end function, so that the
  // testingbot session will be deleted
  var webjsEnd = client.end;
  client._errors = [];
  client.end = function(fn) {
    webjsEnd(function() {
      var name = options.name || 'unnamed';
      if (fn) { fn(); }
      var postData = qs.stringify({
        client_key: client.desiredCapabilities.api_key,
        client_secret: client.desiredCapabilities.api_secret,
        session_id: client.sessionId,
        success: client._errors.length === 0,
        name: name,
        kind: 10
      });

      var post_options = {
        host: 'testingbot.com',
        port: '80',
        path: '/hq',
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': postData.length
        }
      };

      // Set up the request
      var post_req = http.request(post_options, function(res) {
                       res.setEncoding('utf8');
                     });

      // post the data
      post_req.write(postData);
      post_req.end();
    });
  };

  /* additional protocol commands */
  client.addCommand('windowHandle', function(callback) {
    var commandOptions = {
      path: '/session/:sessionId/window_handle',
      method: 'GET'
    };

    var data = {};

    this.executeProtocolCommand(
        commandOptions,
        this.proxyResponse(callback),
        data
    );
  });

  /* commands that push to client._error */
  client.addCommand('titleEquals', function(expected, callback) {
    var self = this;
    self.direct.title(function(title) {
      try {
        assert.equal(title.value, expected);
      } catch (e) {
        self._errors.push(e);
      }
      self.showTest(title.value === expected,
                    title.value, expected,
                    'Title is "' + expected + '"'
      );
      if (typeof callback === 'function') {
        callback(title.value === expected);
      }
    });
  });
  client.addCommand('cssVisible', function(cssSelector, visible, callback) {
    var self = this;
    self.isVisible(cssSelector,
                   function(result) {
                     try {
                       assert.equal(result, visible);
                     } catch (e) {
                       self._errors.push(e);
                     }
                     self.showTest(result === visible, result, visible,
                                   cssSelector +
                                   (visible ? ' ' : ' not ') +
                                   'visible');
                     if (typeof callback === 'function') {
                       callback(result);
                     }
                   }
    );
  });
  client.addCommand('evaluate', function(fun, expected, message, callback) {
    var self = this;
    self.direct.execute(fun, function(result) {
      try {
        assert(result.value, expected);
      } catch (e) {
        self._errors.push(e);
      }
      self.showTest(result.value === expected, result.value, expected, message);
      if (typeof callback === 'function') {
        callback(result);
      }
    });
  });
  client.addCommand('waitForVar',
                    function(varname, expected, timeout, equality, callback) {
                      var self = this;
                      var startTime = new Date().getTime();
                      function checkValue(val) {
                        return equality ? val === expected : val !== expected;
                      }
                      function checkVariable() {
                        var now = new Date().getTime();
                        self.direct.execute('return ' +
                                            varname + ';', function(result) {
                          if (result.status == 0 && checkValue(result.value)) {
                            if (typeof callback === 'function') {
                              callback(result.value);
                            }
                          } else {
                            if (now - startTime < timeout) {
                              console.log('sleeping ' + result.value);
                              setTimeout(checkVariable, 500);
                            } else if (typeof callback === 'function') {
                              callback(result.value);
                            }
                          }
                        });
                      }
                      checkVariable();
                    }
                   );

  return client;
};
<|endoftext|>


<commit_before>import {Promise} from 'bluebird'
import http from 'http'
import https from 'https'
import path from 'path'

import {
  config,
  cmsData
} from '../../'

export function requestList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    cmsData.sql.executeQuery(tplPath, match, jsonPage)
      .then((data) => {
        if (!jsonPage['abe_source']) {
          jsonPage['abe_source'] = {}
        }
        jsonPage['abe_source'][obj.key] = data
        if (!obj.editable) {
          if (obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, obj['max-length'])
          } else {
            jsonPage[obj.key] = data
          }
        } else if (jsonPage[obj.key] == null && obj.prefill) {
          if (obj['prefill-quantity'] && obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, (obj['prefill-quantity'] > obj['max-length']) ? obj['max-length'] : obj['prefill-quantity'])
          } else if (obj['prefill-quantity']) {
            jsonPage[obj.key] = data.slice(0, obj['prefill-quantity'])
          } else if (obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, obj['max-length'])
          } else {
            jsonPage[obj.key] = data
          }
        }

        resolve(jsonPage)
      })
  })

  return p
}

export function valueList(obj, match, jsonPage) {
  var p = new Promise((resolve) => {
    var value = cmsData.sql.getDataSource(match)

    if(value.indexOf('{') > -1 || value.indexOf('[') > -1) {
      try{
        value = JSON.parse(value)

        jsonPage['abe_source'][obj.key] = value
      }catch(e){
        jsonPage['abe_source'][obj.key] = null
        console.log(`Error ${value}/is not a valid JSON`, `\n${e}`)
      }
    }
    resolve()
  })

  return p
}

export function urlList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    if(obj.autocomplete !== true && obj.autocomplete !== 'true') {
      var host = obj.sourceString
      host = host.split('/')
      var httpUse = http
      var defaultPort = 80
      if(host[0] === 'https:') {
        httpUse = https
        defaultPort = 443
      }
      host = host[2].split(':')

      var pathSource = obj.sourceString.split('//')
      if(pathSource[1] != null) {
        pathSource = pathSource[1].split('/')
        pathSource.shift()
        pathSource = '/' + pathSource.join('/')
      }else {
        pathSource = '/'
      }
      var options = {
        hostname: host[0],
        port: (host[1] != null) ? host[1] : defaultPort,
        path: pathSource,
        method: 'GET',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': 0
        }
      }

      var body = ''

      var localReq = httpUse.request(options, (localRes) => {
        localRes.setEncoding('utf8')
        localRes.on('data', (chunk) => {
          body += chunk
        })
        localRes.on('end', () => {
          try {
            if(typeof body === 'string') {
              var parsedBody = JSON.parse(body)
              if(typeof parsedBody === 'object' && Object.prototype.toString.call(parsedBody) === '[object Array]') {
                jsonPage['abe_source'][obj.key] = parsedBody
              } else if(typeof parsedBody === 'object' && Object.prototype.toString.call(parsedBody) === '[object Object]') {
                jsonPage['abe_source'][obj.key] = [parsedBody]
              }
            } else if(typeof body === 'object' && Object.prototype.toString.call(body) === '[object Array]') {
              jsonPage['abe_source'][obj.key] = body
            } else if(typeof body === 'object' && Object.prototype.toString.call(body) === '[object Object]') {
              jsonPage['abe_source'][obj.key] = body
            }
          } catch(e) {
            console.log(`Error ${obj.sourceString} is not a valid JSON`, `\n${e}`)
          }
          resolve()
        })
      })

      localReq.on('error', (e) => {
        console.log(e)
      })

      // write data to request body
      localReq.write('')
      localReq.end()

    } else {
      jsonPage['abe_source'][obj.key] = obj.sourceString
      resolve()
    }
  })

  return p
}

export function fileList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    jsonPage['abe_source'][obj.key] = cmsData.file.get(path.join(config.root, obj.sourceString))
    resolve()
  })

  return p
}

export function nextDataList(tplPath, jsonPage, match) {
  var p = new Promise((resolve) => {
    if(jsonPage['abe_source'] == null) {
      jsonPage['abe_source'] = {}
    }

    var obj = cmsData.attributes.getAll(match, jsonPage)
    obj = cmsData.attributes.sanitizeSourceAttribute(obj, jsonPage)

    var type = cmsData.sql.getSourceType(obj.sourceString)

    switch (type) {
    case 'request':
      requestList(obj, tplPath, match, jsonPage)
        .then((jsonPage) => {
          resolve(jsonPage)
        }).catch((e) => {
          console.log('[ERROR] source.js requestList', e)
        })
      break
    case 'value':
      valueList(obj, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js valueList', e)
        })
      break
    case 'url':
      urlList(obj, tplPath, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js urlList', e)
        })
      break
    case 'file':
      fileList(obj, tplPath, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js fileList', e)
        })
      break
    default:
      resolve()
      break
    }
  })

  return p
}

export function getDataList(tplPath, text, jsonPage) {
  var p = new Promise((resolve) => {

    var promises = []
    var matches = cmsData.regex.getTagAbeTypeRequest(text)
    Array.prototype.forEach.call(matches, (match) => {
      promises.push(nextDataList(tplPath, jsonPage, match[0]))
    })

    Promise.all(promises)
      .then(() => {
        resolve()
      }).catch(function(e) {
        console.error('source.js getDataList', e)
      })
  }).catch(function(e) {
    console.error('source.js getDataList', e)
  })

  return p
}

export function removeDataList(text) {

  return text.replace(cmsData.regex.dataTypeReg, '')
}

export function removeNonEditableDataList(text) {

  return text.replace(cmsData.regex.nonEditableDataReg, '')
}

export function removeNonEachDataList(text) {
  // removing each blocks potentially containing abe data type
  let pattEach = /(\{\{#each (\r|\t|\n|.)*?\/each\}\})/g
  let textWithNoEach = text.replace(pattEach, '')

  var match
  while (match = cmsData.regex.dataTypeReg.exec(textWithNoEach)) {
    text = text.replace(match[0], '')
  }

  return text
}
<commit_msg>doc: functions<commit_after>import {Promise} from 'bluebird'
import http from 'http'
import https from 'https'
import path from 'path'

import {
  config,
  cmsData
} from '../../'

export function requestList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    cmsData.sql.executeQuery(tplPath, match, jsonPage)
      .then((data) => {
        if (!jsonPage['abe_source']) {
          jsonPage['abe_source'] = {}
        }
        jsonPage['abe_source'][obj.key] = data
        if (!obj.editable) {
          if (obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, obj['max-length'])
          } else {
            jsonPage[obj.key] = data
          }
        } else if (jsonPage[obj.key] == null && obj.prefill) {
          if (obj['prefill-quantity'] && obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, (obj['prefill-quantity'] > obj['max-length']) ? obj['max-length'] : obj['prefill-quantity'])
          } else if (obj['prefill-quantity']) {
            jsonPage[obj.key] = data.slice(0, obj['prefill-quantity'])
          } else if (obj['max-length']) {
            jsonPage[obj.key] = data.slice(0, obj['max-length'])
          } else {
            jsonPage[obj.key] = data
          }
        }

        resolve(jsonPage)
      })
  })

  return p
}

export function valueList(obj, match, jsonPage) {
  var p = new Promise((resolve) => {
    var value = cmsData.sql.getDataSource(match)

    if(value.indexOf('{') > -1 || value.indexOf('[') > -1) {
      try{
        value = JSON.parse(value)

        jsonPage['abe_source'][obj.key] = value
      }catch(e){
        jsonPage['abe_source'][obj.key] = null
        console.log(`Error ${value}/is not a valid JSON`, `\n${e}`)
      }
    }
    resolve()
  })

  return p
}

export function urlList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    if(obj.autocomplete !== true && obj.autocomplete !== 'true') {
      var host = obj.sourceString
      host = host.split('/')
      var httpUse = http
      var defaultPort = 80
      if(host[0] === 'https:') {
        httpUse = https
        defaultPort = 443
      }
      host = host[2].split(':')

      var pathSource = obj.sourceString.split('//')
      if(pathSource[1] != null) {
        pathSource = pathSource[1].split('/')
        pathSource.shift()
        pathSource = '/' + pathSource.join('/')
      }else {
        pathSource = '/'
      }
      var options = {
        hostname: host[0],
        port: (host[1] != null) ? host[1] : defaultPort,
        path: pathSource,
        method: 'GET',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': 0
        }
      }

      var body = ''

      var localReq = httpUse.request(options, (localRes) => {
        localRes.setEncoding('utf8')
        localRes.on('data', (chunk) => {
          body += chunk
        })
        localRes.on('end', () => {
          try {
            if(typeof body === 'string') {
              var parsedBody = JSON.parse(body)
              if(typeof parsedBody === 'object' && Object.prototype.toString.call(parsedBody) === '[object Array]') {
                jsonPage['abe_source'][obj.key] = parsedBody
              } else if(typeof parsedBody === 'object' && Object.prototype.toString.call(parsedBody) === '[object Object]') {
                jsonPage['abe_source'][obj.key] = [parsedBody]
              }
            } else if(typeof body === 'object' && Object.prototype.toString.call(body) === '[object Array]') {
              jsonPage['abe_source'][obj.key] = body
            } else if(typeof body === 'object' && Object.prototype.toString.call(body) === '[object Object]') {
              jsonPage['abe_source'][obj.key] = body
            }
          } catch(e) {
            console.log(`Error ${obj.sourceString} is not a valid JSON`, `\n${e}`)
          }
          resolve()
        })
      })

      localReq.on('error', (e) => {
        console.log(e)
      })

      // write data to request body
      localReq.write('')
      localReq.end()

    } else {
      jsonPage['abe_source'][obj.key] = obj.sourceString
      resolve()
    }
  })

  return p
}

export function fileList(obj, tplPath, match, jsonPage) {
  var p = new Promise((resolve) => {
    jsonPage['abe_source'][obj.key] = cmsData.file.get(path.join(config.root, obj.sourceString))
    resolve()
  })

  return p
}

export function nextDataList(tplPath, jsonPage, match) {
  var p = new Promise((resolve) => {
    if(jsonPage['abe_source'] == null) {
      jsonPage['abe_source'] = {}
    }

    var obj = cmsData.attributes.getAll(match, jsonPage)
    obj = cmsData.attributes.sanitizeSourceAttribute(obj, jsonPage)

    var type = cmsData.sql.getSourceType(obj.sourceString)

    switch (type) {
    case 'request':
      requestList(obj, tplPath, match, jsonPage)
        .then((jsonPage) => {
          resolve(jsonPage)
        }).catch((e) => {
          console.log('[ERROR] source.js requestList', e)
        })
      break
    case 'value':
      valueList(obj, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js valueList', e)
        })
      break
    case 'url':
      urlList(obj, tplPath, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js urlList', e)
        })
      break
    case 'file':
      fileList(obj, tplPath, match, jsonPage)
        .then(() => {
          resolve()
        }).catch((e) => {
          console.log('[ERROR] source.js fileList', e)
        })
      break
    default:
      resolve()
      break
    }
  })

  return p
}

export function getDataList(tplPath, text, jsonPage) {
  var p = new Promise((resolve) => {

    var promises = []
    var matches = cmsData.regex.getTagAbeTypeRequest(text)
    Array.prototype.forEach.call(matches, (match) => {
      promises.push(nextDataList(tplPath, jsonPage, match[0]))
    })

    Promise.all(promises)
      .then(() => {
        resolve()
      }).catch(function(e) {
        console.error('source.js getDataList', e)
      })
  }).catch(function(e) {
    console.error('source.js getDataList', e)
  })

  return p
}

export function removeDataList(text) {

  return text.replace(cmsData.regex.dataTypeReg, '')
}

export function removeNonEditableDataList(text) {

  return text.replace(cmsData.regex.nonEditableDataReg, '')
}

/**
 * Remove all type='data' outside {{#each}} statements
 * @param  {[type]} text [description]
 * @return {[type]}      [description]
 */
export function removeNonEachDataList(text) {
  // removing each blocks potentially containing abe data type
  let pattEach = /(\{\{#each (\r|\t|\n|.)*?\/each\}\})/g
  let textWithNoEach = text.replace(pattEach, '')

  var match
  while (match = cmsData.regex.dataTypeReg.exec(textWithNoEach)) {
    text = text.replace(match[0], '')
  }

  return text
}
<|endoftext|>


<commit_before>// Learn more about configuring this file at <https://github.com/theintern/intern/wiki/Configuring-Intern>.
// These default settings work OK for most people. The options that *must* be changed below are the
// packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites.
define({
	// The port on which the instrumenting proxy will listen
	proxyPort: 9000,

	// A fully qualified URL to the Intern proxy
	proxyUrl: 'http://localhost:9000/',

	// Default desired capabilities for all environments. Individual capabilities can be overridden by any of the
	// specified browser environments in the `environments` array below as well. See
	// https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and
	// https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities.
	// Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment
	// automatically
	capabilities: {
		'selenium-version': '2.42.0',
		'idle-timeout': 30
	},

	// Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce
	// OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other
	// capabilities options specified for an environment will be copied as-is
	environments: [
		{ browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' },
		{ browserName: 'internet explorer', version: '10', platform: 'Windows 8' },
		{ browserName: 'internet explorer', version: '9', platform: 'Windows 7' },
		{ browserName: 'internet explorer', version: '8', platform: 'Windows XP' },
		{ browserName: 'firefox', version: '31', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] },
		{ browserName: 'chrome', version: '34', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] },
		{ browserName: 'safari', version: '7', platform: 'OS X 10.9' }
	],

	// Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service
	maxConcurrency: 3,

	// Name of the tunnel class to use for WebDriver tests
	tunnel: 'SauceLabsTunnel',

	// Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader
	// can be used here
	loader: {
		baseUrl: typeof process === 'undefined' ?
				// if we are using the full path to rql, we assume we are running
				// in a sibling path configuration
				location.search.indexOf('config=rql') > -1 ? '../..' : '..' :
			'./node_modules',
		// Packages that should be registered with the loader in each testing environment
		packages: [
			{ name: 'rql', location: typeof process === 'undefined' &&
					location.search.indexOf('config=rql') > -1 ? 'rql' : '..'}
		]
	},

	// Non-functional test suite(s) to run in each browser
	suites: [ 'rql/test/all' ],

	// A regular expression matching URLs to files that should not be included in code coverage analysis
	excludeInstrumentation: /^(?:test|node_modules)\//
});
<commit_msg>Leave path config alone unless it is a known sibling configuration<commit_after>// Learn more about configuring this file at <https://github.com/theintern/intern/wiki/Configuring-Intern>.
// These default settings work OK for most people. The options that *must* be changed below are the
// packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites.
define({
	// The port on which the instrumenting proxy will listen
	proxyPort: 9000,

	// A fully qualified URL to the Intern proxy
	proxyUrl: 'http://localhost:9000/',

	// Default desired capabilities for all environments. Individual capabilities can be overridden by any of the
	// specified browser environments in the `environments` array below as well. See
	// https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and
	// https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities.
	// Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment
	// automatically
	capabilities: {
		'selenium-version': '2.42.0',
		'idle-timeout': 30
	},

	// Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce
	// OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other
	// capabilities options specified for an environment will be copied as-is
	environments: [
		{ browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' },
		{ browserName: 'internet explorer', version: '10', platform: 'Windows 8' },
		{ browserName: 'internet explorer', version: '9', platform: 'Windows 7' },
		{ browserName: 'internet explorer', version: '8', platform: 'Windows XP' },
		{ browserName: 'firefox', version: '31', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] },
		{ browserName: 'chrome', version: '34', platform: [ 'OS X 10.9', 'Windows 7', 'Linux' ] },
		{ browserName: 'safari', version: '7', platform: 'OS X 10.9' }
	],

	// Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service
	maxConcurrency: 3,

	// Name of the tunnel class to use for WebDriver tests
	tunnel: 'SauceLabsTunnel',

	// Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader
	// can be used here
	loader: (typeof process === 'undefined' && location.search.indexOf('config=rql') > -1) ?
		{
			// if we are using the full path to rql, we assume we are running
			// in a sibling path configuration
			baseUrl: '../..'
		} : {},

	// Non-functional test suite(s) to run in each browser
	suites: [ (typeof process === 'undefined' && location.search.indexOf('config=rql') > -1) ?
		'rql/test/all' : 'test/all' ],

	// A regular expression matching URLs to files that should not be included in code coverage analysis
	excludeInstrumentation: /^(?:test|node_modules)\//
});
<|endoftext|>


<commit_before>/*global IOC:true, describe:true, it:true, expect:true, jasmine:true, spyOn:true */
describe("IOC.DI", function () {
  IOC.Extra = function () {

  };

  it("should be able to add and retrieve instances from the context", function () {
    var di = IOC.DI();
    var instance = (function () {
      return {'a': 'b'};
    })();
    di.di.addInstance('instanceName', instance, false);
    expect(di.di.getInstance('instanceName')).toBe(instance);
  });

  it("should be able to retrieve factory instances from the context", function () {
    var di = IOC.DI();
    var factory = function () {
      return {a: 'b'};
    };
    di.di.addInstance('instanceName', factory, true);
    expect(di.di.getInstance('instanceName')).toEqual(factory());
  });

  it("should be able to retrieve factory instances with arguments from the context", function () {
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{value: '1'}]);
    expect(di.di.getInstance('instanceName')).toEqual(factory('1'));
  });

  it("should be able to retrieve differnt instances from factory instances on each retrieve", function () {
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{
      exec: function () {
        return window.performance.now();
      }
    }]);
    expect(di.di.getInstance('instanceName')).not.toEqual(di.di.getInstance('instanceName'));
  });

  it("should return undefined for unknown instances", function () {
    var di = IOC.DI();
    expect(di.di.getInstance('instanceName')).toBe(undefined);
  });

  it("should throw exception if arguments can\'t be resolved", function () {
    var di = IOC.DI({
      di: {
        getInstance: function () {
          return null;
        }
      }
    });
    di.di.addInstance('instanceName', function (c) {
      return {a: c};
    }, true, [{ref: 'impossible'}]);
    expect(function () {
      di.di.getInstance('instanceName');
    }).toThrow('Unable to resolve arguments for "instanceName"');
  });

  it("should resolve value arguments", function () {

  });

  it("should resolve exec arguments", function () {
    var calls = 0;
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{
      exec: function () {
        calls++;
        return window.performance.now();
      }
    }]);
    di.di.getInstance('instanceName');
    expect(calls).toBe(1);
  });

  it("should resolve func arguments", function () {
    var func = function () {
    };
    var di = IOC.DI({
      di: {
        getInstance: function () {
          return {};
        }
      }
    });
    di.di.addInstance('instanceName', function (c) {
      return {a: c};
    }, true, [{func: func}]);
    expect(di.di.getInstance('instanceName').a).toBe(func);
  });

  it('can use empty config', function () {
    IOC({});
  });

  it('should not expose ioc if option isn\'t true', function () {
    IOC({
      exposeIoc: false
    });
    expect(window.ioc).toBe(undefined);
  });

  it('should expose ioc if option is true', function () {
    IOC({
      exposeIoc: true
    });
    expect(window.ioc).not.toBe(undefined);
  });

  it('should merge config with imports', function () {
    spyOn(IOC, 'Extra').and.callFake(function () {
      return {
        context: {
          instances: {}
        }
      };
    });
    IOC({
      exposeIoc: true,
      imports: [
        {
          url: 'url',
          namespace: 'IOC.Extra'
        }
      ]
    });

    expect(window.ioc.config).toEqual({
      exposeIoc: true, imports: [{url: 'url', namespace: 'IOC.Extra'}], mode: 'default', context: {instances: {}}
    });
  });

  it('should fetch and merge config with imports if not already present', function () {
    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: function (url, cb) {
            IOC.Extra2 = function () {
              return {
                context: {
                  instances: {}
                }
              };
            };
            cb();
          }
        }
      };
    });

    IOC({
      exposeIoc: true,
      imports: [
        {
          url: 'url',
          namespace: 'IOC.Extra2'
        }
      ]
    });

    expect(window.ioc.config).toEqual({
      exposeIoc: true, imports: [{url: 'url', namespace: 'IOC.Extra2'}], mode: 'default', context: {instances: {}}
    });
  });

  it('should fetch dependencies', function () {
    var loadingSpy = jasmine.createSpy('load').and.callFake(function (url, cb) {
      cb();
    });

    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: loadingSpy
        }
      };
    });

    IOC({
      exposeIoc: true,
      context: {
        dependencies: {
          default: {
            sync: [
              '1'
            ],
            async: [
              '2'
            ]
          }
        }
      }
    });

    expect(loadingSpy.calls.count()).toEqual(2);
    expect(loadingSpy).toHaveBeenCalledWith('1', jasmine.any(Function));
    expect(loadingSpy).toHaveBeenCalledWith('2', jasmine.any(Function));
  });

  it('should fetch no dependencies if mode is unknown', function () {
    var loadingSpy = jasmine.createSpy('load').and.callFake(function (url, cb) {
      cb();
    });

    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: loadingSpy
        }
      };
    });

    IOC({
      exposeIoc: true,
      context: {
        dependencies: {
          mmm: {
            sync: [
              '1'
            ],
            async: [
              '2'
            ]
          }
        }
      }
    });

    expect(loadingSpy.calls.count()).toEqual(0);
  });

  it('should wire instances', function () {
    spyOn(IOC, 'Extra');
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Extra'
          }
        }
      }
    });

    expect(IOC.Extra).toHaveBeenCalled();
  });

  //it('should extend ioc if instance is configured to do so', function () {
  //  IOC.Extra = function () {
  //    return {yay: 'yay'};
  //  };
  //  IOC({
  //    exposeIoc: true,
  //    context: {
  //      instances: {
  //        extension: true,
  //        one: {
  //          namespace: 'IOC.Extra'
  //        }
  //      }
  //    }
  //  });
  //
  //  expect(window.ioc.yay).toEqual('yay');
  //});

  it('should wire dependencies on other instances', function () {
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Object',
            args: [{ref: 'two'}]
          },
          two: {
            namespace: 'IOC.Object'
          }
        }
      }
    });
  });

  it('should throw error on circular references', function () {
    expect(function () {
      IOC({
        exposeIoc: true,
        context: {
          instances: {
            one: {
              namespace: 'IOC.Object',
              args: [{ref: 'two'}]
            },
            two: {
              namespace: 'IOC.Object',
              args: [{ref: 'one'}]
            }
          }
        }
      });
    }).toThrow('Make sure you don\'t have circular dependencies, Unable to resolve the following instances: one, two');
  });

  it('should throw error on wire unknown instances', function () {
    expect(function () {
      IOC({
        exposeIoc: true,
        context: {
          instances: {
            one: {
              namespace: 'IOC.Extra3'
            }
          }
        }
      });
    }).toThrow('Unknown function "IOC.Extra3"');
  });

});<commit_msg>Added more tests<commit_after>/*global IOC:true, describe:true, it:true, expect:true, jasmine:true, spyOn:true */
describe("IOC.DI", function () {
  IOC.Extra = function () {

  };

  it("should be able to add and retrieve instances from the context", function () {
    var di = IOC.DI();
    var instance = (function () {
      return {'a': 'b'};
    })();
    di.di.addInstance('instanceName', instance, false);
    expect(di.di.getInstance('instanceName')).toBe(instance);
  });

  it("should be able to retrieve factory instances from the context", function () {
    var di = IOC.DI();
    var factory = function () {
      return {a: 'b'};
    };
    di.di.addInstance('instanceName', factory, true);
    expect(di.di.getInstance('instanceName')).toEqual(factory());
  });

  it("should be able to retrieve factory instances with arguments from the context", function () {
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{value: '1'}]);
    expect(di.di.getInstance('instanceName')).toEqual(factory('1'));
  });

  it("should be able to retrieve differnt instances from factory instances on each retrieve", function () {
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{
      exec: function () {
        return window.performance.now();
      }
    }]);
    expect(di.di.getInstance('instanceName')).not.toEqual(di.di.getInstance('instanceName'));
  });

  it("should return undefined for unknown instances", function () {
    var di = IOC.DI();
    expect(di.di.getInstance('instanceName')).toBe(undefined);
  });

  it("should throw exception if arguments can\'t be resolved", function () {
    var di = IOC.DI({
      di: {
        getInstance: function () {
          return null;
        }
      }
    });
    di.di.addInstance('instanceName', function (c) {
      return {a: c};
    }, true, [{ref: 'impossible'}]);
    expect(function () {
      di.di.getInstance('instanceName');
    }).toThrow('Unable to resolve arguments for "instanceName"');
  });

  it("should resolve value arguments", function () {

  });

  it("should resolve exec arguments", function () {
    var calls = 0;
    var di = IOC.DI();
    var factory = function (c) {
      return {a: c};
    };
    di.di.addInstance('instanceName', factory, true, [{
      exec: function () {
        calls++;
        return window.performance.now();
      }
    }]);
    di.di.getInstance('instanceName');
    expect(calls).toBe(1);
  });

  it("should resolve func arguments", function () {
    var func = function () {
    };
    var di = IOC.DI({
      di: {
        getInstance: function () {
          return {};
        }
      }
    });
    di.di.addInstance('instanceName', function (c) {
      return {a: c};
    }, true, [{func: func}]);
    expect(di.di.getInstance('instanceName').a).toBe(func);
  });

  it('can use empty config', function () {
    IOC({});
  });

  it('should not expose ioc if option isn\'t true', function () {
    IOC({
      exposeIoc: false
    });
    expect(window.ioc).toBe(undefined);
  });

  it('should expose ioc if option is true', function () {
    IOC({
      exposeIoc: true
    });
    expect(window.ioc).not.toBe(undefined);
  });

  it('should merge config with imports', function () {
    spyOn(IOC, 'Extra').and.callFake(function () {
      return {
        context: {
          instances: {}
        }
      };
    });
    IOC({
      exposeIoc: true,
      imports: [
        {
          url: 'url',
          namespace: 'IOC.Extra'
        }
      ]
    });

    expect(window.ioc.config).toEqual({
      exposeIoc: true, imports: [{url: 'url', namespace: 'IOC.Extra'}], mode: 'default', context: {instances: {}}
    });
  });

  it('should fetch and merge config with imports if not already present', function () {
    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: function (url, cb) {
            IOC.Extra2 = function () {
              return {
                context: {
                  instances: {}
                }
              };
            };
            cb();
          }
        }
      };
    });

    IOC({
      exposeIoc: true,
      imports: [
        {
          url: 'url',
          namespace: 'IOC.Extra2'
        }
      ]
    });

    expect(window.ioc.config).toEqual({
      exposeIoc: true, imports: [{url: 'url', namespace: 'IOC.Extra2'}], mode: 'default', context: {instances: {}}
    });
  });

  it('should fetch dependencies', function () {
    var loadingSpy = jasmine.createSpy('load').and.callFake(function (url, cb) {
      cb();
    });

    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: loadingSpy
        }
      };
    });

    IOC({
      exposeIoc: true,
      context: {
        dependencies: {
          default: {
            sync: [
              '1'
            ],
            async: [
              '2'
            ]
          }
        }
      }
    });

    expect(loadingSpy.calls.count()).toEqual(2);
    expect(loadingSpy).toHaveBeenCalledWith('1', jasmine.any(Function));
    expect(loadingSpy).toHaveBeenCalledWith('2', jasmine.any(Function));
  });

  it('should fetch no dependencies if mode is unknown', function () {
    var loadingSpy = jasmine.createSpy('load').and.callFake(function (url, cb) {
      cb();
    });

    spyOn(IOC, 'Loader').and.callFake(function () {
      return {
        loader: {
          loadScript: loadingSpy
        }
      };
    });

    IOC({
      exposeIoc: true,
      context: {
        dependencies: {
          mmm: {
            sync: [
              '1'
            ],
            async: [
              '2'
            ]
          }
        }
      }
    });

    expect(loadingSpy.calls.count()).toEqual(0);
  });

  it('should wire instances', function () {
    spyOn(IOC, 'Extra');
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Extra'
          }
        }
      }
    });

    expect(IOC.Extra).toHaveBeenCalled();
  });

  it('should extend ioc if instance is configured to do so', function () {
    window.IOC.Extra = function () {
      return {yay: 'yay'};
    };
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            extension: true,
            namespace: 'IOC.Extra'
          }
        }
      }
    });

    expect(window.ioc.yay).toEqual('yay');
  });

  it('should wire dependencies on other instances', function () {
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Object',
            args: [{ref: 'two'}]
          },
          two: {
            namespace: 'IOC.Object'
          }
        }
      }
    });
  });

  it('should throw error on circular references', function () {
    expect(function () {
      IOC({
        exposeIoc: true,
        context: {
          instances: {
            one: {
              namespace: 'IOC.Object',
              args: [{ref: 'two'}]
            },
            two: {
              namespace: 'IOC.Object',
              args: [{ref: 'one'}]
            }
          }
        }
      });
    }).toThrow('Make sure you don\'t have circular dependencies, Unable to resolve the following instances: one, two');
  });

  it('should throw error on wire unknown instances', function () {
    expect(function () {
      IOC({
        exposeIoc: true,
        context: {
          instances: {
            one: {
              namespace: 'IOC.Extra3'
            }
          }
        }
      });
    }).toThrow('Unknown function "IOC.Extra3"');
  });

  it('should execute inits', function () {
    var funcSpy = jasmine.createSpy('init');
    spyOn(IOC, 'Extra').and.returnValue({
      init: funcSpy
    });
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Extra',
            init: {
              func: 'init'
            }
          }
        }
      }
    });
    expect(funcSpy).toHaveBeenCalled();
  });

  it('should execute starts', function () {
    var funcSpy = jasmine.createSpy('start');
    spyOn(IOC, 'Extra').and.returnValue({
      start: funcSpy
    });
    IOC({
      exposeIoc: true,
      context: {
        instances: {
          one: {
            namespace: 'IOC.Extra'
          }
        },
        start: [
          {
            instance: 'one',
            func: 'start'
          },
          {
            func: funcSpy
          }
        ]
      }
    });
    expect(funcSpy.calls.count()).toBe(2);
  });

});<|endoftext|>


<commit_before>"use babel";

const React = require('react');
const FileName = require('./FileName');
import {Entity, Structure} from './Structure';

const Metadata = require('lupa').Metadata
const getMetadata = Metadata.getMetadata

const getEntitiesByType = require('../getEntitiesByType');

const getLines = (f) => {
    const item = getMetadata(f).filter((item) => item.name == 'lines')[0] || {}
    return item.data || 0
};

function getEntityTypes(files) {
    var types = {};
    files.forEach(f => {
        const metadata = getMetadata(f);
        metadata.forEach(item => types[item.type || item.name] = true);
    });
    return Object.keys(types);
}

class ProjectExplorer extends React.Component {
    constructor() {
        super();
        this.state = {
            section: 'files',
            entityType: '@mixin'
        }
    }
    handleClickSection(e) {
        const newSection = e.target.getAttribute('data-item');
        const newEntityType = e.target.getAttribute('data-entity-name');
        this.setState({
            section: newSection,
            entityType: newEntityType
        });
    }
    render() {

        const entityTypes = getEntityTypes(this.props.files);
        console.log('entityTypes', entityTypes);

        const entities0 = this.props.files.reduce(
             (res, f) => res.concat(getEntitiesByType(f, this.state.entityType))
        , []);

        // TODO remove `entities`
        const entities = entities0.map( (entity) => {
            // TODO change lupa to not assign loc to entity.source
            const loc = entity.loc || (entity.source && entity.source.start? entity.source : null);
            const line = loc && loc.start && (loc.start.line - 1);
            return React.createElement(FileName, {desc: <Entity entity={entity} />, file: entity.file,
                line, preview: this.props.preview, onChange: this.props.onChange})
        })

        const fileElements = this.props.files.sort( (a, b) =>
            getLines(b) - getLines(a)
        )
        .map( (f) => (
            React.createElement(FileName, {file: f, preview: this.props.preview, onChange: this.props.onChange}))
        );

        var section = ({
            files: fileElements,
            entities: <Structure metadata={entities0} onClickEntity={(entity) => {
                    // TODO this is copy pasted
                    // if !fs.existsSync(path)
                    //     path = getFileForRequire(allFiles, path).path
                    const preview = this.props.preview;
                    preview && preview.getBuffer().setPath(entity.file.path)
                    preview && preview.setText(entity.file.contents + '');
                    const line = (entity.loc.start.line || 1) - 1;
                    this.props.onChange && this.props.onChange(line);
                    preview && preview.scrollToBufferPosition([line, 0]);
                    atom.workspace.open(entity.file.path, {initialLine: line});
            }}/>
        })[this.state.section] || 'section ' + this.state.section + ' not found.';

        return

Project Explorer - BETA!

                    <button data-item="files" className='btn'>Files</button>
                    <button data-entity-name="@mixin" data-item="entities" className='btn'>Mixins</button>
                    <button data-entity-name="modules" data-item="entities" className='btn'>Modules</button>
                    {
                        entityTypes.map(
                            type => <button data-entity-name={type} data-item="entities" className='btn'>{type}</button>
                        )
                    }
                    <button data-entity-name='' data-item="entities" className='btn'>Show All</button>
                    <input type="text" value={this.state.entityType} onChange={ e => this.setState({entityType: e.target.value}) }/>

                    { section }

;
    }
}
module.exports = ProjectExplorer;
<commit_msg>improve project explorer<commit_after>"use babel";

const React = require('react');
const FileName = require('./FileName');
import {Entity, Structure} from './Structure';

const Metadata = require('lupa').Metadata
const getMetadata = Metadata.getMetadata

const getEntitiesByType = require('../getEntitiesByType');

const getLines = (f) => {
    const item = getMetadata(f).filter((item) => item.name == 'lines')[0] || {}
    return item.data || 0
};

function getEntityTypes(files) {
    var types = {};
    files.forEach(f => {
        const metadata = getMetadata(f);
        metadata.forEach(item => types[item.type || item.name] = true);
    });
    return Object.keys(types);
}

class ProjectExplorer extends React.Component {
    constructor() {
        super();
        this.state = {
            section: 'entities',
            entityType: '',
            file: '',
            line: 0,
        }
    }
    handleClickSection(e) {
        const newSection = e.target.getAttribute('data-item');
        const newEntityType = e.target.getAttribute('data-entity-name');
        this.setState({
            section: newSection,
            entityType: newEntityType
        });
    }
    render() {

        const entityTypes = getEntityTypes(this.props.files);
        entityTypes.sort();

        const entities0 = this.props.files.reduce(
             (res, f) => res.concat(getEntitiesByType(f, this.state.entityType))
        , []);

        // TODO remove `entities`
        const entities = entities0.map( (entity) => {
            // TODO change lupa to not assign loc to entity.source
            const loc = entity.loc || (entity.source && entity.source.start? entity.source : null);
            const line = loc && loc.start && (loc.start.line - 1);
            return React.createElement(FileName, {desc: <Entity entity={entity} />, file: entity.file,
                line, preview: this.props.preview, onChange: this.props.onChange})
        })

        const fileElements = this.props.files.sort( (a, b) =>
            getLines(b) - getLines(a)
        )
        .map( (f) => (
            React.createElement(FileName, {file: f, preview: this.props.preview, onChange: this.props.onChange}))
        );

        var section = ({
            files: fileElements,
            entities: <Structure metadata={entities0} onClickEntity={(entity) => {
                    // TODO this is copy pasted
                    // if !fs.existsSync(path)
                    //     path = getFileForRequire(allFiles, path).path
                    const preview = this.props.preview;
                    preview && preview.getBuffer().setPath(entity.file.path)
                    preview && preview.setText(entity.file.contents + '');
                    const line = entity.loc? (entity.loc.start.line || 1) - 1 : 0;
                    this.props.onChange && this.props.onChange(line);
                    preview && preview.scrollToBufferPosition([line, 0]);
                    this.setState({file: entity.file, line: line});
            }}/>
        })[this.state.section] || 'section ' + this.state.section + ' not found.';

        return

Project Explorer - BETA!

{this.state.file.path}
                <button
                    className='btn icon icon-file-text'
                    onClick={ () => atom.workspace.open(this.state.file.path, {initialLine: this.state.line})}>
                    Open
                </button>

<button
                        data-item="files"
                        style={{width: '100%'}}
                        className='btn icon icon-file-text'>Files</button>

<button
                        data-entity-name=''
                        data-item="entities"
                        style={{width: '100%'}}
                        className='btn icon icon-light-bulb'>Show All</button>

                    {
                        entityTypes.map(
                            type =>

                                <button
                                    style={{width: '100%'}}
                                    data-entity-name={type}
                                    data-item="entities"
                                    className='btn'>
                                    {type}
                                </button>

                        )
                    }
                    {/*
                        <input type="text" value={this.state.entityType} onChange={ e => this.setState({entityType: e.target.value}) }/>
                        */ }

                    { section }

;
    }
}
module.exports = ProjectExplorer;
<|endoftext|>