<commit_before>(function($) {
  "use strict"; // Start of use strict

  // Toggle the side navigation
  $("#sidebarToggle").click(function(e) {
    e.preventDefault();
    $("body").toggleClass("sidebar-toggled");
    $(".sidebar").toggleClass("toggled");
  });

  // Prevent the content wrapper from scrolling when the fixed side navigation hovered over
  $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) {
    if ($window.width() > 768) {
      var e0 = e.originalEvent,
        delta = e0.wheelDelta || -e0.detail;
      this.scrollTop += (delta < 0 ? 1 : -1) * 30;
      e.preventDefault();
    }
  });

  // Scroll to top button appear
  $(document).scroll(function() {
    var scrollDistance = $(this).scrollTop();
    if (scrollDistance > 100) {
      $('.scroll-to-top').fadeIn();
    } else {
      $('.scroll-to-top').fadeOut();
    }
  });

  // Smooth scrolling using jQuery easing
  $(document).on('click', 'a.scroll-to-top', function(event) {
    var $anchor = $(this);
    $('html, body').stop().animate({
      scrollTop: ($($anchor.attr('href')).offset().top)
    }, 1000, 'easeInOutExpo');
    event.preventDefault();
  });

})(jQuery); // End of use strict
<commit_msg>Update sb-admin.js<commit_after>(function($) {
  "use strict"; // Start of use strict

  // Toggle the side navigation
  $("#sidebarToggle").on('click',function(e) {
    e.preventDefault();
    $("body").toggleClass("sidebar-toggled");
    $(".sidebar").toggleClass("toggled");
  });

  // Prevent the content wrapper from scrolling when the fixed side navigation hovered over
  $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) {
    if ($(window).width() > 768) {
      var e0 = e.originalEvent,
        delta = e0.wheelDelta || -e0.detail;
      this.scrollTop += (delta < 0 ? 1 : -1) * 30;
      e.preventDefault();
    }
  });

  // Scroll to top button appear
  $(document).on('scroll',function() {
    var scrollDistance = $(this).scrollTop();
    if (scrollDistance > 100) {
      $('.scroll-to-top').fadeIn();
    } else {
      $('.scroll-to-top').fadeOut();
    }
  });

  // Smooth scrolling using jQuery easing
  $(document).on('click', 'a.scroll-to-top', function(event) {
    var $anchor = $(this);
    $('html, body').stop().animate({
      scrollTop: ($($anchor.attr('href')).offset().top)
    }, 1000, 'easeInOutExpo');
    event.preventDefault();
  });

})(jQuery); // End of use strict
<|endoftext|>


<commit_before>

define(['tabmanager'], function(tabmanager) {

  /**
   * @type {Object}
   */
  Settings = {
    ititialized: false,
    defaults: {
      checkInterval: 5000, // How often we check for old tabs.
      badgeCounterInterval: 6000, // How often we update the # of closed tabs in the badge.
      minutesInactive: 20, // How many minutes before we consider a tab "stale" and ready to close.
      minTabs: 5, // Stop acting if there are only minTabs tabs open.
      maxTabs: 100, // Just to keep memory / UI in check.  No UI for this.
      purgeClosedTabs: false, // Save closed tabs in between browser sessions.
      showBadgeCount: true, // Save closed tabs in between browser sessions.
      lockedIds: [],  // An array of tabids which have been explicitly locked by the user.
      whitelist: ["chrome://*"], // An array of patterns to check against.  If a URL matches a pattern, it is never locked.
      paused: false, // If TabWrangler is paused (won't count down)
    },
    // Gets all settings from sync and stores them locally.
    init: function() {
      var self = this;
      var keys = [];
      for (var i in this.defaults) {
        if (this.defaults.hasOwnProperty(i)) {
          this.cache[i] = this.defaults[i];
          keys.push(i);
        }
      }
      chrome.storage.sync.get(keys, function(items) {
        for (var i in items) {
          if (items.hasOwnProperty(i)) {
            self.cache[i] = items[i];
          }
        }
      });
      ititialized = true;
    },
    cache: {}
  };

  /**
   * Returns the number of milliseconds that tabs should stay open for without being used.
   *
   * @return {Number}
   */
  Settings.stayOpen = function() {
    return parseInt(this.get('minutesInactive'), 10) * 60000;
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setminutesInactive = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 0 || parseInt(value, 10) > 720 ){
      throw Error("Minutes Inactive must be greater than 0 and less than 720");
    }
    // Reset the tabTimes since we changed the setting
    tabmanager.tabTimes = {};
    chrome.tabs.query({windowType: 'normal'}, tabmanager.initTabs);

    Settings.setValue('minutesInactive', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setminTabs = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 0 || parseInt(value, 10) > 30 ){
      throw Error("Minimum tabs must be a number between 0 and 30");
    }
    Settings.setValue('minTabs', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setmaxTabs = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 1 || parseInt(value, 10) > 500 ){
      throw Error("Max tabs must be a number between 1 and 500. Setting this too high can cause performance issues");
    }
    Settings.setValue('maxTabs', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setshowBadgeCount = function(value) {
    if (value === false) {
      // Clear out the current badge setting
      chrome.browserAction.setBadgeText({text: ""});
    }
    Settings.setValue('showBadgeCount', value);
  };

  /**
   * @param value
   * @see Settings.set
   */
  Settings.setwhitelist = function(value) {
    // It should be an array, but JS is stupid: http://javascript.crockford.com/remedial.html
    if (typeof(value) != 'object') {
      throw new Error('Whitelist should be an array, ' + typeof(value) + ' given');
    }

    Settings.setValue('whitelist', value);
  };

  Settings.setpaused = function(value) {
    console.log(value);
    if (value === false) {
      // The user has just unpaused, immediately set all tabs to the current time
      // so they will not be closed.
      chrome.tabs.query({
      windowType: 'normal'
    }, tabmanager.initTabs);
    }
    Settings.setValue('paused', value);
  };

  /**
   * Either calls a getter function or retunrs directly from storage.
   * @param key
   * @param fx
   *  Callback function after value is received.
   * @return {*}
   */
  Settings.get = function(key, fx) {
    if (typeof this[key] == 'function') {
      return this[key]();
    }
    return this.cache[key];
  };

  Settings.setValue = function (key, value, fx) {
    var items = {};
    this.cache[key] = value;
    items[key] = value;
    chrome.storage.sync.set(items, fx);
  };

  /**
   * Sets a value in localStorage.  Can also call a setter.
   *
   * If the value is a struct (object or array) it is JSONified.
   *
   * @param key
   *  Settings keyword string.
   * @param value
   * @return {*}
   */
  Settings.set = function(key, value) {
    // Magic setter functions are set{fieldname}
    if (typeof this["set" + key] == 'function') {
      return this["set" + key](value);
    }
    Settings.setValue(key, value);
  };

  return Settings;

});<commit_msg>Increasing minutesInactive limit from 12 hours to 5 days.<commit_after>

define(['tabmanager'], function(tabmanager) {

  /**
   * @type {Object}
   */
  Settings = {
    ititialized: false,
    defaults: {
      checkInterval: 5000, // How often we check for old tabs.
      badgeCounterInterval: 6000, // How often we update the # of closed tabs in the badge.
      minutesInactive: 20, // How many minutes before we consider a tab "stale" and ready to close.
      minTabs: 5, // Stop acting if there are only minTabs tabs open.
      maxTabs: 100, // Just to keep memory / UI in check.  No UI for this.
      purgeClosedTabs: false, // Save closed tabs in between browser sessions.
      showBadgeCount: true, // Save closed tabs in between browser sessions.
      lockedIds: [],  // An array of tabids which have been explicitly locked by the user.
      whitelist: ["chrome://*"], // An array of patterns to check against.  If a URL matches a pattern, it is never locked.
      paused: false, // If TabWrangler is paused (won't count down)
    },
    // Gets all settings from sync and stores them locally.
    init: function() {
      var self = this;
      var keys = [];
      for (var i in this.defaults) {
        if (this.defaults.hasOwnProperty(i)) {
          this.cache[i] = this.defaults[i];
          keys.push(i);
        }
      }
      chrome.storage.sync.get(keys, function(items) {
        for (var i in items) {
          if (items.hasOwnProperty(i)) {
            self.cache[i] = items[i];
          }
        }
      });
      ititialized = true;
    },
    cache: {}
  };

  /**
   * Returns the number of milliseconds that tabs should stay open for without being used.
   *
   * @return {Number}
   */
  Settings.stayOpen = function() {
    return parseInt(this.get('minutesInactive'), 10) * 60000;
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setminutesInactive = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 0 || parseInt(value, 10) > 7200 ){
      throw Error("Minutes Inactive must be greater than 0 and less than 7200");
    }
    // Reset the tabTimes since we changed the setting
    tabmanager.tabTimes = {};
    chrome.tabs.query({windowType: 'normal'}, tabmanager.initTabs);

    Settings.setValue('minutesInactive', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setminTabs = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 0 || parseInt(value, 10) > 30 ){
      throw Error("Minimum tabs must be a number between 0 and 30");
    }
    Settings.setValue('minTabs', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setmaxTabs = function(value) {
    if ( isNaN(parseInt(value, 10)) || parseInt(value, 10) <= 1 || parseInt(value, 10) > 500 ){
      throw Error("Max tabs must be a number between 1 and 500. Setting this too high can cause performance issues");
    }
    Settings.setValue('maxTabs', value);
  };

  /**
   *
   * @param value
   * @see Settings.set
   */
  Settings.setshowBadgeCount = function(value) {
    if (value === false) {
      // Clear out the current badge setting
      chrome.browserAction.setBadgeText({text: ""});
    }
    Settings.setValue('showBadgeCount', value);
  };

  /**
   * @param value
   * @see Settings.set
   */
  Settings.setwhitelist = function(value) {
    // It should be an array, but JS is stupid: http://javascript.crockford.com/remedial.html
    if (typeof(value) != 'object') {
      throw new Error('Whitelist should be an array, ' + typeof(value) + ' given');
    }

    Settings.setValue('whitelist', value);
  };

  Settings.setpaused = function(value) {
    console.log(value);
    if (value === false) {
      // The user has just unpaused, immediately set all tabs to the current time
      // so they will not be closed.
      chrome.tabs.query({
      windowType: 'normal'
    }, tabmanager.initTabs);
    }
    Settings.setValue('paused', value);
  };

  /**
   * Either calls a getter function or retunrs directly from storage.
   * @param key
   * @param fx
   *  Callback function after value is received.
   * @return {*}
   */
  Settings.get = function(key, fx) {
    if (typeof this[key] == 'function') {
      return this[key]();
    }
    return this.cache[key];
  };

  Settings.setValue = function (key, value, fx) {
    var items = {};
    this.cache[key] = value;
    items[key] = value;
    chrome.storage.sync.set(items, fx);
  };

  /**
   * Sets a value in localStorage.  Can also call a setter.
   *
   * If the value is a struct (object or array) it is JSONified.
   *
   * @param key
   *  Settings keyword string.
   * @param value
   * @return {*}
   */
  Settings.set = function(key, value) {
    // Magic setter functions are set{fieldname}
    if (typeof this["set" + key] == 'function') {
      return this["set" + key](value);
    }
    Settings.setValue(key, value);
  };

  return Settings;

});<|endoftext|>


<commit_before>var React = require('react');
var PropTypes = React.PropTypes;

import { BarChart, Bar, Cell, CartesianGrid, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import { HUC12_MAP_FEATUREID, TRA_MAP_FEATUREID, CATALOGING_MAP_FEATUREID, NLCD_MAP_FEATUREID } from '../constants/actionConstants';

const tooltipstyle = {
  width: '100%',
  margin: 0,
  lineHeight: 24,
  border: '1px solid #f5f5f5',
  backgroundColor: 'rgba(255, 255, 255, 0.95)',
  padding: 10,
};

const toolTipLabel = {
  margin: '0',
  color: '#666',
  fontWeight: '700',
};

const CustomToolTipBarCharts  = React.createClass({
  propTypes: {
    type: PropTypes.string,
    payload: PropTypes.array,
    label: PropTypes.string,
  },
  get_layer_id: function(layer){
    switch (layer) {
      case 'baseline':
        return HUC12_MAP_FEATUREID
        break;
      case 'uplift':
        return HUC12_MAP_FEATUREID
        break;
      case 'tra':
        return TRA_MAP_FEATUREID
        break;
      default:
        return HUC12_MAP_FEATUREID
    }
  },
  handleMouse: function (data, e){
    const chart_type = this.props.chart_type

    this.props.set_search_method('chart hover ' + chart_type)
    this.props.get_LayerGeom_ByValue(data.value, data.layer_id)

  },
  componentWillUpdate: function(nextProps, nextState) {
    const self = this;
    const layer_id = this.get_layer_id(nextProps.chart_type)
    const data = {value:nextProps.label, chart_type: nextProps.chart_type, layer_id};
    const nodata = {value:null, chart_type: null, layer_id: null}
    const chart_type = nextProps.chart_type

    const foreground_bar = $('#bar-chart-'+chart_type).find('.recharts-rectangle.recharts-bar-rectangle')
    const background_bar = $('#bar-chart-'+chart_type).find('.recharts-bar-cursor')
    const background_bar2 = $('#bar-chart-'+chart_type).find('.recharts-wrapper')

    //yes jquery but I cannot hook to the elements in d3 svg.
    //  so i need to bind to them...
    $(foreground_bar).unbind('click');
    $(foreground_bar).unbind('mouseenter');
    $(foreground_bar).unbind('mouseleave');

    $(background_bar).unbind('click');
    $(background_bar).unbind('mouseenter');
    $(background_bar).unbind('mouseleave');

    $(background_bar2).unbind('click');
    $(background_bar2).unbind('mouseenter');
    $(background_bar2).unbind('mouseleave');

    $(background_bar).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })
    $(background_bar2).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })
    $(foreground_bar).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })

    // $(background_bar).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    // $(background_bar2).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    // $(foreground_bar).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    //
    // $(background_bar).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })
    // $(background_bar2).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })
    // $(foreground_bar).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })

  },

  render() {

    const { active } = this.props;
    let html_hov = '';
    if (active) {
      const { payload, label } = this.props;

      const layer_id = this.get_layer_id(this.props.chart_type)

      const reversed_payload = [ ...payload ].reverse()

      const thedata = reversed_payload.map( bar_segment => {
       const colors = this.props.get_keyColors(bar_segment.name)

        const toolTipName = {
          margin: '0',
          color: colors[1],
        }

        const toolTipValue = {
          fontWeight: '800',
        }

        const value = bar_segment.value ?  bar_segment.value.toString().substring(0,5) : '0';
        const name = bar_segment.name + ": "

        const testname = this.props.function_limits[0].active_name
        console.log(testname,bar_segment.name)
        //when tra's have a value of 0 do not display the tool tip...
        if((bar_segment.value === 0 || !bar_segment.value ) && this.props.chart_type.toUpperCase() === 'TRA' ){
          return null
        } else {
          if(bar_segment.value === 0 || !bar_segment.value ){
            return null
          } else {
            return (
{name}{value}
)
          }
        }
      })

      //check to see if there is data in the case of tra's there could be no data and
      //  we want to tell users that there is no data.
      let hasdata = false;
      thedata.map( d  => {
        if(d){hasdata = true}
      })

      const labelstr = label.toString().trim();

      //null tip when there is no id
      if (!labelstr || !hasdata){
        return (
)
      }

      //return tooltip
      return (

{this.props.level_label}: {`${labelstr}`}

          {thedata}

      );
    }

    return null;
  }
});

