<commit_before>import './directives/sol-vibrate';
import './Services';
import 'angular';
export default angular.module('ui.media-panel', ['solVibrate'])
    .directive('mediaPanel', ['playList', function(playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/panel.html',
            replace: true,
            scope: true,
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.setIsCued = function(val) {
                    val = typeof val === 'boolean' ? val : true;
                    $scope.isCued = val;
                };

                $scope.toggleVideo = function() {
                    $element.toggleClass('show-video');
                };
                $scope.$watch(playList.getNowPlaying, function(newVal, oldVal) {
                    if (newVal)
                        $element.addClass('active');
                });

                $scope.$on('youtubePlayer:videoCued', function(e, data) {
                    $scope.isCued = true;
                });

                $scope.$on('youtubePlayer:onStateChange', function(e, data) {
                    if (data.info === YT.PlayerState.PLAYING) {
                        $scope.isCued = false;
                        if (!$scope.$$phase) $scope.$digest();
                    }
                });
            }
        };

        return definitions;
    }])
    .directive('mediaPlayer', ['$sce', 'youtubePlayer', 'playList', function($sce, ytPlayer, playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/youtube.html',
            replace: true,
            scope: true,
            link: function($scope, $element) {
                ytPlayer.setElement($element.attr('id'));
            },
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.nowPlaying = ytPlayer.nowPlaying;
            }
        };

        return definitions;
    }]).directive('playlistRelated', ['$rootScope', 'youtubePlayer', 'youtubeAPI', 'playList', function($rootScope, youtubePlayer, youtubeAPI, playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/related.html',
            replace: true,
            scope: {},
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.addItem = function(videoId) {
                    playList.addLast(videoId);
                };
                $scope.$watch(playList.getNowPlaying, function(item) {
                    if (item) {
                        youtubeAPI.getRelated(item.id).then(function(items) {
                            $scope.items = items;
                        });
                    }
                });
            }
        };
        return definitions;
    }]);
<commit_msg>Use the toast notification for the cued-video mechanism<commit_after>import './directives/sol-vibrate';
import './Services';
import 'angular';
export default angular.module('ui.media-panel', ['solVibrate'])
    .directive('mediaPanel', ['$rootScope', 'playList', function($rootScope, playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/panel.html',
            replace: true,
            scope: true,
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.setIsCued = function(val) {
                    val = typeof val === 'boolean' ? val : true;
                    $scope.isCued = val;
                };

                $scope.toggleVideo = function() {
                    $element.toggleClass('show-video');
                };
                $scope.$watch(playList.getNowPlaying, function(newVal, oldVal) {
                    if (newVal)
                        $element.addClass('active');
                });

                $scope.$on('youtubePlayer:videoCued', function(e, data) {
                    $rootScope.$broadcast('toast::notify', {
                        text: 'The video should be played manually',
                        persist: true
                    });

                    let unregister = $scope.$on('youtubePlayer:onStateChange', function(e, data) {
                        if (data.info === YT.PlayerState.PLAYING) {
                            $rootScope.$broadcast('toast::close');
                            unregister();
                        }
                    });
                });
            }
        };

        return definitions;
    }])
    .directive('mediaPlayer', ['$sce', 'youtubePlayer', 'playList', function($sce, ytPlayer, playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/youtube.html',
            replace: true,
            scope: true,
            link: function($scope, $element) {
                ytPlayer.setElement($element.attr('id'));
            },
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.nowPlaying = ytPlayer.nowPlaying;
            }
        };

        return definitions;
    }]).directive('playlistRelated', ['$rootScope', 'youtubePlayer', 'youtubeAPI', 'playList', function($rootScope, youtubePlayer, youtubeAPI, playList) {
        var definitions = {
            restrict: 'E',
            templateUrl: '/html/media-panel/related.html',
            replace: true,
            scope: {},
            controller: function($scope, $element, $attrs, $transclude) {
                $scope.addItem = function(videoId) {
                    playList.addLast(videoId);
                };
                $scope.$watch(playList.getNowPlaying, function(item) {
                    if (item) {
                        youtubeAPI.getRelated(item.id).then(function(items) {
                            $scope.items = items;
                        });
                    }
                });
            }
        };
        return definitions;
    }]);
<|endoftext|>


<commit_before>import Ember from 'ember';
import WithConfigMixin from 'ember-idx-utils/mixin/with-config';
import Modal from 'ember-idx-modal/modal';
var computed = Ember.computed;
var COMPONENT_NAME = 'view:em-wysiwyg-action-link-modal';

export default Ember.Component.extend(WithConfigMixin, {
  tagName: 'a',
  classNameBindings: ['styleClasses', 'activeClasses'],
  linkHref: '',
  initModal: (function() {
    var container = this.get('container');
    if(!container.lookupFactory(COMPONENT_NAME)) {
      container._registry.register(COMPONENT_NAME, Modal.extend({
        layoutName: 'components/em-wysiwyg-action-link-modal',
        configName: 'bs',
        _parentView: this,
        linkHref: computed.alias('parentView.linkHref'),
        actions: {
          addLink: function() {
            (this.get('parentView') || this.get('_parentView')).send('addLink');
          }
        }
      }));
    }
    this.set('modal', container.lookup(COMPONENT_NAME));
    return this.get('modal').append();
  }).on('init'),
  styleClasses: (function() {
    var _ref;
    return (_ref = this.get('config.wysiwyg.actionClasses')) != null ? _ref.join(" ") : void 0;
  }).property(),
  activeClasses: (function() {
    var _ref;
    if (this.get('active')) {
      return (_ref = this.get('config.wysiwyg.actionActiveClasses')) != null ? _ref.join(" ") : void 0;
    }
  }).property('active'),
  actions: {
    addLink: function() {
      this.get('editor').restoreSelection();
      this.get('editor').$().focus();
      if (this.get('linkHref')) {
        document.execCommand('CreateLink', 0, this.get('linkHref'));
      } else {
        document.execCommand('unlink', 0);
      }
      this.get('editor').saveSelection();
      this.get('wysiwyg').trigger('update_actions');
      return this.get('modal').close();
    }
  },
  click: function() {
    return this.get('modal').open();
  },
  wysiwyg: computed.alias('parentView.wysiwyg'),
  editor: computed.alias('wysiwyg.editor'),
  listenToUpdate: (function() {
    return this.get('wysiwyg').on('update_actions', (function(_this) {
      return function() {
        var container;
        container = _this.get('editor.selectionRange').commonAncestorContainer;
        if (container.nodeType === 3) {
          container = container.parentNode;
        }
        if (container.nodeName === "A") {
          _this.set('linkHref', Ember.$(container).attr('href'));
          return _this.set('active', true);
        } else {
          _this.set('linkHref', '');
          return _this.set('active', false);
        }
      };
    })(this));
  }).on('init')
});
<commit_msg>Update action-link.js<commit_after>import Ember from 'ember';
import WithConfigMixin from 'ember-idx-utils/mixin/with-config';
import Modal from 'ember-idx-modal/modal';
var computed = Ember.computed;
var COMPONENT_NAME = 'view:em-wysiwyg-action-link-modal';

export default Ember.Component.extend(WithConfigMixin, {
  tagName: 'a',
  classNameBindings: ['styleClasses', 'activeClasses'],
  linkHref: '',
  initModal: (function() {
    var container = this.get('container');
    if(!container.lookupFactory(COMPONENT_NAME)) {
      container._registry.register(COMPONENT_NAME, Modal.extend({
        layoutName: 'components/em-wysiwyg-action-link-modal',
        configName: 'bs',
        parentView: this,
        linkHref: computed.alias('parentView.linkHref'),
        actions: {
          addLink: function() {
            this.get('parentView').send('addLink');
          }
        }
      }));
    }
    this.set('modal', container.lookup(COMPONENT_NAME));
    return this.get('modal').append();
  }).on('init'),
  styleClasses: (function() {
    var _ref;
    return (_ref = this.get('config.wysiwyg.actionClasses')) != null ? _ref.join(" ") : void 0;
  }).property(),
  activeClasses: (function() {
    var _ref;
    if (this.get('active')) {
      return (_ref = this.get('config.wysiwyg.actionActiveClasses')) != null ? _ref.join(" ") : void 0;
    }
  }).property('active'),
  actions: {
    addLink: function() {
      this.get('editor').restoreSelection();
      this.get('editor').$().focus();
      if (this.get('linkHref')) {
        document.execCommand('CreateLink', 0, this.get('linkHref'));
      } else {
        document.execCommand('unlink', 0);
      }
      this.get('editor').saveSelection();
      this.get('wysiwyg').trigger('update_actions');
      return this.get('modal').close();
    }
  },
  click: function() {
    return this.get('modal').open();
  },
  wysiwyg: computed.alias('parentView.wysiwyg'),
  editor: computed.alias('wysiwyg.editor'),
  listenToUpdate: (function() {
    return this.get('wysiwyg').on('update_actions', (function(_this) {
      return function() {
        var container;
        container = _this.get('editor.selectionRange').commonAncestorContainer;
        if (container.nodeType === 3) {
          container = container.parentNode;
        }
        if (container.nodeName === "A") {
          _this.set('linkHref', Ember.$(container).attr('href'));
          return _this.set('active', true);
        } else {
          _this.set('linkHref', '');
          return _this.set('active', false);
        }
      };
    })(this));
  }).on('init')
});
<|endoftext|>