module.exports = CustomToolTipBarCharts;
<commit_msg>remove console info<commit_after>var React = require('react');
var PropTypes = React.PropTypes;

import { BarChart, Bar, Cell, CartesianGrid, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import { HUC12_MAP_FEATUREID, TRA_MAP_FEATUREID, CATALOGING_MAP_FEATUREID, NLCD_MAP_FEATUREID } from '../constants/actionConstants';

const tooltipstyle = {
  width: '100%',
  margin: 0,
  lineHeight: 24,
  border: '1px solid #f5f5f5',
  backgroundColor: 'rgba(255, 255, 255, 0.95)',
  padding: 10,
};

const toolTipLabel = {
  margin: '0',
  color: '#666',
  fontWeight: '700',
};

const CustomToolTipBarCharts  = React.createClass({
  propTypes: {
    type: PropTypes.string,
    payload: PropTypes.array,
    label: PropTypes.string,
  },
  get_layer_id: function(layer){
    switch (layer) {
      case 'baseline':
        return HUC12_MAP_FEATUREID
        break;
      case 'uplift':
        return HUC12_MAP_FEATUREID
        break;
      case 'tra':
        return TRA_MAP_FEATUREID
        break;
      default:
        return HUC12_MAP_FEATUREID
    }
  },
  handleMouse: function (data, e){
    const chart_type = this.props.chart_type

    this.props.set_search_method('chart hover ' + chart_type)
    this.props.get_LayerGeom_ByValue(data.value, data.layer_id)

  },
  componentWillUpdate: function(nextProps, nextState) {
    const self = this;
    const layer_id = this.get_layer_id(nextProps.chart_type)
    const data = {value:nextProps.label, chart_type: nextProps.chart_type, layer_id};
    const nodata = {value:null, chart_type: null, layer_id: null}
    const chart_type = nextProps.chart_type

    const foreground_bar = $('#bar-chart-'+chart_type).find('.recharts-rectangle.recharts-bar-rectangle')
    const background_bar = $('#bar-chart-'+chart_type).find('.recharts-bar-cursor')
    const background_bar2 = $('#bar-chart-'+chart_type).find('.recharts-wrapper')

    //yes jquery but I cannot hook to the elements in d3 svg.
    //  so i need to bind to them...
    $(foreground_bar).unbind('click');
    $(foreground_bar).unbind('mouseenter');
    $(foreground_bar).unbind('mouseleave');

    $(background_bar).unbind('click');
    $(background_bar).unbind('mouseenter');
    $(background_bar).unbind('mouseleave');

    $(background_bar2).unbind('click');
    $(background_bar2).unbind('mouseenter');
    $(background_bar2).unbind('mouseleave');

    $(background_bar).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })
    $(background_bar2).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })
    $(foreground_bar).on("click",function(){
      self.props.handleClick(self,{name:data.value});
    })

    // $(background_bar).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    // $(background_bar2).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    // $(foreground_bar).on("mouseenter",function(){
    //   self.handleMouse(data);
    // })
    //
    // $(background_bar).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })
    // $(background_bar2).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })
    // $(foreground_bar).on("mouseleave",function(){
    //   self.handleMouse(nodata);
    // })

  },

  render() {

    const { active } = this.props;
    let html_hov = '';
    if (active) {
      const { payload, label } = this.props;

      const layer_id = this.get_layer_id(this.props.chart_type)

      const reversed_payload = [ ...payload ].reverse()

      const thedata = reversed_payload.map( bar_segment => {
       const colors = this.props.get_keyColors(bar_segment.name)

        const toolTipName = {
          margin: '0',
          color: colors[1],
        }

        const toolTipValue = {
          fontWeight: '800',
        }

        const value = bar_segment.value ?  bar_segment.value.toString().substring(0,5) : '0';
        const name = bar_segment.name + ": "

        const testname = this.props.function_limits[0].active_name

        //when tra's have a value of 0 do not display the tool tip...
        if((bar_segment.value === 0 || !bar_segment.value ) && this.props.chart_type.toUpperCase() === 'TRA' ){
          return null
        } else {
          if(bar_segment.value === 0 || !bar_segment.value ){
            return null
          } else {
            return (
{name}{value}
)
          }
        }
      })

      //check to see if there is data in the case of tra's there could be no data and
      //  we want to tell users that there is no data.
      let hasdata = false;
      thedata.map( d  => {
        if(d){hasdata = true}
      })

      const labelstr = label.toString().trim();

      //null tip when there is no id
      if (!labelstr || !hasdata){
        return (
)
      }

      //return tooltip
      return (

{this.props.level_label}: {`${labelstr}`}

          {thedata}

      );
    }

    return null;
  }
});

module.exports = CustomToolTipBarCharts;
<|endoftext|>


<commit_before>import SlackOAuth from '../slack-oauth/component';

export default SlackOAuth.extend({});
<commit_msg>Use absolute path<commit_after>import SlackOAuth from 'canvas-web/components/slack-oauth/component';

export default SlackOAuth.extend({});
<|endoftext|>


<commit_before>//     Zepto.js
//     (c) 2010-2015 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

//添加touch事件
(function($){
  var touch = {},
    touchTimeout, tapTimeout, swipeTimeout, longTapTimeout,
    longTapDelay = 750,
    gesture;

  //根据左边判断swipe方向
  function swipeDirection(x1, x2, y1, y2) {
    return Math.abs(x1 - x2) >=
      Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
  }

  function longTap() {
    longTapTimeout = null;
    if (touch.last) {
      touch.el.trigger('longTap');
      touch = {};
    }
  }

  function cancelLongTap() {
    if (longTapTimeout) {
      clearTimeout(longTapTimeout);
    }
    longTapTimeout = null
  }

  function cancelAll() {
    if (touchTimeout) {
      clearTimeout(touchTimeout);
    }
    if (tapTimeout) {
      clearTimeout(tapTimeout);
    }
    if (swipeTimeout) {
      clearTimeout(swipeTimeout);
    }
    if (longTapTimeout) {
      clearTimeout(longTapTimeout);
    }
    touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null;
    touch = {};
  }

  function isPrimaryTouch(event){
    return (event.pointerType == 'touch' ||
      event.pointerType == event.MSPOINTER_TYPE_TOUCH)
      && event.isPrimary;
  }

  function isPointerEventType(e, type){
    return (e.type == 'pointer'+type ||
      e.type.toLowerCase() == 'mspointer'+type);
  }

  $(document).ready(function(){
    var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType;

    if ('MSGesture' in window) {
      gesture = new MSGesture();
      gesture.target = document.body;
    }

    $(document)
      .bind('MSGestureEnd', function(e){
        var swipeDirectionFromVelocity =
          e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null;
        if (swipeDirectionFromVelocity) {
          touch.el.trigger('swipe');
          touch.el.trigger('swipe'+ swipeDirectionFromVelocity);
        }
      })
      .on('touchstart MSPointerDown pointerdown', function(e){
        if((_isPointerType = isPointerEventType(e, 'down')) &&
          !isPrimaryTouch(e)) {
          return;
        }
        firstTouch = _isPointerType ? e : e.touches[0];
        if (e.touches && e.touches.length === 1 && touch.x2) {
          // Clear out touch movement data if we have it sticking around
          // This can occur if touchcancel doesn't fire due to preventDefault, etc.
          touch.x2 = undefined;
          touch.y2 = undefined;
        }
        now = Date.now();
        delta = now - (touch.last || now);
        touch.el = $('tagName' in firstTouch.target ?
          firstTouch.target : firstTouch.target.parentNode);
        touchTimeout && clearTimeout(touchTimeout);
        touch.x1 = firstTouch.pageX;
        touch.y1 = firstTouch.pageY;
        if (delta > 0 && delta <= 250) {
          touch.isDoubleTap = true;
        }
        touch.last = now;
        longTapTimeout = setTimeout(longTap, longTapDelay);
        // adds the current touch contact for IE gesture recognition
        if (gesture && _isPointerType) {
          gesture.addPointer(e.pointerId);
        }
      })
      .on('touchmove MSPointerMove pointermove', function(e){
        if((_isPointerType = isPointerEventType(e, 'move')) &&
          !isPrimaryTouch(e)) return
        firstTouch = _isPointerType ? e : e.touches[0]
        cancelLongTap()
        touch.x2 = firstTouch.pageX
        touch.y2 = firstTouch.pageY

        deltaX += Math.abs(touch.x1 - touch.x2)
        deltaY += Math.abs(touch.y1 - touch.y2)
      })
      .on('touchend MSPointerUp pointerup', function(e){
        if((_isPointerType = isPointerEventType(e, 'up')) &&
          !isPrimaryTouch(e)) return
        cancelLongTap()

        // swipe
        if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
            (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))

          swipeTimeout = setTimeout(function() {
            touch.el.trigger('swipe');
            touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
            touch = {};
          }, 0);

        // normal tap
        else if ('last' in touch)
          // don't fire tap when delta position changed by more than 30 pixels,
          // for instance when moving to a point and back to origin
          if (deltaX < 30 && deltaY < 30) {
            // delay by one tick so we can cancel the 'tap' event if 'scroll' fires
            // ('tap' fires before 'scroll')
            tapTimeout = setTimeout(function() {

              // trigger universal 'tap' with the option to cancelTouch()
              // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
              var event = $.Event('tap')
              event.cancelTouch = cancelAll;
              touch.el.trigger(event);

              // trigger double tap immediately
              if (touch.isDoubleTap) {
                if (touch.el) touch.el.trigger('doubleTap')
                touch = {}
              }

              // trigger single tap after 250ms of inactivity
              else {
                touchTimeout = setTimeout(function(){
                  touchTimeout = null
                  if (touch.el) touch.el.trigger('singleTap')
                  touch = {}
                }, 250)
              }
            }, 0)
          } else {
            touch = {}
          }
          deltaX = deltaY = 0

      })
      // when the browser window loses focus,
      // for example when a modal dialog is shown,
      // cancel all ongoing events
      .on('touchcancel MSPointerCancel pointercancel', cancelAll);

    // scrolling the window indicates intention of the user
    // to scroll, not tap or swipe, so cancel all ongoing events
    $(window).on('scroll', cancelAll);
  });

  ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
    'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){
    $.fn[eventName] = function(callback){
      return this.on(eventName, callback);
    };
  })
})(Zepto);
<commit_msg>add comment<commit_after>//     Zepto.js
//     (c) 2010-2015 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

//添加touch事件
(function($){
  var touch = {},
    touchTimeout, tapTimeout, swipeTimeout, longTapTimeout,
    longTapDelay = 750,
    gesture;

  //根据左边判断swipe方向
  function swipeDirection(x1, x2, y1, y2) {
    return Math.abs(x1 - x2) >=
      Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
  }

  function longTap() {
    longTapTimeout = null;
    if (touch.last) {
      touch.el.trigger('longTap');
      touch = {};
    }
  }

  function cancelLongTap() {
    if (longTapTimeout) {
      clearTimeout(longTapTimeout);
    }
    longTapTimeout = null
  }

  function cancelAll() {
    if (touchTimeout) {
      clearTimeout(touchTimeout);
    }
    if (tapTimeout) {
      clearTimeout(tapTimeout);
    }
    if (swipeTimeout) {
      clearTimeout(swipeTimeout);
    }
    if (longTapTimeout) {
      clearTimeout(longTapTimeout);
    }
    touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null;
    touch = {};
  }

  function isPrimaryTouch(event){
    return (event.pointerType == 'touch' ||
      event.pointerType == event.MSPOINTER_TYPE_TOUCH)
      && event.isPrimary;
  }

  //是否pointer事件
  function isPointerEventType(e, type){
    return (e.type == 'pointer'+type ||
      e.type.toLowerCase() == 'mspointer'+type);
  }

  $(document).ready(function(){
    var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType;

    if ('MSGesture' in window) {
      gesture = new MSGesture();
      gesture.target = document.body;
    }

    $(document)
        //IE的手势
      .bind('MSGestureEnd', function(e){
        var swipeDirectionFromVelocity =
          e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null;
        if (swipeDirectionFromVelocity) {
          touch.el.trigger('swipe');
          touch.el.trigger('swipe'+ swipeDirectionFromVelocity);
        }
      })
      .on('touchstart MSPointerDown pointerdown', function(e){
        if((_isPointerType = isPointerEventType(e, 'down')) &&
          !isPrimaryTouch(e)) {
          return;
        }
        firstTouch = _isPointerType ? e : e.touches[0];
        if (e.touches && e.touches.length === 1 && touch.x2) {
          // Clear out touch movement data if we have it sticking around
          // This can occur if touchcancel doesn't fire due to preventDefault, etc.
          touch.x2 = undefined;
          touch.y2 = undefined;
        }
        now = Date.now();
        delta = now - (touch.last || now);//上次有时间
        touch.el = $('tagName' in firstTouch.target ?
          firstTouch.target : firstTouch.target.parentNode);
        touchTimeout && clearTimeout(touchTimeout);
        touch.x1 = firstTouch.pageX;
        touch.y1 = firstTouch.pageY;
        if (delta > 0 && delta <= 250) {
          touch.isDoubleTap = true;//双击
        }
        touch.last = now;
        longTapTimeout = setTimeout(longTap, longTapDelay);//750ms表示长按
        // adds the current touch contact for IE gesture recognition
        if (gesture && _isPointerType) {
          gesture.addPointer(e.pointerId);
        }
      })
      .on('touchmove MSPointerMove pointermove', function(e){
        if((_isPointerType = isPointerEventType(e, 'move')) &&
          !isPrimaryTouch(e)) {
          return;
        }
        firstTouch = _isPointerType ? e : e.touches[0];
        cancelLongTap();//触发move就取消longtap
        touch.x2 = firstTouch.pageX;
        touch.y2 = firstTouch.pageY;

        deltaX += Math.abs(touch.x1 - touch.x2);
        deltaY += Math.abs(touch.y1 - touch.y2);
      })
      .on('touchend MSPointerUp pointerup', function(e){
        if((_isPointerType = isPointerEventType(e, 'up')) &&
          !isPrimaryTouch(e)) {
          return;
        }
        cancelLongTap();//取消longtap

        // swipe
        if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
            (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))

          swipeTimeout = setTimeout(function() {
            touch.el.trigger('swipe');
            touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
            touch = {};
          }, 0);

        // normal tap
        else if ('last' in touch)
          // don't fire tap when delta position changed by more than 30 pixels,
          // for instance when moving to a point and back to origin
          if (deltaX < 30 && deltaY < 30) {
            // delay by one tick so we can cancel the 'tap' event if 'scroll' fires
            // ('tap' fires before 'scroll')
            tapTimeout = setTimeout(function() {

              // trigger universal 'tap' with the option to cancelTouch()
              // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
              var event = $.Event('tap');
              event.cancelTouch = cancelAll;
              touch.el.trigger(event);

              // trigger double tap immediately
              if (touch.isDoubleTap) {
                if (touch.el) {
                  touch.el.trigger('doubleTap');
                }
                touch = {};
              }

              // trigger single tap after 250ms of inactivity
              else {
                touchTimeout = setTimeout(function(){
                  touchTimeout = null;
                  if (touch.el) {
                    touch.el.trigger('singleTap');
                  }
                  touch = {};
                }, 250);
              }
            }, 0);
          } else {
            touch = {};
          }
          deltaX = deltaY = 0;

      })
      // when the browser window loses focus,
      // for example when a modal dialog is shown,
      // cancel all ongoing events
      .on('touchcancel MSPointerCancel pointercancel', cancelAll);

    // scrolling the window indicates intention of the user
    // to scroll, not tap or swipe, so cancel all ongoing events
    $(window).on('scroll', cancelAll);
  });

  ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
    'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){
    $.fn[eventName] = function(callback){
      return this.on(eventName, callback);
    };
  })
})(Zepto);
<|endoftext|>