<commit_before>(function($) {
  "use strict";
  var namespace = 'animsition';
  var methods = {
    init: function(options){
      options = $.extend({
        inClass               :   'fade-in',
        outClass              :   'fade-out',
        inDuration            :    1500,
        outDuration           :    800,
        linkElement           :   '.animsition-link',
        // e.g. linkElement   :   'a:not([target="_blank"]):not([href^=#])'
        loading               :    true,
        loadingParentElement  :   'body', //animsition wrapper element
        loadingClass          :   'animsition-loading',
        unSupportCss          : [ 'animation-duration',
                                  '-webkit-animation-duration',
                                  '-o-animation-duration'],
        overlay               :   false,
        overlayClass          :   'animsition-overlay-slide',
        overlayParentElement  :   'body'
      }, options);

      // Remove the "Animsition" in a browser
      // that does not support the "animaition-duration".
      var support = methods.supportCheck.call(this, options);
      if(support === false){
        // If do not have a console object to object window
        if (!('console' in window)) {
          window.console = {};
          window.console.log = function(str){return str};
        }
        console.log("Animsition does not support this browser.");
        return methods.destroy.call( this );
      }

      var overlayMode = methods.optionCheck.call(this, options);
      if(overlayMode === true) {
        methods.addOverlay.call(this, options);
      }

      if(options.loading === true) {
        methods.addLoading.call(this, options);
      }

      return this.each(function(){
        var _this = this;
        var $this = $(this);
        var $window = $(window);
        var data = $this.data(namespace);

        if (!data) {
          options = $.extend({}, options);

          $this.data(namespace, {
            options: options
          });

          $window.on("load." + namespace + " pageshow." + namespace, function() {
            methods.pageIn.call( _this );
          });

          // Firefox back button issue #4
          $window.on("unload." + namespace, function() { });

          $(options.linkElement).on("click." + namespace, function(event) {
            event.preventDefault();
            var $self = $(this);
            methods.pageOut.call( _this, $self);
          });
        }
      }); // end each
    },

    addOverlay: function(options){
      $(options.overlayParentElement)
        .prepend('

');
    },

    addLoading: function(options){
      $(options.loadingParentElement)
        .append('

');
    },

    removeLoading: function(){
      var $this     = $(this);
      var options   = $this.data(namespace).options;
      var $loading  = $(options.loadingParentElement).children("."+options.loadingClass);
      $loading.fadeOut().remove();
    },

    supportCheck: function(options){
      var $this = $(this);
      var props = options.unSupportCss;
      var propsNum = props.length;
      var support  = false;

      if (propsNum === 0) {
        support = true;
      }
      for (var i = 0; i < propsNum; i++) {
        if (typeof $this.css(props[i]) === "string") {
          support = true;
          break;
        }
      }
      return support;
    },

    optionCheck: function(options){
      var $this = $(this);
      var overlayMode;
      if(options.overlay || $this.data('animsition-overlay')){
        overlayMode = true
      } else {
        overlayMode = false
      }
      return overlayMode;
    },

    animationCheck : function(data, stateClass, stateIn){
      var $this = $(this);
      var options = $this.data(namespace).options;
      var dataType = typeof data;
      var dataDuration = !stateClass && dataType === "number";
      var dataClass = stateClass && dataType === "string" && data.length > 0;

      if(dataDuration || dataClass){
        data = data;
      } else if(stateClass && stateIn) {
        data = options.inClass;
      } else if(!stateClass && stateIn) {
        data = options.inDuration;
      } else if(stateClass && !stateIn) {
        data = options.outClass;
      } else if(!stateClass && !stateIn) {
        data = options.outDuration;
      }
      return data;
    },

    pageIn: function(){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var thisInDuration = $this.data('animsition-in-duration');
      var thisInClass = $this.data('animsition-in');
      var inDuration = methods.animationCheck.call(_this,thisInDuration,false,true);
      var inClass = methods.animationCheck.call(_this,thisInClass,true,true);
      var overlayMode = methods.optionCheck.call(_this, options);

      if(options.loading) {
        methods.removeLoading.call(_this);
      }

      if(overlayMode) {
        methods.pageInOverlay.call(_this,inClass,inDuration);
      } else {
        methods.pageInBasic.call(_this,inClass,inDuration);
      }
    },

    pageInBasic: function(inClass,inDuration){
      var $this = $(this);

      $this
        .css({ "animation-duration" : (inDuration / 1000) + "s" })
        .addClass(inClass)
        .animateCallback(function(){
          $this
            .removeClass(inClass)
            .css({ "opacity" : 1 });
        });
    },

    pageInOverlay: function(inClass,inDuration){
      var $this = $(this);
      var options = $this.data(namespace).options;

      $this
        .css({ "opacity" : 1 });
      $(options.overlayParentElement).children('.' + options.overlayClass)
        .css({ "animation-duration" : (inDuration / 1000) + "s" })
        .addClass(inClass);
    },

    pageOut: function($self){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var selfOutClass = $self.data('animsition-out');
      var thisOutClass = $this.data('animsition-out');
      var selfOutDuration = $self.data('animsition-out-duration');
      var thisOutDuration = $this.data('animsition-out-duration');
      var isOutClass = selfOutClass ? selfOutClass : thisOutClass;
      var isOutDuration = selfOutDuration ? selfOutDuration : thisOutDuration;
      var outClass = methods.animationCheck.call(_this,isOutClass,true,false);
      var outDuration = methods.animationCheck.call(_this, isOutDuration,false,false);
      var overlayMode = methods.optionCheck.call(_this, options);
      var url = $self.attr('href');

      if(overlayMode) {
        methods.pageOutOverlay.call(_this,outClass,outDuration,url);
      } else {
        methods.pageOutBasic.call(_this,outClass,outDuration,url);
      }
    },

    pageOutBasic: function(outClass,outDuration,url){
      var $this = $(this);

      $this
        .css({ "animation-duration" : (outDuration / 1000) + "s" })
        .addClass(outClass)
        .animateCallback(function(){
          location.href = url
        });
    },

    pageOutOverlay: function(outClass,outDuration,url){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var thisInClass = $this.data('animsition-in');
      var inClass = methods.animationCheck.call(_this,thisInClass,true,true);

      $(options.overlayParentElement).children('.' + options.overlayClass)
        .css({ "animation-duration" : (outDuration / 1000) + "s" })
        .removeClass(inClass)
        .addClass(outClass)
        .animateCallback(function(){
          $this.css({"opacity":0});
          location.href = url
        });
    },

    destroy: function(){
      return this.each(function(){
        var $this = $(this);
        $(window).unbind('.'+namespace);
        $this
          .css({'opacity':1})
          .removeData(namespace);
      });
    }

  };

  $.fn.animateCallback = function(callback){
    var end = "animationend webkitAnimationEnd mozAnimationEnd oAnimationEnd MSAnimationEnd";
    return this.each(function() {
      $(this).bind(end, function(){
        $(this).unbind(end);
        return callback.call(this);
      });
    });
  };

  $.fn.animsition = function(method){
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.'+namespace);
    }
  };

})(jQuery);<commit_msg>Changed if(boolean)<commit_after>(function($) {
  "use strict";
  var namespace = 'animsition';
  var methods = {
    init: function(options){
      options = $.extend({
        inClass               :   'fade-in',
        outClass              :   'fade-out',
        inDuration            :    1500,
        outDuration           :    800,
        linkElement           :   '.animsition-link',
        // e.g. linkElement   :   'a:not([target="_blank"]):not([href^=#])'
        loading               :    true,
        loadingParentElement  :   'body', //animsition wrapper element
        loadingClass          :   'animsition-loading',
        unSupportCss          : [ 'animation-duration',
                                  '-webkit-animation-duration',
                                  '-o-animation-duration'],
        overlay               :   false,
        overlayClass          :   'animsition-overlay-slide',
        overlayParentElement  :   'body'
      }, options);

      // Remove the "Animsition" in a browser
      // that does not support the "animaition-duration".
      var support = methods.supportCheck.call(this, options);
      if(!support){
        // If do not have a console object to object window
        if (!('console' in window)) {
          window.console = {};
          window.console.log = function(str){return str};
        }
        console.log("Animsition does not support this browser.");
        return methods.destroy.call( this );
      }

      var overlayMode = methods.optionCheck.call(this, options);
      if(overlayMode) {
        methods.addOverlay.call(this, options);
      }

      if(options.loading) {
        methods.addLoading.call(this, options);
      }

      return this.each(function(){
        var _this = this;
        var $this = $(this);
        var $window = $(window);
        var data = $this.data(namespace);

        if (!data) {
          options = $.extend({}, options);

          $this.data(namespace, {
            options: options
          });

          $window.on("load." + namespace + " pageshow." + namespace, function() {
            methods.pageIn.call( _this );
          });

          // Firefox back button issue #4
          $window.on("unload." + namespace, function() { });

          $(options.linkElement).on("click." + namespace, function(event) {
            event.preventDefault();
            var $self = $(this);
            methods.pageOut.call( _this, $self);
          });
        }
      }); // end each
    },

    addOverlay: function(options){
      $(options.overlayParentElement)
        .prepend('

');
    },

    addLoading: function(options){
      $(options.loadingParentElement)
        .append('

');
    },

    removeLoading: function(){
      var $this     = $(this);
      var options   = $this.data(namespace).options;
      var $loading  = $(options.loadingParentElement).children("."+options.loadingClass);
      $loading.fadeOut().remove();
    },

    supportCheck: function(options){
      var $this = $(this);
      var props = options.unSupportCss;
      var propsNum = props.length;
      var support  = false;

      if (propsNum === 0) {
        support = true;
      }
      for (var i = 0; i < propsNum; i++) {
        if (typeof $this.css(props[i]) === "string") {
          support = true;
          break;
        }
      }
      return support;
    },

    optionCheck: function(options){
      var $this = $(this);
      var overlayMode;
      if(options.overlay || $this.data('animsition-overlay')){
        overlayMode = true
      } else {
        overlayMode = false
      }
      return overlayMode;
    },

    animationCheck : function(data, stateClass, stateIn){
      var $this = $(this);
      var options = $this.data(namespace).options;
      var dataType = typeof data;
      var dataDuration = !stateClass && dataType === "number";
      var dataClass = stateClass && dataType === "string" && data.length > 0;

      if(dataDuration || dataClass){
        data = data;
      } else if(stateClass && stateIn) {
        data = options.inClass;
      } else if(!stateClass && stateIn) {
        data = options.inDuration;
      } else if(stateClass && !stateIn) {
        data = options.outClass;
      } else if(!stateClass && !stateIn) {
        data = options.outDuration;
      }
      return data;
    },

    pageIn: function(){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var thisInDuration = $this.data('animsition-in-duration');
      var thisInClass = $this.data('animsition-in');
      var inDuration = methods.animationCheck.call(_this,thisInDuration,false,true);
      var inClass = methods.animationCheck.call(_this,thisInClass,true,true);
      var overlayMode = methods.optionCheck.call(_this, options);

      if(options.loading) {
        methods.removeLoading.call(_this);
      }

      if(overlayMode) {
        methods.pageInOverlay.call(_this,inClass,inDuration);
      } else {
        methods.pageInBasic.call(_this,inClass,inDuration);
      }
    },

    pageInBasic: function(inClass,inDuration){
      var $this = $(this);

      $this
        .css({ "animation-duration" : (inDuration / 1000) + "s" })
        .addClass(inClass)
        .animateCallback(function(){
          $this
            .removeClass(inClass)
            .css({ "opacity" : 1 });
        });
    },

    pageInOverlay: function(inClass,inDuration){
      var $this = $(this);
      var options = $this.data(namespace).options;

      $this
        .css({ "opacity" : 1 });
      $(options.overlayParentElement).children('.' + options.overlayClass)
        .css({ "animation-duration" : (inDuration / 1000) + "s" })
        .addClass(inClass);
    },

    pageOut: function($self){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var selfOutClass = $self.data('animsition-out');
      var thisOutClass = $this.data('animsition-out');
      var selfOutDuration = $self.data('animsition-out-duration');
      var thisOutDuration = $this.data('animsition-out-duration');
      var isOutClass = selfOutClass ? selfOutClass : thisOutClass;
      var isOutDuration = selfOutDuration ? selfOutDuration : thisOutDuration;
      var outClass = methods.animationCheck.call(_this,isOutClass,true,false);
      var outDuration = methods.animationCheck.call(_this, isOutDuration,false,false);
      var overlayMode = methods.optionCheck.call(_this, options);
      var url = $self.attr('href');

      if(overlayMode) {
        methods.pageOutOverlay.call(_this,outClass,outDuration,url);
      } else {
        methods.pageOutBasic.call(_this,outClass,outDuration,url);
      }
    },

    pageOutBasic: function(outClass,outDuration,url){
      var $this = $(this);

      $this
        .css({ "animation-duration" : (outDuration / 1000) + "s" })
        .addClass(outClass)
        .animateCallback(function(){
          location.href = url
        });
    },

    pageOutOverlay: function(outClass,outDuration,url){
      var _this = this;
      var $this = $(this);
      var options = $this.data(namespace).options;
      var thisInClass = $this.data('animsition-in');
      var inClass = methods.animationCheck.call(_this,thisInClass,true,true);

      $(options.overlayParentElement).children('.' + options.overlayClass)
        .css({ "animation-duration" : (outDuration / 1000) + "s" })
        .removeClass(inClass)
        .addClass(outClass)
        .animateCallback(function(){
          $this.css({"opacity":0});
          location.href = url
        });
    },

    destroy: function(){
      return this.each(function(){
        var $this = $(this);
        $(window).unbind('.'+namespace);
        $this
          .css({'opacity':1})
          .removeData(namespace);
      });
    }

  };

  $.fn.animateCallback = function(callback){
    var end = "animationend webkitAnimationEnd mozAnimationEnd oAnimationEnd MSAnimationEnd";
    return this.each(function() {
      $(this).bind(end, function(){
        $(this).unbind(end);
        return callback.call(this);
      });
    });
  };

  $.fn.animsition = function(method){
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.'+namespace);
    }
  };

})(jQuery);<|endoftext|>


<commit_before>chrome.browserAction.onClicked.addListener(function(tab) {
	var toCreate = { url: chrome.extension.getURL('/views/main.html') };
	chrome.tabs.query(toCreate, function(tabs) {
		if (tabs.length === 0) {
			chrome.tabs.create(toCreate);
		}
	});
});<commit_msg>[#3] Tab clustering not displayed if already opened Focus on window and tab containing the extension.<commit_after>chrome.browserAction.onClicked.addListener(function(tab) {
	var toCreate = { url: chrome.extension.getURL('/views/main.html') };
	chrome.tabs.query(toCreate, function(tabs) {
		if (tabs.length === 0) {
			chrome.tabs.create(toCreate);
		} else {
			var tab = tabs[0];
			chrome.tabs.update(tab.id, { active: true });
			chrome.windows.update(tab.windowId, { focused: true });
		}
	});
});<|endoftext|>


<commit_before>const _ = require('underscore')
const os = require('os');
const fs = require('fs');
const path = require('path')
const mkdirp = require('mkdirp');
const detectThread = require('./detect-thread');
const extractFiles = require('./extract-files');
const extractContacts = require('./extract-contacts');
const MessageFactory = require('../shared/message-factory')
const LocalDatabaseConnector = require('../shared/local-database-connector');

const MAX_QUEUE_LENGTH = 500
const MAX_CPU_USE_ON_AC = 1.0;
const MAX_CPU_USE_ON_BATTERY = 0.10;
const MAX_CHUNK_SIZE = 1;

class MessageProcessor {

  constructor() {
    // The queue is a chain of Promises
    this._queue = Promise.resolve()
    this._queueLength = 0
    this._currentChunkSize = 0
    this._currentChunkStart = Date.now();
    this._isBatteryCharging = true;
    navigator.getBattery().then((battery) => {
      this._isBatteryCharging = battery.charging;
      battery.addEventListener('chargingchange', () => {
        console.info('charge change', battery.charging);
        this._isBatteryCharging = battery.charging
      });
    });
  }

  queueLength() {
    return this._queueLength
  }

  queueIsFull() {
    return this._queueLength >= MAX_QUEUE_LENGTH
  }

  _maxCPUForProcessing() {
    if (this._isBatteryCharging) {
      return MAX_CPU_USE_ON_AC;
    }
    return MAX_CPU_USE_ON_BATTERY;
  }

  _computeThrottlingTimeout() {
    const timeSliceMs = Date.now() - this._currentChunkStart;
    const maxCPU = this._maxCPUForProcessing();
    return (timeSliceMs * (1.0 / maxCPU)) - timeSliceMs;
  }

  /**
   * @returns Promise that resolves when message has been processed
   * This promise will never reject, given that this function is meant to be
   * called as a fire and forget operation
   * If message processing fails, we will register the failure in the folder
   * syncState
   */
  queueMessageForProcessing({accountId, folderId, imapMessage, struct, desiredParts}) {
    return new Promise((resolve) => {
      this._queueLength++
      this._queue = this._queue.then(async () => {
        if (this._currentChunkSize === 0) {
          this._currentChunkStart = Date.now();
        }
        this._currentChunkSize++;

        await this._processMessage({accountId, folderId, imapMessage, struct, desiredParts})
        this._queueLength--

        // Throttle message processing to meter cpu usage
        if (this._currentChunkSize === MAX_CHUNK_SIZE) {
          const timeout = this._computeThrottlingTimeout();
          await new Promise(r => setTimeout(r, timeout))
          this._currentChunkSize = 0;
        }

        // To save memory, we reset the Promise chain if the queue reaches a
        // length of 0, otherwise we will continue referencing the entire chain
        // of promises that came before
        if (this._queueLength === 0) {
          this._queue = Promise.resolve()
        }
        resolve()
      })
    })
  }

  async _processMessage({accountId, folderId, imapMessage, struct, desiredParts}) {
    const db = await LocalDatabaseConnector.forAccount(accountId);
    const {Message, Folder} = db
    const folder = await Folder.findById(folderId)
    const accountDb = await LocalDatabaseConnector.forShared()
    const account = await accountDb.Account.findById(accountId)
    const logger = global.Logger.forAccount(account)

    try {
      const messageValues = await MessageFactory.parseFromImap(imapMessage, desiredParts, {
        db,
        folder,
        accountId,
      });
      const existingMessage = await Message.findById(messageValues.id);
      let processedMessage;
      if (existingMessage) {
        // TODO: optimize to not do a full message parse for existing messages
        processedMessage = await this._processExistingMessage({
          logger,
          struct,
          messageValues,
          existingMessage,
        })
      } else {
        processedMessage = await this._processNewMessage({
          logger,
          struct,
          messageValues,
        })
      }

      // Inflate the serialized oldestProcessedDate value, if it exists
      let oldestProcessedDate;
      if (folder.syncState && folder.syncState.oldestProcessedDate) {
        oldestProcessedDate = new Date(folder.syncState.oldestProcessedDate);
      }
      const justProcessedDate = messageValues.date ? new Date(messageValues.date) : new Date()

      // Update the oldestProcessedDate if:
      //   a) justProcessedDate is after the year 1980. We don't want to base this
      //      off of messages with borked 1970 dates.
      // AND
      //   b) i) We haven't set oldestProcessedDate yet
      //     OR
      //      ii) justProcessedDate is before oldestProcessedDate and in a different
      //          month. (We only use this to update the sync status in Nylas Mail,
      //          which uses month precision. Updating a folder's syncState triggers
      //          many re-renders in Nylas Mail, so we only do it as necessary.)
      if (justProcessedDate > new Date("1980") && (
            !oldestProcessedDate || (
              (justProcessedDate.getMonth() !== oldestProcessedDate.getMonth() ||
                justProcessedDate.getFullYear() !== oldestProcessedDate.getFullYear()) &&
              justProcessedDate < oldestProcessedDate))) {
        await folder.updateSyncState({oldestProcessedDate: justProcessedDate})
      }

      logger.log(`🔃 ✉ (${folder.name}) "${messageValues.subject}" - ${messageValues.date}`)
      return processedMessage
    } catch (err) {
      logger.error(`MessageProcessor: Could not build message`, {
        err,
        imapMessage,
        desiredParts,
      })
      NylasEnv.reportError(err)

      // Keep track of uids we failed to fetch
      const {failedUIDs = []} = folder.syncState
      const {uid} = imapMessage.attributes
      if (uid) {
        await folder.updateSyncState({failedUIDs: _.uniq(failedUIDs.concat([uid]))})
      }

      // Save parse errors for future debugging
      if (process.env.NYLAS_DEBUG) {
        const outJSON = JSON.stringify({imapMessage, desiredParts, result: {}});
        const outDir = path.join(os.tmpdir(), "k2-parse-errors", folder.name)
        const outFile = path.join(outDir, imapMessage.attributes.uid.toString());
        mkdirp.sync(outDir);
        fs.writeFileSync(outFile, outJSON);
      }
      return null
    }
  }

  // Replaces ["<rfc2822messageid>", ...] with [[object Reference], ...]
  // Creates references that do not yet exist, and adds the correct
  // associations as well
  async _addReferences(db, message, thread, references) {
    const {Reference} = db;

    let existingReferences = [];
    if (references.length > 0) {
      existingReferences = await Reference.findAll({
        where: {
          rfc2822MessageId: references,
        },
      });
    }

    const refByMessageId = {};
    for (const ref of existingReferences) {
      refByMessageId[ref.rfc2822MessageId] = ref;
    }
    for (const mid of references) {
      if (!refByMessageId[mid]) {
        refByMessageId[mid] = await Reference.create({rfc2822MessageId: mid, threadId: thread.id});
      }
    }

    const referencesInstances = references.map(mid => refByMessageId[mid]);
    await message.addReferences(referencesInstances);
    message.referencesOrder = referencesInstances.map(ref => ref.id);
    await thread.addReferences(referencesInstances);
  }

  async _processNewMessage({messageValues, struct, logger = console} = {}) {
    const {accountId} = messageValues;
    const db = await LocalDatabaseConnector.forAccount(accountId);
    const {Message} = db

    const thread = await detectThread({db, messageValues});
    messageValues.threadId = thread.id;
    const createdMessage = await Message.create(messageValues);

    if (messageValues.labels) {
      await createdMessage.addLabels(messageValues.labels)
      // Note that the labels aren't officially associated until save() is called later
    }

    await this._addReferences(db, createdMessage, thread, messageValues.references);

    // TODO: need to delete dangling references somewhere (maybe at the
    // end of the sync loop?)

    const files = await extractFiles({db, messageValues, struct});
    // Don't count inline images (files with contentIds) as attachments
    if (files.some(f => !f.contentId) && !thread.hasAttachments) {
      thread.hasAttachments = true;
      await thread.save();
    }
    await extractContacts({db, messageValues, logger});

    createdMessage.isProcessed = true;
    await createdMessage.save()
    return createdMessage
  }

  /**
   * When we send a message we store an incomplete copy in the local
   * database while we wait for the sync loop to discover the actually
   * delivered one. We store this to keep track of our delivered state and
   * to ensure it's in the sent folder.
   *
   * It'll have the basic ID, but no thread, labels, etc.
   *
   * We also get already processed messages because they may have had their
   * folders or labels changed or had some other property updated with them,
   * or because we interrupted the sync loop before the message was fully
   * processed.
   */
  async _processExistingMessage({existingMessage, messageValues, struct} = {}) {
    const {accountId} = messageValues;
    const db = await LocalDatabaseConnector.forAccount(accountId);
    await existingMessage.update(messageValues);
    if (messageValues.labels && messageValues.labels.length > 0) {
      await existingMessage.setLabels(messageValues.labels)
    }

    let thread = await existingMessage.getThread();
    if (!existingMessage.isProcessed) {
      if (!thread) {
        thread = await detectThread({db, messageValues});
        existingMessage.threadId = thread.id;
      }
      await this._addReferences(db, existingMessage, thread, messageValues.references);
      const files = await extractFiles({db, messageValues: existingMessage, struct});
      // Don't count inline images (files with contentIds) as attachments
      if (files.some(f => !f.contentId) && !thread.hasAttachments) {
        thread.hasAttachments = true;
        await thread.save();
      }
      await extractContacts({db, messageValues: existingMessage});
      existingMessage.isProcessed = true;
    } else {
      if (!thread) {
        throw new Error(`Existing processed message ${existingMessage.id} doesn't have thread`)
      }
    }

    await existingMessage.save();
    await thread.updateLabelsAndFolders();
    return existingMessage
  }
}

module.exports = new MessageProcessor()
<commit_msg>[local-sync] When replying to a thread, properly add it to Sent folder<commit_after>const _ = require('underscore')
const os = require('os');
const fs = require('fs');
const path = require('path')
const mkdirp = require('mkdirp');
const detectThread = require('./detect-thread');
const extractFiles = require('./extract-files');
const extractContacts = require('./extract-contacts');
const MessageFactory = require('../shared/message-factory')
const LocalDatabaseConnector = require('../shared/local-database-connector');

const MAX_QUEUE_LENGTH = 500
const MAX_CPU_USE_ON_AC = 1.0;
const MAX_CPU_USE_ON_BATTERY = 0.10;
const MAX_CHUNK_SIZE = 1;

class MessageProcessor {

  constructor() {
    // The queue is a chain of Promises
    this._queue = Promise.resolve()
    this._queueLength = 0
    this._currentChunkSize = 0
    this._currentChunkStart = Date.now();
    this._isBatteryCharging = true;
    navigator.getBattery().then((battery) => {
      this._isBatteryCharging = battery.charging;
      battery.addEventListener('chargingchange', () => {
        console.info('charge change', battery.charging);
        this._isBatteryCharging = battery.charging
      });
    });
  }

  queueLength() {
    return this._queueLength
  }

  queueIsFull() {
    return this._queueLength >= MAX_QUEUE_LENGTH
  }

  _maxCPUForProcessing() {
    if (this._isBatteryCharging) {
      return MAX_CPU_USE_ON_AC;
    }
    return MAX_CPU_USE_ON_BATTERY;
  }

  _computeThrottlingTimeout() {
    const timeSliceMs = Date.now() - this._currentChunkStart;
    const maxCPU = this._maxCPUForProcessing();
    return (timeSliceMs * (1.0 / maxCPU)) - timeSliceMs;
  }

  /**
   * @returns Promise that resolves when message has been processed
   * This promise will never reject, given that this function is meant to be
   * called as a fire and forget operation
   * If message processing fails, we will register the failure in the folder
   * syncState
   */
  queueMessageForProcessing({accountId, folderId, imapMessage, struct, desiredParts}) {
    return new Promise((resolve) => {
      this._queueLength++
      this._queue = this._queue.then(async () => {
        if (this._currentChunkSize === 0) {
          this._currentChunkStart = Date.now();
        }
        this._currentChunkSize++;

        await this._processMessage({accountId, folderId, imapMessage, struct, desiredParts})
        this._queueLength--

        // Throttle message processing to meter cpu usage
        if (this._currentChunkSize === MAX_CHUNK_SIZE) {
          const timeout = this._computeThrottlingTimeout();
          await new Promise(r => setTimeout(r, timeout))
          this._currentChunkSize = 0;
        }

        // To save memory, we reset the Promise chain if the queue reaches a
        // length of 0, otherwise we will continue referencing the entire chain
        // of promises that came before
        if (this._queueLength === 0) {
          this._queue = Promise.resolve()
        }
        resolve()
      })
    })
  }

  async _processMessage({accountId, folderId, imapMessage, struct, desiredParts}) {
    const db = await LocalDatabaseConnector.forAccount(accountId);
    const {Message, Folder, Label} = db
    const folder = await Folder.findById(folderId)
    const accountDb = await LocalDatabaseConnector.forShared()
    const account = await accountDb.Account.findById(accountId)
    const logger = global.Logger.forAccount(account)

    try {
      const messageValues = await MessageFactory.parseFromImap(imapMessage, desiredParts, {
        db,
        folder,
        accountId,
      });
      const existingMessage = await Message.findById(messageValues.id, {
        include: [{model: Folder, as: 'folder'}, {model: Label, as: 'labels'}],
      });
      let processedMessage;
      if (existingMessage) {
        // TODO: optimize to not do a full message parse for existing messages
        processedMessage = await this._processExistingMessage({
          logger,
          struct,
          messageValues,
          existingMessage,
        })
      } else {
        processedMessage = await this._processNewMessage({
          logger,
          struct,
          messageValues,
        })
      }

      // Inflate the serialized oldestProcessedDate value, if it exists
      let oldestProcessedDate;
      if (folder.syncState && folder.syncState.oldestProcessedDate) {
        oldestProcessedDate = new Date(folder.syncState.oldestProcessedDate);
      }
      const justProcessedDate = messageValues.date ? new Date(messageValues.date) : new Date()

      // Update the oldestProcessedDate if:
      //   a) justProcessedDate is after the year 1980. We don't want to base this
      //      off of messages with borked 1970 dates.
      // AND
      //   b) i) We haven't set oldestProcessedDate yet
      //     OR
      //      ii) justProcessedDate is before oldestProcessedDate and in a different
      //          month. (We only use this to update the sync status in Nylas Mail,
      //          which uses month precision. Updating a folder's syncState triggers
      //          many re-renders in Nylas Mail, so we only do it as necessary.)
      if (justProcessedDate > new Date("1980") && (
            !oldestProcessedDate || (
              (justProcessedDate.getMonth() !== oldestProcessedDate.getMonth() ||
                justProcessedDate.getFullYear() !== oldestProcessedDate.getFullYear()) &&
              justProcessedDate < oldestProcessedDate))) {
        await folder.updateSyncState({oldestProcessedDate: justProcessedDate})
      }

      logger.log(`🔃 ✉ (${folder.name}) "${messageValues.subject}" - ${messageValues.date}`)
      return processedMessage
    } catch (err) {
      logger.error(`MessageProcessor: Could not build message`, {
        err,
        imapMessage,
        desiredParts,
      })
      NylasEnv.reportError(err)

      // Keep track of uids we failed to fetch
      const {failedUIDs = []} = folder.syncState
      const {uid} = imapMessage.attributes
      if (uid) {
        await folder.updateSyncState({failedUIDs: _.uniq(failedUIDs.concat([uid]))})
      }

      // Save parse errors for future debugging
      if (process.env.NYLAS_DEBUG) {
        const outJSON = JSON.stringify({imapMessage, desiredParts, result: {}});
        const outDir = path.join(os.tmpdir(), "k2-parse-errors", folder.name)
        const outFile = path.join(outDir, imapMessage.attributes.uid.toString());
        mkdirp.sync(outDir);
        fs.writeFileSync(outFile, outJSON);
      }
      return null
    }
  }

  // Replaces ["<rfc2822messageid>", ...] with [[object Reference], ...]
  // Creates references that do not yet exist, and adds the correct
  // associations as well
  async _addReferences(db, message, thread, references) {
    const {Reference} = db;

    let existingReferences = [];
    if (references.length > 0) {
      existingReferences = await Reference.findAll({
        where: {
          rfc2822MessageId: references,
        },
      });
    }

    const refByMessageId = {};
    for (const ref of existingReferences) {
      refByMessageId[ref.rfc2822MessageId] = ref;
    }
    for (const mid of references) {
      if (!refByMessageId[mid]) {
        refByMessageId[mid] = await Reference.create({rfc2822MessageId: mid, threadId: thread.id});
      }
    }

    const referencesInstances = references.map(mid => refByMessageId[mid]);
    await message.addReferences(referencesInstances);
    message.referencesOrder = referencesInstances.map(ref => ref.id);
    await thread.addReferences(referencesInstances);
  }

  async _processNewMessage({messageValues, struct, logger = console} = {}) {
    const {accountId} = messageValues;
    const db = await LocalDatabaseConnector.forAccount(accountId);
    const {Message} = db

    const thread = await detectThread({db, messageValues});
    messageValues.threadId = thread.id;
    const createdMessage = await Message.create(messageValues);

    if (messageValues.labels) {
      await createdMessage.addLabels(messageValues.labels)
      // Note that the labels aren't officially associated until save() is called later
    }

    await this._addReferences(db, createdMessage, thread, messageValues.references);

    // TODO: need to delete dangling references somewhere (maybe at the
    // end of the sync loop?)

    const files = await extractFiles({db, messageValues, struct});
    // Don't count inline images (files with contentIds) as attachments
    if (files.some(f => !f.contentId) && !thread.hasAttachments) {
      thread.hasAttachments = true;
      await thread.save();
    }
    await extractContacts({db, messageValues, logger});

    createdMessage.isProcessed = true;
    await createdMessage.save()
    return createdMessage
  }

  /**
   * When we send a message we store an incomplete copy in the local
   * database while we wait for the sync loop to discover the actually
   * delivered one. We store this to keep track of our delivered state and
   * to ensure it's in the sent folder.
   *
   * It'll have the basic ID, but no thread, labels, etc.
   *
   * We also get already processed messages because they may have had their
   * folders or labels changed or had some other property updated with them,
   * or because we interrupted the sync loop before the message was fully
   * processed.
   */
  async _processExistingMessage({existingMessage, messageValues, struct} = {}) {
    const {accountId} = messageValues;
    const db = await LocalDatabaseConnector.forAccount(accountId);
    await existingMessage.update(messageValues);
    if (messageValues.labels && messageValues.labels.length > 0) {
      await existingMessage.setLabels(messageValues.labels)
    }

    let thread = await existingMessage.getThread({
      include: [{model: db.Folder, as: 'folders'}, {model: db.Label, as: 'labels'}],
    });
    if (!existingMessage.isProcessed) {
      if (!thread) {
        thread = await detectThread({db, messageValues});
        existingMessage.threadId = thread.id;
      } else {
        await thread.updateFromMessages({db, messages: [existingMessage]})
      }
      await this._addReferences(db, existingMessage, thread, messageValues.references);
      const files = await extractFiles({db, messageValues: existingMessage, struct});
      // Don't count inline images (files with contentIds) as attachments
      if (files.some(f => !f.contentId) && !thread.hasAttachments) {
        thread.hasAttachments = true;
        await thread.save();
      }
      await extractContacts({db, messageValues: existingMessage});
      existingMessage.isProcessed = true;
    } else {
      if (!thread) {
        throw new Error(`Existing processed message ${existingMessage.id} doesn't have thread`)
      }
    }

    await existingMessage.save();
    await thread.updateLabelsAndFolders();
    return existingMessage
  }
}

module.exports = new MessageProcessor()
<|endoftext|>


<commit_before>import {
  props,
  define,
  hasNativeShadowDomSupport,
  query,
} from '@bolt/core/utils';
import { withLitHtml, html } from '@bolt/core';
import classNames from 'classnames';
import styles from './interactive-pathway.scss';
// import schema from '../interactive-pathway.schema.yml';

let cx = classNames.bind(styles);

@define
class BoltInteractivePathway extends withLitHtml() {
  static is = 'bolt-interactive-pathway';

  static props = {
    noShadow: {
      ...props.boolean,
      ...{ default: false },
    },
  };

  // https://github.com/WebReflection/document-register-element#upgrading-the-constructor-context
  // @ts-ignore
  constructor(self) {
    self = super(self);
    self.useShadow = hasNativeShadowDomSupport;
    // self.schema = schema;
    self.isActivePathway = false;
    self.activeStep = -1;
    self.steps = [];
    self.addEventListener('change-active-step', event => {
      const steps = this.getSteps();
      const stepId = steps.findIndex(step => step.el === event.target);
      this.setActiveStep(stepId);
    });
    return self;
  }

  /**
   * @return {{ el: BoltInteractiveStep, title: string }[]}
   */
  getSteps() {
    const els = /** @type {BoltInteractiveStep[]} */ (query(
      'bolt-interactive-step',
      this,
    ));

    return els.map(el => ({
      el,
      title: el.getTitle(),
    }));
  }

  setActive(isActive = true) {
    this.isActivePathway = isActive;
    this.setActiveStep(0);
    this.triggerUpdate();
  }

  /**
   * @return {string}
   */
  getTitle() {
    /** @type {HTMLElement} */
    const pathwayTitleEl = this.renderRoot.querySelector('.c-bolt-interactive-pathway__nav-item--active');
    return pathwayTitleEl ? pathwayTitleEl.innerText : '';
  }

  connectedCallback() {
    super.connectedCallback();
    // let children render before trying to access
    setTimeout(() => {
      this.steps = this.getSteps();
      this.triggerUpdate();
    }, 0);
  }

  /**
   * Set the active tab panel step
   * @param {number} stepIndex
   * @return {Promise<void>}
   */
  setActiveStep = async stepIndex => {
    if (stepIndex === this.activeStep) {
      // @todo first one initially set twice, causes double animation in
      console.warn('current step already active');
      return;
    }
    const steps = this.getSteps();
    if (!steps) {
      console.error('No steps inside, so cannot setActiveStep', this);
      return;
    }
    const newActiveStep = steps[stepIndex];
    const currentActiveStep = steps[this.activeStep];
    if (!newActiveStep) {
      console.error(
        `uh oh setActiveStep fired with stepIndex "${stepIndex}" but could not find one`,
      );
      return;
    }
    if (currentActiveStep) {
      await currentActiveStep.el.triggerAnimOuts();
      currentActiveStep.el.setActive(false);
    }
    newActiveStep.el.setActive(true);
    this.activeStep = stepIndex;
    await newActiveStep.el.triggerAnimIns();
    this.triggerUpdate();
  };

  render() {
    const classes = cx('c-bolt-interactive-pathway', {
      [`c-bolt-interactive-pathway--disabled`]: !this.isActivePathway,
      [`c-bolt-interactive-pathway--active`]: this.isActivePathway,
    });

    const navClasses = cx('c-bolt-interactive-pathway__nav');
    const itemClasses = cx('c-bolt-interactive-pathway__items');
    // new approach
    return html`
      ${this.addStyles([styles])}

          ${this.steps.map((step, stepIndex) => {
            const isActiveItem = this.activeStep === stepIndex;
            const navItemClasses = cx('c-bolt-interactive-pathway__nav-item', {
              'c-bolt-interactive-pathway__nav-item--active': isActiveItem,
            });
            return html`

 this.setActiveStep(stepIndex)}
              >
                ${step.title}

            `;
          })}

          ${this.slot('default')}

    `;

    // old approach
    const old = html`
      ${this.addStyles([styles])}

          ${this.slot('default')}

    `;
  }
}