<commit_before>import * as assert from "assert"
import generate from "babel-generator"
import * as T from "babel-types"
import {Tag,symKind,symName} from "./core"
import chalk from "chalk"

const MAX_TRACE_CODE_LEN = 40
const TYPE_SIZE = 20
const BROWSER_DEBUG = typeof window !== "undefined" && window.chrome
const enterStyles = "background: #222; color: #bada55;font-size:1.5em"
const leaveStyles = "color: #ee5757; background: black"
const newTagStyle = "color:purple;font-size:large"
const positionStyle = "color:gray;text-decoration:underline"
const dirStyle = "font-size:x-large;font-weight:bolder"

/**
  * outputs short description of AST node
  */
export function cg(ast, opts = {}) {
  var res
  if (ast == null) {
    // console.error("<NULL>")
    return "<NULL>"
  }
  try {
    if (Array.isArray(ast)) {
      ast = ast.length > 0 && T.isExpression(ast[0])
        ? T.sequenceExpression(ast)
        : T.blockStatement(ast)
    }
    res = generate(ast,opts,"").code
  } catch (e) {
    if (ast.type != null)
      console.error(e.stack)
  }
  if (res != null) {
    return res
  }
  return "!!" + opts.compact ? JSON.stringify(ast) : JSON.stringify(ast,null,2)
}

/**
  * same as `cg` but using compact syntax
  */
export function ccg(ast) {
  return cg(ast,{compact:true})
}

if (BROWSER_DEBUG) {
  global.cg = cg
  global.ccg = ccg
}

export function* verify(s) {
  const stack = []
  for(const i of s) {
    assert.ok(i.enter != null)
    assert.ok(i.leave != null)
    assert.ok(i.pos != null)
    assert.ok(i.type != null)
    assert.ok(i.value != null)
    if (i.enter && stack.length) {
      const [f,keys] = stack[stack.length-1]
      if (f.type === Tag.Array) {
        assert.equal(i.pos, Tag.push)
      } else if (keys != null) {
        let k
        while((k = keys.shift()) != null) {
          if (Tag[k] === i.pos)
            break
        }
        assert.ok(k,"field name exists")
      }
    }
    if (i.enter && !i.leave) {
      const keys = T.VISITOR_KEYS[symName(i.type)]
      stack.push([i,keys && [...keys]])
    }
    if (!i.enter && i.leave) {
      const [f] = stack.pop()
      assert.ok(f != null)
      assert.equal(f.type,i.type)
      assert.equal(f.pos,i.pos)
      assert.equal(f.value,i.value)
    }
    yield i
  }
  assert.equal(stack.length,0)
}

function pad(s) {
  if (s.length % 2)
    s += ' '
  const sps = Array(Math.max(20 - s.length/2,2)).join(' ')
  return sps + s + sps
}

const traceImpl = BROWSER_DEBUG ? browserTraceImpl : traceNodeImpl

function* traceNodeImpl(prefix, s) {
  let level = 0
  let x = 0
//  prefix = chalk.bold(prefix)
  for(const i of s) {
    if (i.enter)
      level++
    const dir = chalk.bold(i.leave ? (i.enter ? "|" : "/") : "\\")

    const clevel = s.level ? `/${s.level}` : ""
    const descr = `${chalk.green(symName(i.pos))}:${
           i.type.ctrl ? chalk.green(symName(i.type))
                       : chalk.green.bold(symName(i.type))
        }[${level}${clevel}]`
    let n = ""
    const {node} = i.value
    const comments = []
    let commentsTxt = ""
    if (i.value.comments) {
      for(const j of i.obj.comments) {
        let c = j.txt
        c = !i.enter(chalk.dim(j.txt)) || j.txt
      }
      if (comments.length)
        commentsTxt = chalk.bold("[") + comments.join(" ") + chalk.bold("]")
    }
    if (node != null && i.type !== Tag.Array && symKind(i.type) !== "ctrl") {
      n = ccg(node)
      if (n.length > MAX_TRACE_CODE_LEN)
        n = n.substr(0,MAX_TRACE_CODE_LEN) + "..."
      n = chalk.yellow(n)
      const {loc} = node
      if (loc != null) {
        let {source:f,start:s,end:e} = loc
        n += chalk.blue(` @${f || "?"}-${s.line}:${s.column}..${e.line}:${e.column}`)
      } else {
        n += chalk.bold(" @new")
      }
    }
    console.log(
      prefix,
      Array(level).join(' '),
      dir,`${descr}@${x}`,
      commentsTxt, n)
    yield i
    if (i.leave) {
      level--
    }
    x++
  }
  console.log(prefix,"len:",x)
}

function* browserTraceImpl(prefix,s) {
  let level = 0
  let x = 0
  console.log(`%c${pad(prefix)}%c`,
              `background:#2B81AF;color:#fff;font-size:xx-large;
              text-shadow:rgba(0, 0, 0, 0.5) 2px 2px 1px`,
              "")
  for(const i of s) {
    const styles = []
    if (i.enter)
      level++
    const dir = i.enter && i.leave ? "\u21c4" : i.enter ? "\u2192" : "\u2190"
    const clevel = s.level ? `/${s.level}` : ""
    const tp = i.pos === i.type ? symName(i.type)
          :`${symName(i.pos)}:${symName(i.type)}`
    const descr = `${prefix}${tp}[${level}${clevel}]`
    let ldescr
    if (i.pos === i.type) {
      ldescr = `${prefix}%c${symName(i.type)}%c[${level}${clevel}]`
      styles.push(symKind(i.type) === "ctrl"
                  ? "color:navy;font-size:large"
                  : "color:steelblue",
                  "")
    } else {
      ldescr = `${prefix}%c${symName(i.pos)}:%c${
        symName(i.type)}%c[${level}${clevel}]`
      styles.push(symKind(i.pos) === "ctrl"
                  ? "color:olive;font-size:large"
                  : "color:green")
      styles.push(symKind(i.type) === "ctrl"
                  ? "color:navy;font-size:large"
                  : "color:steelblue",
                  "")
    }
    if (i.enter && !i.leave && console.group != null)
      console.group(descr)
    let n = ""
    const {node} = i.value
    const comments = []
    let commentsTxt = ""
    const commentsStyle = []
    if (i.value.comments) {
      for(const j of i.obj.comments) {
        comments.push(`%c${j.txt}%c`)
        const mod = !i.enter
              ? "font-size:small;font-style:italic"
              : "font-weight:bolder"
        const s = `${j.style}${mod}`
        styles.push(s,"")
      }
      if (comments.length)
        commentsTxt = "[" + comments.join(" ") + "]"
    }
    if (node != null && i.type !== Tag.Array && symKind(i.type) !== "ctrl") {
      n = ccg(node)
      if (n.length > MAX_TRACE_CODE_LEN)
        n = n.substr(0,MAX_TRACE_CODE_LEN) + "..."
      n = `%c ${n} %c`
      styles.push(i.enter ? enterStyles : leaveStyles,"")
      const {loc} = node
      if (loc != null) {
        let {source:f,start:s,end:e} = loc
        n += ` %c@${f || "?"}-${s.line}:${s.column}..${e.line}:${e.column}%c`
        styles.push(positionStyle,"")
      } else {
        n += " %c@new%c"
        styles.push(newTagStyle,"")
      }
    }
    console.log(`%c${dir}%c ${ldescr}@${x}${commentsTxt} ${n}`,
                dirStyle,"",
                ...styles,i.value)
    yield i
    if (i.leave) {
      if (!i.enter && console.group != null)
        console.groupEnd()
      level--
    }
    x++
  }
  console.log(`${prefix}: len: ${x}`)
}