export { BoltInteractivePathway };
<commit_msg>style(interactive-pathways): js lint<commit_after>import {
  props,
  define,
  hasNativeShadowDomSupport,
  query,
} from '@bolt/core/utils';
import { withLitHtml, html } from '@bolt/core';
import classNames from 'classnames';
import styles from './interactive-pathway.scss';
// import schema from '../interactive-pathway.schema.yml';

let cx = classNames.bind(styles);

@define
class BoltInteractivePathway extends withLitHtml() {
  static is = 'bolt-interactive-pathway';

  static props = {
    noShadow: {
      ...props.boolean,
      ...{ default: false },
    },
  };

  // https://github.com/WebReflection/document-register-element#upgrading-the-constructor-context
  // @ts-ignore
  constructor(self) {
    self = super(self);
    self.useShadow = hasNativeShadowDomSupport;
    // self.schema = schema;
    self.isActivePathway = false;
    self.activeStep = -1;
    self.steps = [];
    self.addEventListener('change-active-step', event => {
      const steps = this.getSteps();
      const stepId = steps.findIndex(step => step.el === event.target);
      this.setActiveStep(stepId);
    });
    return self;
  }

  /**
   * @return {{ el: BoltInteractiveStep, title: string }[]}
   */
  getSteps() {
    const els = /** @type {BoltInteractiveStep[]} */ (query(
      'bolt-interactive-step',
      this,
    ));

    return els.map(el => ({
      el,
      title: el.getTitle(),
    }));
  }

  setActive(isActive = true) {
    this.isActivePathway = isActive;
    this.setActiveStep(0);
    this.triggerUpdate();
  }

  /**
   * @return {string}
   */
  getTitle() {
    /** @type {HTMLElement} */
    const pathwayTitleEl = this.renderRoot.querySelector(
      '.c-bolt-interactive-pathway__nav-item--active',
    );
    return pathwayTitleEl ? pathwayTitleEl.innerText : '';
  }

  connectedCallback() {
    super.connectedCallback();
    // let children render before trying to access
    setTimeout(() => {
      this.steps = this.getSteps();
      this.triggerUpdate();
    }, 0);
  }

  /**
   * Set the active tab panel step
   * @param {number} stepIndex
   * @return {Promise<void>}
   */
  setActiveStep = async stepIndex => {
    if (stepIndex === this.activeStep) {
      // @todo first one initially set twice, causes double animation in
      console.warn('current step already active');
      return;
    }
    const steps = this.getSteps();
    if (!steps) {
      console.error('No steps inside, so cannot setActiveStep', this);
      return;
    }
    const newActiveStep = steps[stepIndex];
    const currentActiveStep = steps[this.activeStep];
    if (!newActiveStep) {
      console.error(
        `uh oh setActiveStep fired with stepIndex "${stepIndex}" but could not find one`,
      );
      return;
    }
    if (currentActiveStep) {
      await currentActiveStep.el.triggerAnimOuts();
      currentActiveStep.el.setActive(false);
    }
    newActiveStep.el.setActive(true);
    this.activeStep = stepIndex;
    await newActiveStep.el.triggerAnimIns();
    this.triggerUpdate();
  };