function traceAllImpl(prefix,s) {
  return [...verify(traceImpl(prefix,s))]
}

function traceArgs(impl) {
  return function traceImpl(prefix,s) {
    if (prefix == null || prefix.substr == null) {
      if (s == null)
        s = prefix
      prefix = ""
    }
    if (prefix.length)
      prefix += ":"
    if (s == null || s[Symbol.iterator] == null)
      return (s) => impl(prefix,s)
    return impl(prefix,s)
  }
}

export const lazy = traceArgs(traceImpl)
export const all = traceArgs(traceAllImpl)

<commit_msg>comments stylings<commit_after>import * as assert from "assert"
import generate from "babel-generator"
import * as T from "babel-types"
import {Tag,symKind,symName} from "./core"
import chalk from "chalk"

const MAX_TRACE_CODE_LEN = 40
const TYPE_SIZE = 20
export const BROWSER_DEBUG = typeof window !== "undefined" && window.chrome
const enterStyles = "background: #222; color: #bada55;font-size:1.5em"
const leaveStyles = "color: #ee5757; background: black"
const newTagStyle = "color:purple;font-size:large"
const positionStyle = "color:gray;text-decoration:underline"
const dirStyle = "font-size:x-large;font-weight:bolder"

/**
  * outputs short description of AST node
  */
export function cg(ast, opts = {}) {
  var res
  if (ast == null) {
    // console.error("<NULL>")
    return "<NULL>"
  }
  try {
    if (Array.isArray(ast)) {
      ast = ast.length > 0 && T.isExpression(ast[0])
        ? T.sequenceExpression(ast)
        : T.blockStatement(ast)
    }
    res = generate(ast,opts,"").code
  } catch (e) {
    if (ast.type != null)
      console.error(e.stack)
  }
  if (res != null) {
    return res
  }
  return "!!" + opts.compact ? JSON.stringify(ast) : JSON.stringify(ast,null,2)
}

/**
  * same as `cg` but using compact syntax
  */
export function ccg(ast) {
  return cg(ast,{compact:true})
}

if (BROWSER_DEBUG) {
  global.cg = cg
  global.ccg = ccg
}

export function* verify(s) {
  const stack = []
  for(const i of s) {
    assert.ok(i.enter != null)
    assert.ok(i.leave != null)
    assert.ok(i.pos != null)
    assert.ok(i.type != null)
    assert.ok(i.value != null)
    if (i.enter && stack.length) {
      const [f,keys] = stack[stack.length-1]
      if (f.type === Tag.Array) {
        if (symKind(i.type) !== "ctrl")
          assert.equal(i.pos, Tag.push)
      } else if (keys != null) {
        let k
        while((k = keys.shift()) != null) {
          if (Tag[k] === i.pos)
            break
        }
        assert.ok(k,"field name exists")
      }
    }
    if (i.enter && !i.leave) {
      const keys = T.VISITOR_KEYS[symName(i.type)]
      stack.push([i,keys && [...keys]])
    }
    if (!i.enter && i.leave) {
      const [f] = stack.pop()
      assert.ok(f != null)
      assert.equal(f.type,i.type)
      assert.equal(f.pos,i.pos)
      assert.equal(f.value,i.value)
    }
    yield i
  }
  assert.equal(stack.length,0)
}

function pad(s) {
  if (s.length % 2)
    s += ' '
  const sps = Array(Math.max(20 - s.length/2,2)).join(' ')
  return sps + s + sps
}

const traceImpl = BROWSER_DEBUG ? browserTraceImpl : traceNodeImpl

function* traceNodeImpl(prefix, s) {
  let level = 0
  let x = 0
//  prefix = chalk.bold(prefix)
  for(const i of s) {
    if (i.enter)
      level++
    const dir = chalk.bold(i.leave ? (i.enter ? "|" : "/") : "\\")

    const clevel = s.level ? `/${s.level}` : ""
    const descr = `${chalk.green(symName(i.pos))}:${
           i.type.ctrl ? chalk.green(symName(i.type))
                       : chalk.green.bold(symName(i.type))
        }[${level}${clevel}]`
    let n = ""
    const {node} = i.value
    const comments = []
    let commentsTxt = ""
    if (i.value.comments) {
      for(const j of i.obj.comments) {
        let c = j.txt
        c = !i.enter(chalk.dim(j.txt)) || j.txt
      }
      if (comments.length)
        commentsTxt = chalk.bold("[") + comments.join(" ") + chalk.bold("]")
    }
    if (node != null && i.type !== Tag.Array && symKind(i.type) !== "ctrl") {
      n = ccg(node)
      if (n.length > MAX_TRACE_CODE_LEN)
        n = n.substr(0,MAX_TRACE_CODE_LEN) + "..."
      n = chalk.yellow(n)
      const {loc} = node
      if (loc != null) {
        let {source:f,start:s,end:e} = loc
        n += chalk.blue(` @${f || "?"}-${s.line}:${s.column}..${e.line}:${e.column}`)
      } else {
        n += chalk.bold(" @new")
      }
    }
    console.log(
      prefix,
      Array(level).join(' '),
      dir,`${descr}@${x}`,
      commentsTxt, n)
    yield i
    if (i.leave) {
      level--
    }
    x++
  }
  console.log(prefix,"len:",x)
}

function* browserTraceImpl(prefix,s) {
  let level = 0
  let x = 0
  console.log(`%c${pad(prefix)}%c`,
              `background:#2B81AF;color:#fff;font-size:xx-large;
              text-shadow:rgba(0, 0, 0, 0.5) 2px 2px 1px`,
              "")
  for(const i of s) {
    const styles = []
    if (i.enter)
      level++
    const dir = i.enter && i.leave ? "\u21c4" : i.enter ? "\u2192" : "\u2190"
    const clevel = s.level ? `/${s.level}` : ""
    const tp = i.pos === i.type ? symName(i.type)
          :`${symName(i.pos)}:${symName(i.type)}`
    const descr = `${prefix}${tp}[${level}${clevel}]`
    let ldescr
    if (i.pos === i.type) {
      ldescr = `${prefix}%c${symName(i.type)}%c[${level}${clevel}]`
      styles.push(symKind(i.type) === "ctrl"
                  ? "color:navy;font-size:large"
                  : "color:steelblue",
                  "")
    } else {
      ldescr = `${prefix}%c${symName(i.pos)}:%c${
        symName(i.type)}%c[${level}${clevel}]`
      styles.push(symKind(i.pos) === "ctrl"
                  ? "color:olive;font-size:large"
                  : "color:green")
      styles.push(symKind(i.type) === "ctrl"
                  ? "color:navy;font-size:large"
                  : "color:steelblue",
                  "")
    }
    if (i.enter && !i.leave && console.group != null)
      console.group(descr)
    let n = ""
    const {node} = i.value
    const comments = []
    let commentsTxt = ""
    const commentsStyle = []
    if (i.value.comments) {
      for(const j of i.obj.comments) {
        comments.push(`%c${j.txt}%c`)
        const mod = !i.enter
              ? "font-size:small;font-style:italic"
              : "font-weight:bolder"
        const s = `${j.style}${mod}`
        styles.push(s,"")
      }
      if (comments.length) {
        commentsTxt = "%c[" + comments.join(" ") + "]%c"
        styles.push("color:green;font-size:large","")
      }
    }
    if (node != null && i.type !== Tag.Array && symKind(i.type) !== "ctrl") {
      n = ccg(node)
      if (n.length > MAX_TRACE_CODE_LEN)
        n = n.substr(0,MAX_TRACE_CODE_LEN) + "..."
      n = `%c ${n} %c`
      styles.push(i.enter ? enterStyles : leaveStyles,"")
      const {loc} = node
      if (loc != null) {
        let {source:f,start:s,end:e} = loc
        n += ` %c@${f || "?"}-${s.line}:${s.column}..${e.line}:${e.column}%c`
        styles.push(positionStyle,"")
      } else {
        n += " %c@new%c"
        styles.push(newTagStyle,"")
      }
    }
    console.log(`%c${dir}%c ${ldescr}@${x}${commentsTxt} ${n}`,
                dirStyle,"",
                ...styles,i.value)
    yield i
    if (i.leave) {
      if (!i.enter && console.group != null)
        console.groupEnd()
      level--
    }
    x++
  }
  console.log(`${prefix}: len: ${x}`)
}

function traceAllImpl(prefix,s) {
  return [...verify(traceImpl(prefix,s))]
}

function traceArgs(impl) {
  return function traceImpl(prefix,s) {
    if (prefix == null || prefix.substr == null) {
      if (s == null)
        s = prefix
      prefix = ""
    }
    if (prefix.length)
      prefix += ":"
    if (s == null || s[Symbol.iterator] == null)
      return (s) => impl(prefix,s)
    return impl(prefix,s)
  }
}

export const lazy = traceArgs(traceImpl)
export const all = traceArgs(traceAllImpl)

<|endoftext|>


<commit_before>'use strict';

var objects = require('./objects.js');

function type(val) {
    // does an end-around on primitives by converting them to objects
    // tries to find subtype for objects
    if ( val === undefined ) {
        return {'type': 'undefined', 'prototypes': [],
                'subtype': null, 'isPrimitive': true};
    } else if ( val === null ) {
        return {'type': 'null', 'prototypes': [],
                'subtype': null, 'isPrimitive': true};
    }
    var ps = objects.prototypes(val);
    return {
        'type': 'object',
        'prototypes': ps,
        'subtype': (ps.length > 0) ? ps[0].constructor.name : null,
        'isPrimitive': !(val instanceof Object)
    };
}

function isArray(val) {
    return val instanceof Array;
}

function isArguments(val) {
    return Object.prototype.toString.call(obj) === '[object Arguments]';
}