  render() {
    const classes = cx('c-bolt-interactive-pathway', {
      [`c-bolt-interactive-pathway--disabled`]: !this.isActivePathway,
      [`c-bolt-interactive-pathway--active`]: this.isActivePathway,
    });

    const navClasses = cx('c-bolt-interactive-pathway__nav');
    const itemClasses = cx('c-bolt-interactive-pathway__items');
    // new approach
    return html`
      ${this.addStyles([styles])}

          ${this.steps.map((step, stepIndex) => {
            const isActiveItem = this.activeStep === stepIndex;
            const navItemClasses = cx('c-bolt-interactive-pathway__nav-item', {
              'c-bolt-interactive-pathway__nav-item--active': isActiveItem,
            });
            return html`

 this.setActiveStep(stepIndex)}
              >
                ${step.title}

            `;
          })}

          ${this.slot('default')}

    `;

    // old approach
    const old = html`
      ${this.addStyles([styles])}

          ${this.slot('default')}

    `;
  }
}

export { BoltInteractivePathway };
<|endoftext|>


<commit_before>var difficulty = 0;

/* variables à récupérer :
 * winState
 * mise
 * tours
 * difficulty (gameSpeed dans tomcruise.js)
 */

// conserver le nombre de tours gagnants d'affilé
var lastWinFail = [];
var cumulWin = [];
var cumulFail = [];
var bondDiff = [0.1, 0.3, 0.7];
var win = "true";
var fail = "false";
var compteurTroisTours = 0; //compteur qui augmente après chaque tour
var toursGagnantsDaffile = 0; //à incrémenter, dés que c'est égal à 3, modifier courbe

function cumulTours() {
    if (winState === true) {
        lastWinFail.push("true");
        compteurTroisTours++;
        clearArray();
    } else if (winState === false) {
        lastWinFail.push("fail");
        compteurTroisTours++;
        clearArray();
    }
}

function clearArray() {
    if (compteurTroisTours === 3) {
        lastWinFail = [];
    }
}

function checkWinFail() {
    var idx = lastWinFail.indexOf(win);
    var i = 0;
    while (idx != -1 && i >= 3) {
        cumulWin.push(idx);
        idx = lastWinFail.indexOf(win, idx + 1);
        i++;
    }
    console.log(cumulWin);
}

var compareArrayWin = function (lastWinFail, cumulWin) {
    if (lastWinFail === cumulWin)
        return true;
    if (lastWinFail.length !== cumulWin.length)
        return false;
    for (var i = 0; i < lastWinFail.length; i++) {
        if (!equal(lastWinFail[i], cumulWin[i])) return false;
    };
    return true;
};

var compareArrayFail = function (lastWinFail, cumulFail) {
    if (lastWinFail === cumulFail)
        return true;
    if (lastWinFail.length !== cumulFail.length)
        return false;
    for (var i = 0; i < lastWinFail.length; i++) {
        if (!equal(lastWinFail[i], cumulFail[i])) return false;
    };
    return true;
};

function changeDifficulty() {
    if (compareArrayWin === true) {
        newDiff = Math.random(bondDiff);
        difficulty = newDiff;
    } else if (compareArrayFail === false) {
        newDiff = Math.random(bondDiff);
        difficulty = (- newDiff);
    } else {

    }
}
<commit_msg>modification de la difficulté<commit_after>var difficulty = 0;
var mode = 0; //à intégrer dans chaque jeu, 0 pour adaptation de la difficulté en fonction win/fail, 1 pour courbe bonds

/* variables à récupérer :
 * winState
 * mise
 * tours
 * difficulty (gameSpeed dans tomcruise.js)
 */

// à intégrer dans chaque jeu
function changeMetaDiff() {
    if (mode === 0) {
        // reprendre code actuel fonctionnement diff
    } else if (mode === 1) {
        // envoyer vers contenu de ce script js
        cumulTours();
        checkWinFail();
        changeDifficulty();
    }
}

// conserver le nombre de tours gagnants d'affilé
var lastWinFail = [];
var cumulWin = [];
var cumulFail = [];
var bondDiff = [0.1, 0.3, 0.7];
var win = "true";
var fail = "false";

var compteurTroisTours = 0; //compteur qui augmente après chaque tour
var toursGagnantsDaffile = 0; //à incrémenter, dés que c'est égal à 3, modifier courbe

function cumulTours() {
    if (winState === true) {
        lastWinFail.push("true");
        compteurTroisTours++;
        clearArray();
    } else if (winState === false) {
        lastWinFail.push("fail");
        compteurTroisTours++;
        clearArray();
    }
}

function clearArray() {
    if (compteurTroisTours === 3) {
        lastWinFail = [];
    }
}

function checkWinFail() {
    var idx = lastWinFail.indexOf(win);
    var i = 0;
    while (idx != -1 && i >= 3) {
        cumulWin.push(idx);
        idx = lastWinFail.indexOf(win, idx + 1);
        i++;
    }
    console.log(cumulWin);

    var idx2 = lastWinFail.indexOf(win);
    var j = 0;
    while (idx2 != -1 && j >= 3) {
        cumulFail.push(idx2);
        idx2 = lastWinFail.indexOf(win, idx2 + 1);
        j++;
    }
    console.log(cumulFail);
}

function changeDifficulty() {
    //comparer les tableaux pour vérifier la présence de trois win
    var compareArrayWin = function (lastWinFail, cumulWin) {
        if (lastWinFail === cumulWin) {
            return true;
        }
        if (lastWinFail.length !== cumulWin.length) {
            return false;
        }
        for (var i = 0; i < lastWinFail.length; i++) {
            if (!equal(lastWinFail[i], cumulWin[i])) return false;
        }
        return true;
    };

    //comparer les tableaux pour vérifier la présence de trois fail
    var compareArrayFail = function (lastWinFail, cumulFail) {
        if (lastWinFail === cumulFail) {
            return true;
        }
        if (lastWinFail.length !== cumulFail.length) {
            return false;
        }
        for (var i = 0; i < lastWinFail.length; i++) {
            if (!equal(lastWinFail[i], cumulFail[i])) return false;
        }
        return true;
    };

    //modifier la difficulté en fonction
    if (compareArrayWin === true) {
        newDiff = Math.random(bondDiff);
        difficulty = difficulty + newDiff;
    } else if (compareArrayFail === true) {
        newDiff = Math.random(bondDiff);
        difficulty = difficulty - newDiff;
    } else {

    }
}