module.exports = {
    'type':  type,
    'isArray': isArray,
    'isArguments': isArguments
};

<commit_msg>simplify interface into type inspection by getting rid of magic<commit_after>'use strict';

var objects = require('./objects.js');

function isProto(obj, possible_prototype) {
    return possible_prototype.isPrototypeOf(obj);
}

function getPrototypes(obj) {
    var protos = [],
        parent;
    while ( true ) { // seems to eventually get to null
        parent = Object.getPrototypeOf(parent);
        if ( parent === null ) {
            break;
        }
        protos.push(parent);
    }
    return protos;
}

function getTypeData(val) {
    if ( val instanceof Object ) {
        var protos = getPrototypes(val);
        return {
            'type'       : 'object', // that's right -- even for functions
            'prototypes' : protos,
            'subtype'    : (protos.length > 0) ? protos[0].constructor.name : null,
            'isPrimitive': false,
            'toString'   : Object.prototype.toString.call(val)
        };
    }
    // else: it's a primitive
    return {
        'type'       : ( val === null ) ? "null" : typeof val,
        'prototypes' : null,
        'subtype'    : null,
        'isPrimitive': true,
        'toString'   : Object.prototype.toString.call(val)
    };
}

module.exports = {
    'getTypeData':  getTypeData,
    'getPrototypes': getPrototypes,
    'isProto': isProto
};
<|endoftext|>


<commit_before>var jgb = jgb || {}

jgb.FillInfo = function(){
  var romInfo = window.emulator.rom
  var romInfoHtml = "Title: " + romInfo.title
  romInfoHtml += "
Type: " + romInfo.cartridgeType
  romInfoHtml += "
Size: " + romInfo.size
  $("#rom-info").append(romInfoHtml)
}

jgb.FileHandler = function(files){
  var romFile = files[0]
  var supportsFileAPI = window.File && window.FileReader && window.FileList && window.Blob
  if (supportsFileAPI) {
    if (romFile.name.toLowerCase().endsWith(".gb")) {
      var reader = new FileReader();
      reader.onload = function(theFile) {
        var content = theFile.target.result
        var romByteArray = new Uint8Array(content)
        window.emulator = new jgb.Gameboy(romByteArray)
        new jgb.FillInfo()
      }
      reader.readAsArrayBuffer(romFile)
    } else {
      alert("This file isn't a gb.")
    }
  } else {
    alert("The File APIs are not fully supported in this browser.")
  }

}
<commit_msg>adds more rom info<commit_after>var jgb = jgb || {}

jgb.FillInfo = function(){
  var romInfo = window.emulator.rom
  var romInfoHtml = "Title: " + romInfo.title
  romInfoHtml += "
Type: " + romInfo.cartridgeType
  romInfoHtml += "
Size: " + romInfo.size
  romInfoHtml += "
Checksum: " + romInfo.globalChecksum
  romInfoHtml += "
Manufacturer: " + romInfo.manufacturer
  $("#rom-info").empty()
  alert(romInfo.rawRom[0x100])
  $("#rom-info").append(romInfoHtml)
}

jgb.FileHandler = function(files){
  var romFile = files[0]
  var supportsFileAPI = window.File && window.FileReader && window.FileList && window.Blob
  if (supportsFileAPI) {
    if (romFile.name.toLowerCase().endsWith(".gb")) {
      var reader = new FileReader();
      reader.onload = function(theFile) {
        var content = theFile.target.result
        var romByteArray = new Uint8Array(content)
        window.emulator = new jgb.Gameboy(romByteArray)
        new jgb.FillInfo()
      }
      reader.readAsArrayBuffer(romFile)
    } else {
      alert("This file isn't a gb.")
    }
  } else {
    alert("The File APIs are not fully supported in this browser.")
  }

}
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import {render} from 'react-dom'
import _ from "lodash"
// var config = require("../config")  // don't need it for now

window.start = function(){
    window.editor = monaco.editor.create(document.getElementById("code-container"), {
        value: window.code,
        language: "javascript",
        readOnly: true,
        scrollBeyondLastLine: false,
    });

    window.addEventListener("resize", function(){
        editor.layout()
    });

    var decorations = Object.keys(locations).map(function(key){
        var location = locations[key].loc
        if (!location) {
            console.log("not sure wht this is... look into, no location info")
            return
        }
        var type = locations[key].type
        var start = location.start
        var end = location.end
        if (type === "returnStatement") {
            end = {line: start.line, column: start.column + "return".length }
        }
        if (type === "functionLocation") {
            return
        }
        // if (type === "call"  ) {
        //     console.log("TODO: INSERT STH WITH RETVAL instead...")

        //     return
        // }

        start.column++
        end.column++

        var hasExamples = locations[key].hasValue

        return  {
            range: new monaco.Range(start.line, start.column, end.line, end.column),
            options: {
                isWholeLine: false,
                inlineClassName: "value value-" + key + " " + (hasExamples ? "" : "value--no-data")
            }
        }

        console.log(location.loc)
    })
    decorations = decorations.filter(x => x !== undefined)

    goToLineInHash()
    editor.deltaDecorations([], decorations);
}

window.onhashchange  = function(){
    goToLineInHash()
}

function goToLineInHash(){
    var line = parseFloat(location.hash.replace("#", ""))
    if (line) {
        var LINE_HEIGHT = 18
        editor.setScrollTop((line - 2) * LINE_HEIGHT)
        editor.setSelection(new monaco.Range(line, 1, line, 1000))
    }
}
window.goToLineInHash = goToLineInHash

var setState = null

window.openingId = 1;

function getValues(scriptId, valueId, cb){
    if (window.valueCache[valueId]) {
        cb(window.valueCache[valueId])
    } else {
        fetch("/__jscb/getValues/" + scriptId + "/" + valueId)
        .then(r=>r.json())
        .then(function(values){
            window.valueCache[valueId] = values;
            cb(values)
        })
    }
}

class OverlayContent extends Component {
    constructor(props){
        super(props)
        this.state = {
            valueId: -1
        }
    }
    componentWillMount(){
        setState = (valueId) => {
            this.setState({
                exampleIndex: 0,
                previewExampleIndex: null,
                valueId: valueId,
                examples: {examples: []},
                hasFetchedExamples: false
            })
            getValues(scriptId, valueId, (examples) => this.setState({
                examples: {examples},
                hasFetchedExamples: true
            }))
        }
    }
    render(){
        if (!this.state.hasFetchedExamples) {
            return null
        }

        if (this.state.examples) {
            var examples = this.state.examples.examples
            window.openingId++

            var exampleNav = null;
            if (examples && examples.length > 1) {
                exampleNav =

                    {examples.map((e, i) => {
                        var previousExamples = examples.slice(0, i)
                        var previousExamplesThatAreSame = previousExamples.filter(function(prevExample){
                            return JSON.stringify(prevExample) == JSON.stringify(e)
                        })
                        var isUnique = previousExamplesThatAreSame.length === 0
                        var isSelected = this.state.exampleIndex === i
                        var className = "example-nav-item "
                        if (isUnique) {
                            className += "example-nav-item__unique "
                        }
                        if (isSelected ){
                            className += "example-nav-item__selected "
                        }
                        return <button
                            onClick={() => this.setState({exampleIndex: i})}
                            className={className}
                            onMouseEnter={() => this.setState({previewExampleIndex: i})}
                            onMouseLeave={() => this.setState({previewExampleIndex: null})}
                            >
                            {i}
                        </button>
                    })}

            }
            var exampleView = null;
            var hasExamples = examples && examples.length > 0
            if (hasExamples) {
                if (this.state.previewExampleIndex === null) {
                    exampleView = <ExampleView example={examples[this.state.exampleIndex]} />
                } else {
                    exampleView = <ExampleView example={examples[this.state.previewExampleIndex]} />
                }
            }
            else {
                exampleView = No value captured, this code didn't run.
            }
            return

                {exampleNav}

                    {exampleView}

        }
        return
no examples

    }
}

class ExampleView extends Component {
    render() {
        return

            <ValueExample key={window.openingId} example={this.props.example} isRoot={true}/>

    }
}

class FunctionPreview extends Component {
    constructor(props){
        super(props)
        this.state = {}
    }
    componentDidMount(){
        var value = this.props.value;
        if (!value.scriptId) {
            this.setState({text: value.text})
        } else {
            fetch("/__jscb/fetchFunctionCode/" + value.scriptId + "/" + value.locationId)
            .then(t => t.json())
            .then(json => this.setState({
                text: json.text,
                url: json.url
            }))
        }
    }
    render(){
        return
            {this.props.value.scriptId ? (<button onClick={() => window.location = this.state.url}>Go to definition</button>
) : null}

{this.state.text ? this.state.text.split(/\n/g).slice(0, 10).join("\n") : null}

    }
}

class StringPreview extends Component {
    constructor(props){
        super(props)
        this.state = {
            isExpanded: false
        }
    }
    render(){
        var val = this.props.value
        var PREVIEW_STRING_LENGTH = 50
        var previewIsTruncated = val.text.length > PREVIEW_STRING_LENGTH
        var toggleButton = null
        var preview = null

        var stringView = null
        if (!this.state.isExpanded) {
            var v = val.text.slice(0, PREVIEW_STRING_LENGTH).replace(/\n/g, "\\n")
            if (previewIsTruncated) {
                v += "..."
            }
            stringView = "{v}"
        } else {
            var fullText = val.text
            var isTruncated = val.length > val.text.length
            if (isTruncated) {
                fullText += "..."
            }
            stringView =

"{fullText}"

        }

        if (previewIsTruncated) {
            toggleButton = <button
                className="toggle-value-detail-button"
                onClick={() => this.setState({isExpanded: !this.state.isExpanded})}>
                {this.state.isExpanded ? "-" : "+"}
            </button>
        } else {
            return stringView
        }

        return

{toggleButton}

{stringView}

    }
}