<|endoftext|>


<commit_before>// DOM Library Utilites
$.parseUrlQuery = function (url) {
   var url = url || location.href;
    var query = {}, i, params, param;

    if (typeof url === 'string' && url.length)  {
        url = (url.indexOf('#') > -1) ? url.split('#')[0] : url;
        if (url.indexOf('?') > -1) url = url.split('?')[1];
        else return query;

        params = url.split('&');
        for (i = 0; i < params.length; i ++) {
            param = params[i].split('=');
            query[param[0]] = param[1];
        }
    }
    return query;
};
$.isArray = function (arr) {
    if (Object.prototype.toString.apply(arr) === '[object Array]') return true;
    else return false;
};
$.each = function (obj, callback) {
    if (typeof obj !== 'object') return;
    if (!callback) return;
    var i, prop;
    if ($.isArray(obj) || obj instanceof Dom7) {
        // Array
        for (i = 0; i < obj.length; i++) {
            callback(i, obj[i]);
        }
    }
    else {
        // Object
        for (prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                callback(prop, obj[prop]);
            }
        }
    }
};
$.unique = function (arr) {
    var unique = [];
    for (var i = 0; i < arr.length; i++) {
        if (unique.indexOf(arr[i]) === -1) unique.push(arr[i]);
    }
    return unique;
};
$.serializeObject = $.param = function (obj, parents) {
    if (typeof obj === 'string') return obj;
    var resultArray = [];
    var separator = '&';
    parents = parents || [];
    var newParents;
    function var_name(name) {
        if (parents.length > 0) {
            var _parents = '';
            for (var j = 0; j < parents.length; j++) {
                if (j === 0) _parents += parents[j];
                else _parents += '[' + encodeURIComponent(parents[j]) + ']';
            }
            return _parents + '[' + encodeURIComponent(name) + ']';
        }
        else {
            return encodeURIComponent(name);
        }
    }
    function var_value(value) {
        return encodeURIComponent(value);
    }
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            var toPush;
            if ($.isArray(obj[prop])) {
                toPush = [];
                for (var i = 0; i < obj[prop].length; i ++) {
                    if (!$.isArray(obj[prop][i]) && typeof obj[prop][i] === 'object') {
                        newParents = parents.slice();
                        newParents.push(prop);
                        newParents.push(i + '');
                        toPush.push($.serializeObject(obj[prop][i], newParents));
                    }
                    else {
                        toPush.push(var_name(prop) + '[]=' + var_value(obj[prop][i]));
                    }

                }
                if (toPush.length > 0) resultArray.push(toPush.join(separator));
            }
            else if (typeof obj[prop] === 'object') {
                // Object, convert to named array
                newParents = parents.slice();
                newParents.push(prop);
                toPush = $.serializeObject(obj[prop], newParents);
                if (toPush !== '') resultArray.push(toPush);
            }
            else if (typeof obj[prop] !== 'undefined' && obj[prop] !== '') {
                // Should be string or plain value
                resultArray.push(var_name(prop) + '=' + var_value(obj[prop]));
            }
        }
    }
    return resultArray.join(separator);
};
$.toCamelCase = function (string) {
    return string.toLowerCase().replace(/-(.)/g, function(match, group1) {
        return group1.toUpperCase();
    });
};
$.dataset = function (el) {
    return $(el).dataset();
};
$.getTranslate = function (el, axis) {
    var matrix, curTransform, curStyle, transformMatrix;

    // automatic axis detection
    if (typeof axis === 'undefined') {
        axis = 'x';
    }

    curStyle = window.getComputedStyle(el, null);
    if (window.WebKitCSSMatrix) {
        curTransform = curStyle.transform || curStyle.webkitTransform;
        if (curTransform.split(',').length > 6) {
            curTransform = curTransform.split(', ').map(function(a){
                return a.replace(',','.');
            }).join(', ');
        }
        // Some old versions of Webkit choke when 'none' is passed; pass
        // empty string instead in this case
        transformMatrix = new WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
    }
    else {
        transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
        matrix = transformMatrix.toString().split(',');
    }

    if (axis === 'x') {
        //Latest Chrome and webkits Fix
        if (window.WebKitCSSMatrix)
            curTransform = transformMatrix.m41;
        //Crazy IE10 Matrix
        else if (matrix.length === 16)
            curTransform = parseFloat(matrix[12]);
        //Normal Browsers
        else
            curTransform = parseFloat(matrix[4]);
    }
    if (axis === 'y') {
        //Latest Chrome and webkits Fix
        if (window.WebKitCSSMatrix)
            curTransform = transformMatrix.m42;
        //Crazy IE10 Matrix
        else if (matrix.length === 16)
            curTransform = parseFloat(matrix[13]);
        //Normal Browsers
        else
            curTransform = parseFloat(matrix[5]);
    }

    return curTransform || 0;
};

$.requestAnimationFrame = function (callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback);
    else {
        return window.setTimeout(callback, 1000 / 60);
    }
};
$.cancelAnimationFrame = function (id) {
    if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
    else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
    else if (window.mozCancelAnimationFrame) return window.mozCancelAnimationFrame(id);
    else {
        return window.clearTimeout(id);
    }
};
$.supportTouch = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);

// Link to prototype
$.fn = Dom7.prototype;

// Plugins
$.fn.scrollTo = function (left, top, duration, easing, callback) {
    if (arguments.length === 4 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    return this.each(function () {
        var el = this;
        var currentTop, currentLeft, maxTop, maxLeft, newTop, newLeft, scrollTop, scrollLeft;
        var animateTop = top > 0 || top === 0;
        var animateLeft = left > 0 || left === 0;
        if (typeof easing === 'undefined') {
            easing = 'swing';
        }
        if (animateTop) {
            currentTop = el.scrollTop;
            if (!duration) {
                el.scrollTop = top;
            }
        }
        if (animateLeft) {
            currentLeft = el.scrollLeft;
            if (!duration) {
                el.scrollLeft = left;
            }
        }
        if (!duration) return;
        if (animateTop) {
            maxTop = el.scrollHeight - el.offsetHeight;
            newTop = Math.max(Math.min(top, maxTop), 0);
        }
        if (animateLeft) {
            maxLeft = el.scrollWidth - el.offsetWidth;
            newLeft = Math.max(Math.min(left, maxLeft), 0);
        }
        var startTime = null;
        if (animateTop && newTop === currentTop) animateTop = false;
        if (animateLeft && newLeft === currentLeft) animateLeft = false;
        function render(time) {
            if (time === undefined) {
                time = new Date().getTime();
            }
            if (startTime === null) {
                startTime = time;
            }
            var doneLeft, doneTop, done;
            var progress = Math.max(Math.min((time - startTime) / duration, 1), 0);
            var easeProgress = easing === 'linear' ? progress : (0.5 - Math.cos( progress * Math.PI ) / 2);
            if (animateTop) scrollTop = currentTop + (easeProgress * (newTop - currentTop));
            if (animateLeft) scrollLeft = currentLeft + (easeProgress * (newLeft - currentLeft));
            if (animateTop && newTop > currentTop && scrollTop >= newTop)  {
                el.scrollTop = newTop;
                done = true;
            }
            if (animateTop && newTop < currentTop && scrollTop <= newTop)  {
                el.scrollTop = newTop;
                done = true;
            }

            if (animateLeft && newLeft > currentLeft && scrollLeft >= newLeft)  {
                el.scrollLeft = newLeft;
                done = true;
            }
            if (animateLeft && newLeft < currentLeft && scrollLeft <= newLeft)  {
                el.scrollLeft = newLeft;
                done = true;
            }

            if (done) {
                if (callback) callback();
                return;
            }
            if (animateTop) el.scrollTop = scrollTop;
            if (animateLeft) el.scrollLeft = scrollLeft;
            $.requestAnimationFrame(render);
        }
        $.requestAnimationFrame(render);
    });
};
$.fn.scrollTop = function (top, duration, easing, callback) {
    if (arguments.length === 3 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    var dom = this;
    if (typeof top === 'undefined') {
        if (dom.length > 0) return dom[0].scrollTop;
        else return null;
    }
    return dom.scrollTo(undefined, top, duration, easing, callback);
};
$.fn.scrollLeft = function (left, duration, easing, callback) {
    if (arguments.length === 3 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    var dom = this;
    if (typeof left === 'undefined') {
        if (dom.length > 0) return dom[0].scrollLeft;
        else return null;
    }
    return dom.scrollTo(left, undefined, duration, easing, callback);
};<commit_msg>null case<commit_after>// DOM Library Utilites
$.parseUrlQuery = function (url) {
   var url = url || location.href;
    var query = {}, i, params, param;

    if (typeof url === 'string' && url.length)  {
        url = (url.indexOf('#') > -1) ? url.split('#')[0] : url;
        if (url.indexOf('?') > -1) url = url.split('?')[1];
        else return query;

        params = url.split('&');
        for (i = 0; i < params.length; i ++) {
            param = params[i].split('=');
            query[param[0]] = param[1];
        }
    }
    return query;
};
$.isArray = function (arr) {
    if (Object.prototype.toString.apply(arr) === '[object Array]') return true;
    else return false;
};
$.each = function (obj, callback) {
    if (typeof obj !== 'object') return;
    if (!callback) return;
    var i, prop;
    if ($.isArray(obj) || obj instanceof Dom7) {
        // Array
        for (i = 0; i < obj.length; i++) {
            callback(i, obj[i]);
        }
    }
    else {
        // Object
        for (prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                callback(prop, obj[prop]);
            }
        }
    }
};
$.unique = function (arr) {
    var unique = [];
    for (var i = 0; i < arr.length; i++) {
        if (unique.indexOf(arr[i]) === -1) unique.push(arr[i]);
    }
    return unique;
};
$.serializeObject = $.param = function (obj, parents) {
    if (typeof obj === 'string') return obj;
    var resultArray = [];
    var separator = '&';
    parents = parents || [];
    var newParents;
    function var_name(name) {
        if (parents.length > 0) {
            var _parents = '';
            for (var j = 0; j < parents.length; j++) {
                if (j === 0) _parents += parents[j];
                else _parents += '[' + encodeURIComponent(parents[j]) + ']';
            }
            return _parents + '[' + encodeURIComponent(name) + ']';
        }
        else {
            return encodeURIComponent(name);
        }
    }
    function var_value(value) {
        return encodeURIComponent(value);
    }
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            var toPush;
            if ($.isArray(obj[prop])) {
                toPush = [];
                for (var i = 0; i < obj[prop].length; i ++) {
                    if (!$.isArray(obj[prop][i]) && typeof obj[prop][i] === 'object') {
                        newParents = parents.slice();
                        newParents.push(prop);
                        newParents.push(i + '');
                        toPush.push($.serializeObject(obj[prop][i], newParents));
                    }
                    else {
                        toPush.push(var_name(prop) + '[]=' + var_value(obj[prop][i]));
                    }

                }
                if (toPush.length > 0) resultArray.push(toPush.join(separator));
            }
            else if (obj[prop] === null) {
                resultArray.push(var_name(prop) + '=');
            }
            else if (typeof obj[prop] === 'object') {
                // Object, convert to named array
                newParents = parents.slice();
                newParents.push(prop);
                toPush = $.serializeObject(obj[prop], newParents);
                if (toPush !== '') resultArray.push(toPush);
            }
            else if (typeof obj[prop] !== 'undefined' && obj[prop] !== '') {
                // Should be string or plain value
                resultArray.push(var_name(prop) + '=' + var_value(obj[prop]));
            }
        }
    }
    return resultArray.join(separator);
};
$.toCamelCase = function (string) {
    return string.toLowerCase().replace(/-(.)/g, function(match, group1) {
        return group1.toUpperCase();
    });
};
$.dataset = function (el) {
    return $(el).dataset();
};
$.getTranslate = function (el, axis) {
    var matrix, curTransform, curStyle, transformMatrix;

    // automatic axis detection
    if (typeof axis === 'undefined') {
        axis = 'x';
    }

    curStyle = window.getComputedStyle(el, null);
    if (window.WebKitCSSMatrix) {
        curTransform = curStyle.transform || curStyle.webkitTransform;
        if (curTransform.split(',').length > 6) {
            curTransform = curTransform.split(', ').map(function(a){
                return a.replace(',','.');
            }).join(', ');
        }
        // Some old versions of Webkit choke when 'none' is passed; pass
        // empty string instead in this case
        transformMatrix = new WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
    }
    else {
        transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
        matrix = transformMatrix.toString().split(',');
    }

    if (axis === 'x') {
        //Latest Chrome and webkits Fix
        if (window.WebKitCSSMatrix)
            curTransform = transformMatrix.m41;
        //Crazy IE10 Matrix
        else if (matrix.length === 16)
            curTransform = parseFloat(matrix[12]);
        //Normal Browsers
        else
            curTransform = parseFloat(matrix[4]);
    }
    if (axis === 'y') {
        //Latest Chrome and webkits Fix
        if (window.WebKitCSSMatrix)
            curTransform = transformMatrix.m42;
        //Crazy IE10 Matrix
        else if (matrix.length === 16)
            curTransform = parseFloat(matrix[13]);
        //Normal Browsers
        else
            curTransform = parseFloat(matrix[5]);
    }

    return curTransform || 0;
};

$.requestAnimationFrame = function (callback) {
    if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
    else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
    else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback);
    else {
        return window.setTimeout(callback, 1000 / 60);
    }
};
$.cancelAnimationFrame = function (id) {
    if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
    else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
    else if (window.mozCancelAnimationFrame) return window.mozCancelAnimationFrame(id);
    else {
        return window.clearTimeout(id);
    }
};
$.supportTouch = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);

// Link to prototype
$.fn = Dom7.prototype;

// Plugins
$.fn.scrollTo = function (left, top, duration, easing, callback) {
    if (arguments.length === 4 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    return this.each(function () {
        var el = this;
        var currentTop, currentLeft, maxTop, maxLeft, newTop, newLeft, scrollTop, scrollLeft;
        var animateTop = top > 0 || top === 0;
        var animateLeft = left > 0 || left === 0;
        if (typeof easing === 'undefined') {
            easing = 'swing';
        }
        if (animateTop) {
            currentTop = el.scrollTop;
            if (!duration) {
                el.scrollTop = top;
            }
        }
        if (animateLeft) {
            currentLeft = el.scrollLeft;
            if (!duration) {
                el.scrollLeft = left;
            }
        }
        if (!duration) return;
        if (animateTop) {
            maxTop = el.scrollHeight - el.offsetHeight;
            newTop = Math.max(Math.min(top, maxTop), 0);
        }
        if (animateLeft) {
            maxLeft = el.scrollWidth - el.offsetWidth;
            newLeft = Math.max(Math.min(left, maxLeft), 0);
        }
        var startTime = null;
        if (animateTop && newTop === currentTop) animateTop = false;
        if (animateLeft && newLeft === currentLeft) animateLeft = false;
        function render(time) {
            if (time === undefined) {
                time = new Date().getTime();
            }
            if (startTime === null) {
                startTime = time;
            }
            var doneLeft, doneTop, done;
            var progress = Math.max(Math.min((time - startTime) / duration, 1), 0);
            var easeProgress = easing === 'linear' ? progress : (0.5 - Math.cos( progress * Math.PI ) / 2);
            if (animateTop) scrollTop = currentTop + (easeProgress * (newTop - currentTop));
            if (animateLeft) scrollLeft = currentLeft + (easeProgress * (newLeft - currentLeft));
            if (animateTop && newTop > currentTop && scrollTop >= newTop)  {
                el.scrollTop = newTop;
                done = true;
            }
            if (animateTop && newTop < currentTop && scrollTop <= newTop)  {
                el.scrollTop = newTop;
                done = true;
            }

            if (animateLeft && newLeft > currentLeft && scrollLeft >= newLeft)  {
                el.scrollLeft = newLeft;
                done = true;
            }
            if (animateLeft && newLeft < currentLeft && scrollLeft <= newLeft)  {
                el.scrollLeft = newLeft;
                done = true;
            }

            if (done) {
                if (callback) callback();
                return;
            }
            if (animateTop) el.scrollTop = scrollTop;
            if (animateLeft) el.scrollLeft = scrollLeft;
            $.requestAnimationFrame(render);
        }
        $.requestAnimationFrame(render);
    });
};
$.fn.scrollTop = function (top, duration, easing, callback) {
    if (arguments.length === 3 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    var dom = this;
    if (typeof top === 'undefined') {
        if (dom.length > 0) return dom[0].scrollTop;
        else return null;
    }
    return dom.scrollTo(undefined, top, duration, easing, callback);
};
$.fn.scrollLeft = function (left, duration, easing, callback) {
    if (arguments.length === 3 && typeof easing === 'function') {
        callback = easing;
        easing = undefined;
    }
    var dom = this;
    if (typeof left === 'undefined') {
        if (dom.length > 0) return dom[0].scrollLeft;
        else return null;
    }
    return dom.scrollTo(left, undefined, duration, easing, callback);
};<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

// flowlint ambiguous-object-type:error

'use strict';

const invariant = require('invariant');

import type {RelayContext} from './RelayStoreTypes.js';
import typeof {createContext} from 'react';

// Ideally, we'd just import the type of the react module, but this causes Flow
// problems.
type React = {
  createContext: createContext<RelayContext | null>,
  version: string,
  ...
};

let relayContext: ?React$Context<RelayContext | null>;
let firstReact: ?React;

function createRelayContext(react: React): React$Context<RelayContext | null> {
  if (!relayContext) {
    relayContext = react.createContext(null);
    firstReact = react;
  }
  invariant(
    react === firstReact,
    '[createRelayContext]: You passing a different instance of React',
    react.version,
  );
  return relayContext;
}

module.exports = createRelayContext;
<commit_msg>Name a bunch of anonymous RN contexts<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

// flowlint ambiguous-object-type:error

'use strict';

const invariant = require('invariant');

import type {RelayContext} from './RelayStoreTypes.js';
import typeof {createContext} from 'react';

// Ideally, we'd just import the type of the react module, but this causes Flow
// problems.
type React = {
  createContext: createContext<RelayContext | null>,
  version: string,
  ...
};

let relayContext: ?React$Context<RelayContext | null>;
let firstReact: ?React;

function createRelayContext(react: React): React$Context<RelayContext | null> {
  if (!relayContext) {
    relayContext = react.createContext(null);
    if (__DEV__) {
      relayContext.displayName = 'RelayContext';
    }
    firstReact = react;
  }
  invariant(
    react === firstReact,
    '[createRelayContext]: You passing a different instance of React',
    react.version,
  );
  return relayContext;
}

module.exports = createRelayContext;
<|endoftext|>