class Preview extends Component {
    render(){
        var val = this.props.value
        if (typeof val === "number") {
            return {val}
        }
        if (typeof val === "boolean") {
            return {val + ""}
        }
        if (val.type === "Too Deep") {
            return Too deep, no data
        }
        if (val.type === "UI Message") {
            return {val.text}
        }
        if (val.type === "Regular Expression") {
            return {val.value}
        }
        if (val.type === "string") {
            return <StringPreview value={val} />
        }
        if (val.type === "object") {
            return
                (Object)
                {" {" + Object.keys(val.data).join(", ") +"}" }

        }
        if (val.type === "array"){
            return
                (Array) [{val.itemCount}]

        }
        if (val.type === "function") {
            return (Function)
        }
        if (val.type === "undefined") {
            return undefined
        }
        if (val.type === "functionDetail") {
            return <FunctionPreview value={val.fn} />
        }
        if (val.type === "jQuery Object") {
            return
                jQuery Object [{val.elementCount}]

        }
        if (val.type === "HTMLElement") {
            return
                {"<" + val.tagName.toLowerCase() + ">" + val.innerHTML + "<" + val.tagName.toLowerCase() + ">"}

        }
        return (No preview)

{JSON.stringify(val)}

    }
}

class ValueExample extends Component {
    constructor(props) {
        super(props)
        this.state = {
            expandedPaths: []
        }
    }
    render(){
        var example = this.props.example;

        var items = []
        var depth = -1
        var path = []

        console.log("expandedPaths", this.state.expandedPaths)

        var t= this

        function isExpanded(path){
            console.log("isExpanded", path)
            return t.state.expandedPaths.indexOf(path.join(".")) !== -1
        }
        function traverse(e){
            depth++;
            function each(key, val){
                path.push(key)
                var expand = null;
                var canExpand = (val.type === "object" || val.keyCount > 0) ||
                    (val.type === "array" && val.itemCount > 0) ||
                    (val.type === "jQuery Object" && val.elementCount > 0) ||
                    (val.type === "function")
                console.log("val.type", val.type)
                if (canExpand) {
                    expand = {isExpanded(path) ? "▼" : "▶"}
                } else {
                    // keep space free
                    expand = ▼
                }
                let p = path.join(".")
                items.push(
 {
                        var newExpandedPaths = t.state.expandedPaths.slice()
                        if (t.state.expandedPaths.indexOf(p) === -1){
                            newExpandedPaths = newExpandedPaths.concat([p])
                        } else {
                            newExpandedPaths = _.reject(newExpandedPaths, pp => pp === p)
                        }
                        t.setState({expandedPaths: newExpandedPaths})
                    }
                } style={{paddingLeft: (depth + 1) * 20}}>
                    {expand} {key}: <Preview value={val} />

)
                traverse(val)
                path.pop()
            }
            if (e && e.type === "object") {
                if (depth === 0 || isExpanded(path)) {
                    each("constructor", e.konstructor)
                    Object.keys(e.data).forEach(function(key){
                        each(key, e.data[key])
                    })
                    var uncollectedValues = e.keyCount - Object.keys(e.data).length
                    if (uncollectedValues > 0) {
                        each("...", {
                            type: "UI Message",
                            text: "(" + uncollectedValues + " value(s) not collected)"
                        })
                    }
                }
            }
            if (e && e.type === "array") {
                if (depth === 0 || isExpanded(path)) {
                    e.items.forEach(function(item, key){
                        each(key, item)
                    })
                    var uncollectedValues = e.itemCount - e.items.length
                    if (uncollectedValues > 0) {
                        each("...", {
                            type: "UI Message",
                            text: "(" + uncollectedValues + " value(s) not collected)"
                        })
                    }
                }
            }
            if (e && e.type === "jQuery Object") {
                if (depth === 0 || isExpanded(path)) {
                    e.elements.forEach(function(item, key){
                        each(key, item)
                    })
                }
            }
            if (e && e.type === "function") {
                if (depth === 0 || isExpanded(path)) {
                    each("code", {
                        type: "functionDetail",
                        fn: e
                    })
                }
            }

            depth--;
        }
        traverse(example)
        // console.log("items", items)
        return

            {this.props.isRoot ? <Preview value={example} /> : null}
            {items}

    }
}

var overlay = document.getElementById("overlay")
overlay.style.display = "none"
var overlayComp = <OverlayContent />
window.overlayComop = overlayComp
render(overlayComp, overlay)

document.querySelectorAll("[data-value-id]").forEach(function(el){
    var valId = el.getAttribute("data-value-id")
    var vals = window.values[valId]

    if (!vals) {
        vals = []
    }
    if (vals.length ===0) {
        if (el.style.backgroundColor === "red") {
            el.style.backgroundColor = "gray"
        }
        el.style.borderBottom ="1px solid lime"
    }
})

var enteredOverlay = false
var shouldHideOverlaySoon = true
overlay.addEventListener("mouseenter", function(e){
    console.log("mouseenter", e.target)
    enteredOverlay = true;
    setTimeout(function(){
        enteredOverlay = false
    }, 500)
    shouldHideOverlaySoon = false
})
overlay.addEventListener("mouseleave", function(e){
    console.log("mouseleave", e.target)
    shouldHideOverlaySoon = true
    setTimeout(function(){
        if (shouldHideOverlaySoon) {
            overlay.style.display = "none"
        }
    }, 1000)
})

var lastEnteredId = null
document.body.addEventListener("mouseover", function(e){

    var el = e.target
    // console.log(el)
    var match = el.className.match(/value-([0-9]+)/)
    if (match === null) {
        return
    }
    console.log("mouseover", e.target)

    var valId = parseFloat(match[1])
    lastEnteredId = valId
    var overlay = document.getElementById("overlay")
    overlay.style.display = "block"
    overlay.setAttribute("style",
        "top: " + (el.getBoundingClientRect().top + window.scrollY + 12) +
        "px; left: " + (el.getBoundingClientRect().left) + "px"
        + ";position: absolute;padding-top: 8px;"
    )

    setState(valId)

})

document.body.addEventListener("mouseleave", function(e){
    console.log("mouseleave2", e.target)
    var el = e.target
    if (el.className.indexOf("value") === -1) {
        return
    }
    var valId = el.className.split(" ").filter(c => c.indexOf("value-") !== -1)[0].replace(/[^0-9]/g,"")
    if (valId !== lastEnteredId) {
        return;
    }
    {/*console.log(el)*/}
    var valId = el.getAttribute("data-value-id")
    var overlay = document.getElementById("overlay")
    setTimeout(function(){
        if (!enteredOverlay) {
            overlay.style.display = "none"
        }
    }, 400)

})<commit_msg>Make value indices start from 1<commit_after>import React, {Component} from 'react'
import {render} from 'react-dom'
import _ from "lodash"
// var config = require("../config")  // don't need it for now

window.start = function(){
    window.editor = monaco.editor.create(document.getElementById("code-container"), {
        value: window.code,
        language: "javascript",
        readOnly: true,
        scrollBeyondLastLine: false,
    });

    window.addEventListener("resize", function(){
        editor.layout()
    });

    var decorations = Object.keys(locations).map(function(key){
        var location = locations[key].loc
        if (!location) {
            console.log("not sure wht this is... look into, no location info")
            return
        }
        var type = locations[key].type
        var start = location.start
        var end = location.end
        if (type === "returnStatement") {
            end = {line: start.line, column: start.column + "return".length }
        }
        if (type === "functionLocation") {
            return
        }
        // if (type === "call"  ) {
        //     console.log("TODO: INSERT STH WITH RETVAL instead...")

        //     return
        // }

        start.column++
        end.column++

        var hasExamples = locations[key].hasValue

        return  {
            range: new monaco.Range(start.line, start.column, end.line, end.column),
            options: {
                isWholeLine: false,
                inlineClassName: "value value-" + key + " " + (hasExamples ? "" : "value--no-data")
            }
        }

        console.log(location.loc)
    })
    decorations = decorations.filter(x => x !== undefined)

    goToLineInHash()
    editor.deltaDecorations([], decorations);
}

window.onhashchange  = function(){
    goToLineInHash()
}

function goToLineInHash(){
    var line = parseFloat(location.hash.replace("#", ""))
    if (line) {
        var LINE_HEIGHT = 18
        editor.setScrollTop((line - 2) * LINE_HEIGHT)
        editor.setSelection(new monaco.Range(line, 1, line, 1000))
    }
}
window.goToLineInHash = goToLineInHash

var setState = null

window.openingId = 1;

function getValues(scriptId, valueId, cb){
    if (window.valueCache[valueId]) {
        cb(window.valueCache[valueId])
    } else {
        fetch("/__jscb/getValues/" + scriptId + "/" + valueId)
        .then(r=>r.json())
        .then(function(values){
            window.valueCache[valueId] = values;
            cb(values)
        })
    }
}

class OverlayContent extends Component {
    constructor(props){
        super(props)
        this.state = {
            valueId: -1
        }
    }
    componentWillMount(){
        setState = (valueId) => {
            this.setState({
                exampleIndex: 0,
                previewExampleIndex: null,
                valueId: valueId,
                examples: {examples: []},
                hasFetchedExamples: false
            })
            getValues(scriptId, valueId, (examples) => this.setState({
                examples: {examples},
                hasFetchedExamples: true
            }))
        }
    }
    render(){
        if (!this.state.hasFetchedExamples) {
            return null
        }

        if (this.state.examples) {
            var examples = this.state.examples.examples
            window.openingId++

            var exampleNav = null;
            if (examples && examples.length > 1) {
                exampleNav =

                    {examples.map((e, i) => {
                        var previousExamples = examples.slice(0, i)
                        var previousExamplesThatAreSame = previousExamples.filter(function(prevExample){
                            return JSON.stringify(prevExample) == JSON.stringify(e)
                        })
                        var isUnique = previousExamplesThatAreSame.length === 0
                        var isSelected = this.state.exampleIndex === i
                        var className = "example-nav-item "
                        if (isUnique) {
                            className += "example-nav-item__unique "
                        }
                        if (isSelected ){
                            className += "example-nav-item__selected "
                        }
                        return <button
                            onClick={() => this.setState({exampleIndex: i})}
                            className={className}
                            onMouseEnter={() => this.setState({previewExampleIndex: i})}
                            onMouseLeave={() => this.setState({previewExampleIndex: null})}
                            >
                            {i + 1}
                        </button>
                    })}

            }
            var exampleView = null;
            var hasExamples = examples && examples.length > 0
            if (hasExamples) {
                if (this.state.previewExampleIndex === null) {
                    exampleView = <ExampleView example={examples[this.state.exampleIndex]} />
                } else {
                    exampleView = <ExampleView example={examples[this.state.previewExampleIndex]} />
                }
            }
            else {
                exampleView = No value captured, this code didn't run.
            }
            return

                {exampleNav}

                    {exampleView}

        }
        return
no examples

    }
}

class ExampleView extends Component {
    render() {
        return

            <ValueExample key={window.openingId} example={this.props.example} isRoot={true}/>

    }
}

class FunctionPreview extends Component {
    constructor(props){
        super(props)
        this.state = {}
    }
    componentDidMount(){
        var value = this.props.value;
        if (!value.scriptId) {
            this.setState({text: value.text})
        } else {
            fetch("/__jscb/fetchFunctionCode/" + value.scriptId + "/" + value.locationId)
            .then(t => t.json())
            .then(json => this.setState({
                text: json.text,
                url: json.url
            }))
        }
    }
    render(){
        return
            {this.props.value.scriptId ? (<button onClick={() => window.location = this.state.url}>Go to definition</button>
) : null}

{this.state.text ? this.state.text.split(/\n/g).slice(0, 10).join("\n") : null}

    }
}

class StringPreview extends Component {
    constructor(props){
        super(props)
        this.state = {
            isExpanded: false
        }
    }
    render(){
        var val = this.props.value
        var PREVIEW_STRING_LENGTH = 50
        var previewIsTruncated = val.text.length > PREVIEW_STRING_LENGTH
        var toggleButton = null
        var preview = null

        var stringView = null
        if (!this.state.isExpanded) {
            var v = val.text.slice(0, PREVIEW_STRING_LENGTH).replace(/\n/g, "\\n")
            if (previewIsTruncated) {
                v += "..."
            }
            stringView = "{v}"
        } else {
            var fullText = val.text
            var isTruncated = val.length > val.text.length
            if (isTruncated) {
                fullText += "..."
            }
            stringView =

"{fullText}"

        }

        if (previewIsTruncated) {
            toggleButton = <button
                className="toggle-value-detail-button"
                onClick={() => this.setState({isExpanded: !this.state.isExpanded})}>
                {this.state.isExpanded ? "-" : "+"}
            </button>
        } else {
            return stringView
        }

        return

{toggleButton}

{stringView}

    }
}

class Preview extends Component {
    render(){
        var val = this.props.value
        if (typeof val === "number") {
            return {val}
        }
        if (typeof val === "boolean") {
            return {val + ""}
        }
        if (val.type === "Too Deep") {
            return Too deep, no data
        }
        if (val.type === "UI Message") {
            return {val.text}
        }
        if (val.type === "Regular Expression") {
            return {val.value}
        }
        if (val.type === "string") {
            return <StringPreview value={val} />
        }
        if (val.type === "object") {
            return
                (Object)
                {" {" + Object.keys(val.data).join(", ") +"}" }

        }
        if (val.type === "array"){
            return
                (Array) [{val.itemCount}]

        }
        if (val.type === "function") {
            return (Function)
        }
        if (val.type === "undefined") {
            return undefined
        }
        if (val.type === "functionDetail") {
            return <FunctionPreview value={val.fn} />
        }
        if (val.type === "jQuery Object") {
            return
                jQuery Object [{val.elementCount}]

        }
        if (val.type === "HTMLElement") {
            return
                {"<" + val.tagName.toLowerCase() + ">" + val.innerHTML + "<" + val.tagName.toLowerCase() + ">"}

        }
        return (No preview)

{JSON.stringify(val)}

    }
}

class ValueExample extends Component {
    constructor(props) {
        super(props)
        this.state = {
            expandedPaths: []
        }
    }
    render(){
        var example = this.props.example;

        var items = []
        var depth = -1
        var path = []

        console.log("expandedPaths", this.state.expandedPaths)

        var t= this

        function isExpanded(path){
            console.log("isExpanded", path)
            return t.state.expandedPaths.indexOf(path.join(".")) !== -1
        }
        function traverse(e){
            depth++;
            function each(key, val){
                path.push(key)
                var expand = null;
                var canExpand = (val.type === "object" || val.keyCount > 0) ||
                    (val.type === "array" && val.itemCount > 0) ||
                    (val.type === "jQuery Object" && val.elementCount > 0) ||
                    (val.type === "function")
                console.log("val.type", val.type)
                if (canExpand) {
                    expand = {isExpanded(path) ? "▼" : "▶"}
                } else {
                    // keep space free
                    expand = ▼
                }
                let p = path.join(".")
                items.push(
 {
                        var newExpandedPaths = t.state.expandedPaths.slice()
                        if (t.state.expandedPaths.indexOf(p) === -1){
                            newExpandedPaths = newExpandedPaths.concat([p])
                        } else {
                            newExpandedPaths = _.reject(newExpandedPaths, pp => pp === p)
                        }
                        t.setState({expandedPaths: newExpandedPaths})
                    }
                } style={{paddingLeft: (depth + 1) * 20}}>
                    {expand} {key}: <Preview value={val} />

)
                traverse(val)
                path.pop()
            }
            if (e && e.type === "object") {
                if (depth === 0 || isExpanded(path)) {
                    each("constructor", e.konstructor)
                    Object.keys(e.data).forEach(function(key){
                        each(key, e.data[key])
                    })
                    var uncollectedValues = e.keyCount - Object.keys(e.data).length
                    if (uncollectedValues > 0) {
                        each("...", {
                            type: "UI Message",
                            text: "(" + uncollectedValues + " value(s) not collected)"
                        })
                    }
                }
            }
            if (e && e.type === "array") {
                if (depth === 0 || isExpanded(path)) {
                    e.items.forEach(function(item, key){
                        each(key, item)
                    })
                    var uncollectedValues = e.itemCount - e.items.length
                    if (uncollectedValues > 0) {
                        each("...", {
                            type: "UI Message",
                            text: "(" + uncollectedValues + " value(s) not collected)"
                        })
                    }
                }
            }
            if (e && e.type === "jQuery Object") {
                if (depth === 0 || isExpanded(path)) {
                    e.elements.forEach(function(item, key){
                        each(key, item)
                    })
                }
            }
            if (e && e.type === "function") {
                if (depth === 0 || isExpanded(path)) {
                    each("code", {
                        type: "functionDetail",
                        fn: e
                    })
                }
            }

            depth--;
        }
        traverse(example)
        // console.log("items", items)
        return

            {this.props.isRoot ? <Preview value={example} /> : null}
            {items}

    }
}

var overlay = document.getElementById("overlay")
overlay.style.display = "none"
var overlayComp = <OverlayContent />
window.overlayComop = overlayComp
render(overlayComp, overlay)

document.querySelectorAll("[data-value-id]").forEach(function(el){
    var valId = el.getAttribute("data-value-id")
    var vals = window.values[valId]

    if (!vals) {
        vals = []
    }
    if (vals.length ===0) {
        if (el.style.backgroundColor === "red") {
            el.style.backgroundColor = "gray"
        }
        el.style.borderBottom ="1px solid lime"
    }
})

var enteredOverlay = false
var shouldHideOverlaySoon = true
overlay.addEventListener("mouseenter", function(e){
    console.log("mouseenter", e.target)
    enteredOverlay = true;
    setTimeout(function(){
        enteredOverlay = false
    }, 500)
    shouldHideOverlaySoon = false
})
overlay.addEventListener("mouseleave", function(e){
    console.log("mouseleave", e.target)
    shouldHideOverlaySoon = true
    setTimeout(function(){
        if (shouldHideOverlaySoon) {
            overlay.style.display = "none"
        }
    }, 1000)
})

var lastEnteredId = null
document.body.addEventListener("mouseover", function(e){

    var el = e.target
    // console.log(el)
    var match = el.className.match(/value-([0-9]+)/)
    if (match === null) {
        return
    }
    console.log("mouseover", e.target)

    var valId = parseFloat(match[1])
    lastEnteredId = valId
    var overlay = document.getElementById("overlay")
    overlay.style.display = "block"
    overlay.setAttribute("style",
        "top: " + (el.getBoundingClientRect().top + window.scrollY + 12) +
        "px; left: " + (el.getBoundingClientRect().left) + "px"
        + ";position: absolute;padding-top: 8px;"
    )

    setState(valId)

})

document.body.addEventListener("mouseleave", function(e){
    console.log("mouseleave2", e.target)
    var el = e.target
    if (el.className.indexOf("value") === -1) {
        return
    }
    var valId = el.className.split(" ").filter(c => c.indexOf("value-") !== -1)[0].replace(/[^0-9]/g,"")
    if (valId !== lastEnteredId) {
        return;
    }
    {/*console.log(el)*/}
    var valId = el.getAttribute("data-value-id")
    var overlay = document.getElementById("overlay")
    setTimeout(function(){
        if (!enteredOverlay) {
            overlay.style.display = "none"
        }
    }, 400)

})<|endoftext|>