<commit_before>(function(jQuery) {

  var $ = jQuery;
  var GBROWSE = '/gbrowse_phavu1.0?query=ref=Pv04;start=15056944;stop=15058034;add=Pv04+Marker+BM199+15056944..15057534;h_feat=BM199@yellow;style=Marker+bgcolor=red';
  var FOCUS_TRAIT_TERM = 'Seed yield';
  var FOCUS_TRAIT = 'phavu.Seed-yield-2-6';
  var SELECTOR = {
    welcome: '#site-name',
    searchBtn: "[href='/search/qtl']",
    viewContent: '.view-content',
    editQtlName: '#edit-qtl-name',
    editQtlSubmit: '#edit-submit-qtl',
    searchResult: '[href="/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT+'"]',
    detailsPane: "[href='?pane=qtl_details']",
    positionsPane: "[href='?pane=positions']",
    nearestMarker: "#tripal_feature-table-base > tbody > tr:nth-child(2) > td > a",
    gbrowseLink: "[href='/gbrowse_phavu1.0?query=ref=Pv04;start=15056944;stop=15058034;add=Pv04+Marker+BM199+15056944..15057534;h_feat=BM199@yellow;style=Marker+bgcolor=red']",
    gbrowseFrame: '#frameviewer',
  };
  var tour = new Tour({
    name: 'qtl-search-to-gbrowse',
    debug: true,
    orphan: true,
    steps : [
      {
          title: 'QTL Tour: Welcome to LIS!',
          content: 'Let\'s go the legumeinfo.org homepage, where the QTL Tour will begin.
Use the Next button or → (right arrow key) to advance the tour. Use the Prev button or ← (left arrow key) to step back.',
          placement: 'bottom',
          element: SELECTOR.welcome,
          reflex: true,
      }, {
          path: '/',
          title: 'QTL Tour: Getting started',
          content: 'This tour will provide an example of navigating LIS from the genetic location of a published QTL to the associated region of the annotated genome for the species in which it was found.
 Now press the QTL Search button, or use the Next button or press →.',
          placement: 'bottom',
          element: SELECTOR.searchBtn,
          reflex: true,
      }, {
          path: '/search/qtl',
          title: 'QTL Tour: QTL Search',
          content: 'All of the QTLs that have been curated into LIS from the literature are displayed in the paged results below, and can be filtered using the search fields above.',
          placement: 'top',
          element: SELECTOR.viewContent,
          reflex: true,
      }, {
          title: 'QTL Tour: QTL Search',
          content: 'We entered "'+FOCUS_TRAIT_TERM+'" in the QTL name field. This reflects the standardized trait ontology used by the curators. Now press Next or →',
          placement: 'bottom',
          element: SELECTOR.editQtlName,
          reflex: true,
          onShown: function(tour) {
            $(SELECTOR.editQtlName)[0].value=FOCUS_TRAIT_TERM;
          },
      }, {
          title: 'QTL Tour: QTL Search',
          content: 'Then click "Apply" to apply the specified filter to the QTL in the result.',
          placement: 'bottom',
          element: SELECTOR.editQtlSubmit,
          reflex: true,
          onNext: function() {
            $(SELECTOR.editQtlSubmit)[0].click();
          }
      }, {
        title: 'QTL Tour: QTL Search',
        content: 'Please be patient, as we wait for the query results to be returned...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          if(tour.skipStep) {
            tour.skipStep = false;
            tour.prev();
            return;
          }
          var promise = lisTours.waitForContent(
            tour,
            function() {
              return $('tr.views-row-first td.views-field-qtl-name:contains("'+FOCUS_TRAIT_TERM+'")')[0];
            });
          // advance automatically to next step when done loading
          promise.then(function() {
            tour.next();
          });
          return promise;
        }
      }, {
          path: '/search/qtl',
          title: 'QTL Tour: The list of QTL matching the query',
          content: 'Let\'s look at the details for a specific QTL.',
          element: SELECTOR.searchResult,
          reflex: true,
          placement: 'bottom',
          onPrev: function(tour) {
            tour.skipStep = true;
          }
      },
      {
          path: '/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT,
          title: 'QTL Tour: Information about the selected QTL',
          content: "The QTL Details link will reveal this QTL's place on the chromosome.",
          placement: 'right',
          element: SELECTOR.detailsPane,
          reflex: true,
          onNext: function(tour) {
            var el = $(SELECTOR.detailsPane)[0];
            if(el) {
              el.click();
            }
          }
      }, {
        path: '/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT+'#pane=qtl_details',
        title: 'QTL Tour: Nearest Marker',
        content: 'This is the marker that had the strongest association with variation in the trait for this QTL, among those used in the mapping experiment. Since the marker has sequence information associated with it, we can find its position in the genome sequence to find the general region in which the gene responsible for the QTL may be found- note, however that the marker is not guaranteed to be very close to any candidate gene, and you should use this only as a very general guide.',
        placement: 'right',
        element: SELECTOR.nearestMarker,
        reflex: true,
        onShow: function(tour) {
          if(location.hash.indexOf('qtl_details') === -1) {
            var el = $(SELECTOR.detailsPane)[0];
            if(el) {
              el.click();
            }
          }
        }
      }, {
        path: '/node/1360783', /* url must match prev reflex element url */
        title: 'QTL Tour: Marker Overview',
        content: 'The "Overview" links to articles and descriptions of the marker. To find this marker on the phaseolus map, we can look under "Marker Positions".',
        element: SELECTOR.positionsPane,
        reflex: true,
        placement: 'bottom',
        onNext: function(tour) {
          var el = $(SELECTOR.positionsPane)[0];
          if(el) {
            el.click();
          }
        }
      }, {
        path: '/node/1360783#pane=positions',
        title: 'QTL Tour: Genome Browser',
        content: 'The linked GBrowse map will show you annotations on the genome.',
        element: SELECTOR.gbrowseLink,
        reflex: true,
        placement: 'top',
        onShow: function(tour) {
          if(location.hash.indexOf('positions') === -1) {
            var el = $(SELECTOR.positionsPane)[0];
            if(el) {
              el.click();
            }
          }
        }
      }, {
        path: GBROWSE,
        title: 'QTL Tour: GBrowse',
        content: 'Loading GBrowse...',
        placement: 'top',
        onShown: function(tour) {
          // wait for dynamic content with a loading dialog.
              $('.popover-navigation div').hide();
          if(tour.skipStep) {
            tour.skipStep = false;
            tour.prev();
            return;
          }
          var promise = lisTours.waitForContent(
            tour,
            function() {
              return $(SELECTOR.gbrowseFrame).contents().find('#centromere_image')[0];
            });
          // advance automatically to next step when done loading
          promise.then(function() {
            tour.next();
          });
          return promise;
        }
      }, {
        title: 'QTL Tour: GBrowse',
        content: 'GBrowse allows you to visualize features of biological significance that have been located on reference genomes, for example annotated genes or syntenic relationships to other legume genomes. The red bar shows us the position of the marker associated with our search QTL.',
        element: SELECTOR.gbrowseFrame,
        placement: 'top',
        onPrev: function(tour) {
          tour.skipStep = true;
        },
        onNext: function() {
          $(SELECTOR.gbrowseFrame).contents().find('select.searchtitle').val(5000000).change();
        }
      }, {
        title: 'QTL Tour: GBrowse Navigation',
        content: 'Zooming out will give you better sense for the genomic neighborhood in which the marker resides. We\'re right at the edge of some conserved syntenic blocks. We also see that the loss of synteny corresponds to our entrance into a region relatively poor in annotated gene content on the edge of the centromere.',
        element: SELECTOR.gbrowseFrame,
        placement: 'top',
      }, {
        title: 'QTL Tour: GBrowse Settings',
        content: 'You can rearrange tracks by dragging them, or choose which tracks to display through the navigation bar (Select Tracks).',
        element: SELECTOR.gbrowseFrame,
        placement: 'top'
      }, {
        title: 'QTL Tour: Completed',
        content: 'Congratulations, you have finished the QTL Tour! Summary: We navigated LIS from the genetic location of a published QTL to the associated region of the annotated genome for Phaseolus Vulgaris. Now press End Tour.'
      }
    ]
  });

  lisTours.register(tour);

}(window.__jquery));
<commit_msg>Add default template; turn off debug.<commit_after>(function(jQuery) {

  var $ = jQuery;
  var GBROWSE = '/gbrowse_phavu1.0?query=ref=Pv04;start=15056944;stop=15058034;add=Pv04+Marker+BM199+15056944..15057534;h_feat=BM199@yellow;style=Marker+bgcolor=red';
  var FOCUS_TRAIT_TERM = 'Seed yield';
  var FOCUS_TRAIT = 'phavu.Seed-yield-2-6';
  var SELECTOR = {
    welcome: '#site-name',
    searchBtn: "[href='/search/qtl']",
    viewContent: '.view-content',
    editQtlName: '#edit-qtl-name',
    editQtlSubmit: '#edit-submit-qtl',
    searchResult: '[href="/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT+'"]',
    detailsPane: "[href='?pane=qtl_details']",
    positionsPane: "[href='?pane=positions']",
    nearestMarker: "#tripal_feature-table-base > tbody > tr:nth-child(2) > td > a",
    gbrowseLink: "[href='/gbrowse_phavu1.0?query=ref=Pv04;start=15056944;stop=15058034;add=Pv04+Marker+BM199+15056944..15057534;h_feat=BM199@yellow;style=Marker+bgcolor=red']",
    gbrowseFrame: '#frameviewer',
  };
  var tour = new Tour({
    name: 'qtl-search-to-gbrowse',
    //debug: true,
    template: lisTours.template.defaultTemplate,
    orphan: true,
    steps : [
      {
          title: 'QTL Tour: Welcome to LIS!',
          content: 'Let\'s go the legumeinfo.org homepage, where the QTL Tour will begin.
Use the Next button or → (right arrow key) to advance the tour. Use the Prev button or ← (left arrow key) to step back.',
          placement: 'bottom',
          element: SELECTOR.welcome,
          reflex: true,
      }, {
          path: '/',
          title: 'QTL Tour: Getting started',
          content: 'This tour will provide an example of navigating LIS from the genetic location of a published QTL to the associated region of the annotated genome for the species in which it was found.
 Now press the QTL Search button, or use the Next button or press →.',
          placement: 'bottom',
          element: SELECTOR.searchBtn,
          reflex: true,
      }, {
          path: '/search/qtl',
          title: 'QTL Tour: QTL Search',
          content: 'All of the QTLs that have been curated into LIS from the literature are displayed in the paged results below, and can be filtered using the search fields above.',
          placement: 'top',
          element: SELECTOR.viewContent,
          reflex: true,
      }, {
          title: 'QTL Tour: QTL Search',
          content: 'We entered "'+FOCUS_TRAIT_TERM+'" in the QTL name field. This reflects the standardized trait ontology used by the curators. Now press Next or →',
          placement: 'bottom',
          element: SELECTOR.editQtlName,
          reflex: true,
          onShown: function(tour) {
            $(SELECTOR.editQtlName)[0].value=FOCUS_TRAIT_TERM;
          },
      }, {
          title: 'QTL Tour: QTL Search',
          content: 'Then click "Apply" to apply the specified filter to the QTL in the result.',
          placement: 'bottom',
          element: SELECTOR.editQtlSubmit,
          reflex: true,
          onNext: function() {
            $(SELECTOR.editQtlSubmit)[0].click();
          }
      }, {
        title: 'QTL Tour: QTL Search',
        content: 'Please be patient, as we wait for the query results to be returned...',
        placement: 'top',
        onShown: function(tour) {
          $('.popover-navigation div').hide();
          // wait for dynamic content with a loading dialog.
          if(tour.skipStep) {
            tour.skipStep = false;
            tour.prev();
            return;
          }
          var promise = lisTours.waitForContent(
            tour,
            function() {
              return $('tr.views-row-first td.views-field-qtl-name:contains("'+FOCUS_TRAIT_TERM+'")')[0];
            });
          // advance automatically to next step when done loading
          promise.then(function() {
            tour.next();
          });
          return promise;
        }
      }, {
          path: '/search/qtl',
          title: 'QTL Tour: The list of QTL matching the query',
          content: 'Let\'s look at the details for a specific QTL.',
          element: SELECTOR.searchResult,
          reflex: true,
          placement: 'bottom',
          onPrev: function(tour) {
            tour.skipStep = true;
          }
      },
      {
          path: '/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT,
          title: 'QTL Tour: Information about the selected QTL',
          content: "The QTL Details link will reveal this QTL's place on the chromosome.",
          placement: 'right',
          element: SELECTOR.detailsPane,
          reflex: true,
          onNext: function(tour) {
            var el = $(SELECTOR.detailsPane)[0];
            if(el) {
              el.click();
            }
          }
      }, {
        path: '/feature/Phaseolus/vulgaris/QTL/'+FOCUS_TRAIT+'#pane=qtl_details',
        title: 'QTL Tour: Nearest Marker',
        content: 'This is the marker that had the strongest association with variation in the trait for this QTL, among those used in the mapping experiment. Since the marker has sequence information associated with it, we can find its position in the genome sequence to find the general region in which the gene responsible for the QTL may be found- note, however that the marker is not guaranteed to be very close to any candidate gene, and you should use this only as a very general guide.',
        placement: 'right',
        element: SELECTOR.nearestMarker,
        reflex: true,
        onShow: function(tour) {
          if(location.hash.indexOf('qtl_details') === -1) {
            var el = $(SELECTOR.detailsPane)[0];
            if(el) {
              el.click();
            }
          }
        }
      }, {
        path: '/node/1360783', /* url must match prev reflex element url */
        title: 'QTL Tour: Marker Overview',
        content: 'The "Overview" links to articles and descriptions of the marker. To find this marker on the phaseolus map, we can look under "Marker Positions".',
        element: SELECTOR.positionsPane,
        reflex: true,
        placement: 'bottom',
        onNext: function(tour) {
          var el = $(SELECTOR.positionsPane)[0];
          if(el) {
            el.click();
          }
        }
      }, {
        path: '/node/1360783#pane=positions',
        title: 'QTL Tour: Genome Browser',
        content: 'The linked GBrowse map will show you annotations on the genome.',
        element: SELECTOR.gbrowseLink,
        reflex: true,
        placement: 'top',
        onShow: function(tour) {
          if(location.hash.indexOf('positions') === -1) {
            var el = $(SELECTOR.positionsPane)[0];
            if(el) {
              el.click();
            }
          }
        }
      }, {
        path: GBROWSE,
        title: 'QTL Tour: GBrowse',
        content: 'Loading GBrowse...',
        placement: 'top',
        onShown: function(tour) {
          // wait for dynamic content with a loading dialog.
              $('.popover-navigation div').hide();
          if(tour.skipStep) {
            tour.skipStep = false;
            tour.prev();
            return;
          }
          var promise = lisTours.waitForContent(
            tour,
            function() {
              return $(SELECTOR.gbrowseFrame).contents().find('#centromere_image')[0];
            });
          // advance automatically to next step when done loading
          promise.then(function() {
            tour.next();
          });
          return promise;
        }
      }, {
        title: 'QTL Tour: GBrowse',
        content: 'GBrowse allows you to visualize features of biological significance that have been located on reference genomes, for example annotated genes or syntenic relationships to other legume genomes. The red bar shows us the position of the marker associated with our search QTL.',
        element: SELECTOR.gbrowseFrame,
        placement: 'top',
        onPrev: function(tour) {
          tour.skipStep = true;
        },
        onNext: function() {
          $(SELECTOR.gbrowseFrame).contents().find('select.searchtitle').val(5000000).change();
        }
      }, {
        title: 'QTL Tour: GBrowse Navigation',
        content: 'Zooming out will give you better sense for the genomic neighborhood in which the marker resides. We\'re right at the edge of some conserved syntenic blocks. We also see that the loss of synteny corresponds to our entrance into a region relatively poor in annotated gene content on the edge of the centromere.',
        element: SELECTOR.gbrowseFrame,
        placement: 'top',
      }, {
        title: 'QTL Tour: GBrowse Settings',
        content: 'You can rearrange tracks by dragging them, or choose which tracks to display through the navigation bar (Select Tracks).',
        element: SELECTOR.gbrowseFrame,
        placement: 'top'
      }, {
        title: 'QTL Tour: Completed',
        content: 'Congratulations, you have finished the QTL Tour! Summary: We navigated LIS from the genetic location of a published QTL to the associated region of the annotated genome for Phaseolus Vulgaris. Now press End Tour.'
      }
    ]
  });

  lisTours.register(tour);

}(window.__jquery));
<|endoftext|>


<commit_before>/** @jsx React.DOM */
var util = require('./nav-util');

// FIXME use util to DRY up with side-nav-methods
module.exports = React.createClass({
  mixins: ['modelAware', 'events'],

  getInitialState: function() {
    return {};
  },

  render: function() {
    var project = this.getModel();
    var apis = {};

    project.packages.each(function(pkg) {
      var apiName = pkg.parent.name;
      apis[apiName] = apis[apiName] || [];
      apis[apiName].push(pkg);
    });
    var children = util.filteredNavChildren(apis, 'packages', 'package', this);

    var startingLevel = 1;
    if (children.length === 1) {
      // the api type is assumed since there is only 1
      children = children[0].children;
      startingLevel = 2;
    }
    this.state.children = children;

    var menu = util.projectNavMenu(children, this, this.props.viewState, {snippet: true, allowHilight: true, startingLevel: startingLevel});
    var filter = util.filter('package', this);
    return (

              <input type="text" ref="search" placeholder="Search..." onChange={filter} onKeyUp={filter}/>

        {menu}

    );
  },

  componentDidMount: function() {
    $(this.refs.search.getDOMNode()).focus();
  }
});
<commit_msg>package name fix<commit_after>/** @jsx React.DOM */
var util = require('./nav-util');

// FIXME use util to DRY up with side-nav-methods
module.exports = React.createClass({
  mixins: ['modelAware', 'events'],

  getInitialState: function() {
    return {};
  },

  render: function() {
    var project = this.getModel();
    var apis = {};

    project.packages.each(function(pkg) {
      var apiName = pkg.parent.name;
      apis[apiName] = apis[apiName] || [];
      apis[apiName].push(pkg);
    });
    var children = util.filteredNavChildren(apis, 'package', 'packages', this);

    var startingLevel = 1;
    if (children.length === 1) {
      // the api type is assumed since there is only 1
      children = children[0].children;
      startingLevel = 2;
    }
    this.state.children = children;

    var menu = util.projectNavMenu(children, this, this.props.viewState, {snippet: true, allowHilight: true, startingLevel: startingLevel});
    var filter = util.filter('package', this);
    return (

              <input type="text" ref="search" placeholder="Search..." onChange={filter} onKeyUp={filter}/>

        {menu}

    );
  },

  componentDidMount: function() {
    $(this.refs.search.getDOMNode()).focus();
  }
});
<|endoftext|>


<commit_before>/** @jsx React.DOM */

var React = require('react');

var ActivitiesPage = React.createClass({displayName: 'ActivitiesPage',
    render: function () {
        return (
            React.DOM.div(null, "Activities page")
            );
    }
});

module.exports = ActivitiesPage;<commit_msg>Delete ActivitiesPage.js<commit_after><|endoftext|>


<commit_before>let tree;

(async () => {
  const scriptURL = document.currentScript.getAttribute('src');
  const codeInput = document.getElementById('code-input');
  const languageSelect = document.getElementById('language-select');
  const loggingCheckbox = document.getElementById('logging-checkbox');
  const outputContainer = document.getElementById('output-container');
  const outputContainerScroll = document.getElementById('output-container-scroll');
  const updateTimeSpan = document.getElementById('update-time');
  const demoContainer = document.getElementById('playground-container');
  const languagesByName = {};

  await TreeSitter.init();

  const parser = new TreeSitter();
  const codeEditor = CodeMirror.fromTextArea(codeInput, {
    lineNumbers: true,
    showCursorWhenSelecting: true
  });
  const cluster = new Clusterize({
    rows: [],
    noDataText: null,
    contentElem: outputContainer,
    scrollElem: outputContainerScroll
  });
  const renderTreeOnCodeChange = debounce(renderTree, 50);

  let languageName = languageSelect.value;
  let treeRows = null;
  let treeRowHighlightedIndex = -1;
  let parseCount = 0;
  let isRendering = 0;

  codeEditor.on('changes', handleCodeChange);
  codeEditor.on('cursorActivity', debounce(handleCursorMovement, 150));
  loggingCheckbox.addEventListener('change', handleLoggingChange);
  languageSelect.addEventListener('change', handleLanguageChange);
  outputContainer.addEventListener('click', handleTreeClick);

  await handleLanguageChange()

  demoContainer.style.visibility = 'visible';

  async function handleLanguageChange() {
    const newLanguageName = languageSelect.value;
    if (!languagesByName[newLanguageName]) {
      const url = `${LANGUAGE_BASE_URL}/tree-sitter-${newLanguageName}.wasm`
      languageSelect.disabled = true;
      try {
        languagesByName[newLanguageName] = await TreeSitter.Language.load(url);
      } catch (e) {
        console.error(e);
        languageSelect.value = languageName;
        return
      } finally {
        languageSelect.disabled = false;
      }
    }

    tree = null;
    languageName = newLanguageName;
    parser.setLanguage(languagesByName[newLanguageName]);
    handleCodeChange();
  }

  async function handleCodeChange(editor, changes) {
    let start;
    if (tree && changes) {
      start = performance.now();
      for (const change of changes) {
        const edit = treeEditForEditorChange(change);
        tree.edit(edit);
      }
    } else {
      start = performance.now();
    }
    const newTree = parser.parse(codeEditor.getValue() + '\n', tree);
    const duration = (performance.now() - start).toFixed(1);
    updateTimeSpan.innerText = `${duration} ms`;
    if (tree) tree.delete();
    tree = newTree;
    parseCount++;
    renderTreeOnCodeChange();
  }

  async function renderTree() {
    isRendering++;
    const cursor = tree.walk();

    let currentRenderCount = parseCount;
    let row = '';
    let rows = [];
    let finishedRow = false;
    let visitedChildren = false;
    let indentLevel = 0;

    for (let i = 0;; i++) {
      if (i > 0 && i % 10000 === 0) {
        await new Promise(r => setTimeout(r, 0));
        if (parseCount !== currentRenderCount) {
          cursor.delete();
          isRendering--;
          return;
        }
      }

      let displayName;
      if (cursor.nodeIsMissing) {
        displayName = `MISSING ${cursor.nodeType}`
      } else if (cursor.nodeIsNamed) {
        displayName = cursor.nodeType;
      }

      if (visitedChildren) {
        if (displayName) {
          finishedRow = true;
        }

        if (cursor.gotoNextSibling()) {
          visitedChildren = false;
        } else if (cursor.gotoParent()) {
          visitedChildren = true;
          indentLevel--;
        } else {
          break;
        }
      } else {
        if (displayName) {
          if (finishedRow) {
            row += '
';
            rows.push(row);
            finishedRow = false;
          }
          const start = cursor.startPosition;
          const end = cursor.endPosition;
          const id = cursor.nodeId;
          let fieldName = cursor.currentFieldName();
          if (fieldName) {
            fieldName += ': ';
          } else {
            fieldName = '';
          }
          row = `
${'  '.repeat(indentLevel)}${fieldName}${displayName} [${start.row}, ${start.column}] - [${end.row}, ${end.column}])`;
          finishedRow = true;
        }

        if (cursor.gotoFirstChild()) {
          visitedChildren = false;
          indentLevel++;
        } else {
          visitedChildren = true;
        }
      }
    }
    if (finishedRow) {
      row += '
';
      rows.push(row);
    }

    cursor.delete();
    cluster.update(rows);
    treeRows = rows;
    isRendering--;
    handleCursorMovement();
  }

  function handleCursorMovement() {
    if (isRendering) return;

    const selection = codeEditor.getDoc().listSelections()[0];
    let start = {row: selection.anchor.line, column: selection.anchor.ch};
    let end = {row: selection.head.line, column: selection.head.ch};
    if (
      start.row > end.row ||
      (
        start.row === end.row &&
        start.column > end.column
      )
    ) {
      let swap = end;
      end = start;
      start = swap;
    }
    const node = tree.rootNode.namedDescendantForPosition(start, end);
    if (treeRows) {
      if (treeRowHighlightedIndex !== -1) {
        const row = treeRows[treeRowHighlightedIndex];
        if (row) treeRows[treeRowHighlightedIndex] = row.replace('highlighted', 'plain');
      }
      treeRowHighlightedIndex = treeRows.findIndex(row => row.includes(`data-id=${node.id}`));
      if (treeRowHighlightedIndex !== -1) {
        const row = treeRows[treeRowHighlightedIndex];
        if (row) treeRows[treeRowHighlightedIndex] = row.replace('plain', 'highlighted');
      }
      cluster.update(treeRows);
      const lineHeight = cluster.options.item_height;
      const scrollTop = outputContainerScroll.scrollTop;
      const containerHeight = outputContainerScroll.clientHeight;
      const offset = treeRowHighlightedIndex * lineHeight;
      if (scrollTop > offset - 20) {
        $(outputContainerScroll).animate({scrollTop: offset - 20}, 150);
      } else if (scrollTop < offset + lineHeight + 40 - containerHeight) {
        $(outputContainerScroll).animate({scrollTop: offset - containerHeight + 40}, 150);
      }
    }
  }

  function handleTreeClick(event) {
    if (event.target.tagName === 'A') {
      event.preventDefault();
      const [startRow, startColumn, endRow, endColumn] = event
        .target
        .dataset
        .range
        .split(',')
        .map(n => parseInt(n));
      codeEditor.focus();
      codeEditor.setSelection(
        {line: startRow, ch: startColumn},
        {line: endRow, ch: endColumn}
      );
    }
  }

  function handleLoggingChange() {
    if (loggingCheckbox.checked) {
      parser.setLogger((message, lexing) => {
        if (lexing) {
          console.log("  ", message)
        } else {
          console.log(message)
        }
      });
    } else {
      parser.setLogger(null);
    }
  }

  function treeEditForEditorChange(change) {
    const oldLineCount = change.removed.length;
    const newLineCount = change.text.length;
    const lastLineLength = change.text[newLineCount - 1].length;

    const startPosition = {row: change.from.line, column: change.from.ch};
    const oldEndPosition = {row: change.to.line, column: change.to.ch};
    const newEndPosition = {
      row: startPosition.row + newLineCount - 1,
      column: newLineCount === 1
        ? startPosition.column + lastLineLength
        : lastLineLength
    };

    const startIndex = codeEditor.indexFromPos(change.from);
    let newEndIndex = startIndex + newLineCount - 1;
    let oldEndIndex = startIndex + oldLineCount - 1;
    for (let i = 0; i < newLineCount; i++) newEndIndex += change.text[i].length;
    for (let i = 0; i < oldLineCount; i++) oldEndIndex += change.removed[i].length;

    return {
      startIndex, oldEndIndex, newEndIndex,
      startPosition, oldEndPosition, newEndPosition
    };
  }

  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  }
})();
<commit_msg>web playground: don't include editor.getValue() call in parse time<commit_after>let tree;

(async () => {
  const scriptURL = document.currentScript.getAttribute('src');
  const codeInput = document.getElementById('code-input');
  const languageSelect = document.getElementById('language-select');
  const loggingCheckbox = document.getElementById('logging-checkbox');
  const outputContainer = document.getElementById('output-container');
  const outputContainerScroll = document.getElementById('output-container-scroll');
  const updateTimeSpan = document.getElementById('update-time');
  const demoContainer = document.getElementById('playground-container');
  const languagesByName = {};

  await TreeSitter.init();

  const parser = new TreeSitter();
  const codeEditor = CodeMirror.fromTextArea(codeInput, {
    lineNumbers: true,
    showCursorWhenSelecting: true
  });
  const cluster = new Clusterize({
    rows: [],
    noDataText: null,
    contentElem: outputContainer,
    scrollElem: outputContainerScroll
  });
  const renderTreeOnCodeChange = debounce(renderTree, 50);

  let languageName = languageSelect.value;
  let treeRows = null;
  let treeRowHighlightedIndex = -1;
  let parseCount = 0;
  let isRendering = 0;

  codeEditor.on('changes', handleCodeChange);
  codeEditor.on('cursorActivity', debounce(handleCursorMovement, 150));
  loggingCheckbox.addEventListener('change', handleLoggingChange);
  languageSelect.addEventListener('change', handleLanguageChange);
  outputContainer.addEventListener('click', handleTreeClick);

  await handleLanguageChange()

  demoContainer.style.visibility = 'visible';

  async function handleLanguageChange() {
    const newLanguageName = languageSelect.value;
    if (!languagesByName[newLanguageName]) {
      const url = `${LANGUAGE_BASE_URL}/tree-sitter-${newLanguageName}.wasm`
      languageSelect.disabled = true;
      try {
        languagesByName[newLanguageName] = await TreeSitter.Language.load(url);
      } catch (e) {
        console.error(e);
        languageSelect.value = languageName;
        return
      } finally {
        languageSelect.disabled = false;
      }
    }

    tree = null;
    languageName = newLanguageName;
    parser.setLanguage(languagesByName[newLanguageName]);
    handleCodeChange();
  }

  async function handleCodeChange(editor, changes) {
    const newText = codeEditor.getValue() + '\n';

    const start = performance.now();
    if (tree && changes) {
      for (const change of changes) {
        tree.edit(treeEditForEditorChange(change));
      }
    }
    const newTree = parser.parse(newText, tree);
    const duration = (performance.now() - start).toFixed(1);

    updateTimeSpan.innerText = `${duration} ms`;
    if (tree) tree.delete();
    tree = newTree;
    parseCount++;
    renderTreeOnCodeChange();
  }

  async function renderTree() {
    isRendering++;
    const cursor = tree.walk();

    let currentRenderCount = parseCount;
    let row = '';
    let rows = [];
    let finishedRow = false;
    let visitedChildren = false;
    let indentLevel = 0;

    for (let i = 0;; i++) {
      if (i > 0 && i % 10000 === 0) {
        await new Promise(r => setTimeout(r, 0));
        if (parseCount !== currentRenderCount) {
          cursor.delete();
          isRendering--;
          return;
        }
      }

      let displayName;
      if (cursor.nodeIsMissing) {
        displayName = `MISSING ${cursor.nodeType}`
      } else if (cursor.nodeIsNamed) {
        displayName = cursor.nodeType;
      }

      if (visitedChildren) {
        if (displayName) {
          finishedRow = true;
        }

        if (cursor.gotoNextSibling()) {
          visitedChildren = false;
        } else if (cursor.gotoParent()) {
          visitedChildren = true;
          indentLevel--;
        } else {
          break;
        }
      } else {
        if (displayName) {
          if (finishedRow) {
            row += '
';
            rows.push(row);
            finishedRow = false;
          }
          const start = cursor.startPosition;
          const end = cursor.endPosition;
          const id = cursor.nodeId;
          let fieldName = cursor.currentFieldName();
          if (fieldName) {
            fieldName += ': ';
          } else {
            fieldName = '';
          }
          row = `
${'  '.repeat(indentLevel)}${fieldName}${displayName} [${start.row}, ${start.column}] - [${end.row}, ${end.column}])`;
          finishedRow = true;
        }

        if (cursor.gotoFirstChild()) {
          visitedChildren = false;
          indentLevel++;
        } else {
          visitedChildren = true;
        }
      }
    }
    if (finishedRow) {
      row += '
';
      rows.push(row);
    }

    cursor.delete();
    cluster.update(rows);
    treeRows = rows;
    isRendering--;
    handleCursorMovement();
  }

  function handleCursorMovement() {
    if (isRendering) return;

    const selection = codeEditor.getDoc().listSelections()[0];
    let start = {row: selection.anchor.line, column: selection.anchor.ch};
    let end = {row: selection.head.line, column: selection.head.ch};
    if (
      start.row > end.row ||
      (
        start.row === end.row &&
        start.column > end.column
      )
    ) {
      let swap = end;
      end = start;
      start = swap;
    }
    const node = tree.rootNode.namedDescendantForPosition(start, end);
    if (treeRows) {
      if (treeRowHighlightedIndex !== -1) {
        const row = treeRows[treeRowHighlightedIndex];
        if (row) treeRows[treeRowHighlightedIndex] = row.replace('highlighted', 'plain');
      }
      treeRowHighlightedIndex = treeRows.findIndex(row => row.includes(`data-id=${node.id}`));
      if (treeRowHighlightedIndex !== -1) {
        const row = treeRows[treeRowHighlightedIndex];
        if (row) treeRows[treeRowHighlightedIndex] = row.replace('plain', 'highlighted');
      }
      cluster.update(treeRows);
      const lineHeight = cluster.options.item_height;
      const scrollTop = outputContainerScroll.scrollTop;
      const containerHeight = outputContainerScroll.clientHeight;
      const offset = treeRowHighlightedIndex * lineHeight;
      if (scrollTop > offset - 20) {
        $(outputContainerScroll).animate({scrollTop: offset - 20}, 150);
      } else if (scrollTop < offset + lineHeight + 40 - containerHeight) {
        $(outputContainerScroll).animate({scrollTop: offset - containerHeight + 40}, 150);
      }
    }
  }

  function handleTreeClick(event) {
    if (event.target.tagName === 'A') {
      event.preventDefault();
      const [startRow, startColumn, endRow, endColumn] = event
        .target
        .dataset
        .range
        .split(',')
        .map(n => parseInt(n));
      codeEditor.focus();
      codeEditor.setSelection(
        {line: startRow, ch: startColumn},
        {line: endRow, ch: endColumn}
      );
    }
  }

  function handleLoggingChange() {
    if (loggingCheckbox.checked) {
      parser.setLogger((message, lexing) => {
        if (lexing) {
          console.log("  ", message)
        } else {
          console.log(message)
        }
      });
    } else {
      parser.setLogger(null);
    }
  }

  function treeEditForEditorChange(change) {
    const oldLineCount = change.removed.length;
    const newLineCount = change.text.length;
    const lastLineLength = change.text[newLineCount - 1].length;

    const startPosition = {row: change.from.line, column: change.from.ch};
    const oldEndPosition = {row: change.to.line, column: change.to.ch};
    const newEndPosition = {
      row: startPosition.row + newLineCount - 1,
      column: newLineCount === 1
        ? startPosition.column + lastLineLength
        : lastLineLength
    };

    const startIndex = codeEditor.indexFromPos(change.from);
    let newEndIndex = startIndex + newLineCount - 1;
    let oldEndIndex = startIndex + oldLineCount - 1;
    for (let i = 0; i < newLineCount; i++) newEndIndex += change.text[i].length;
    for (let i = 0; i < oldLineCount; i++) oldEndIndex += change.removed[i].length;

    return {
      startIndex, oldEndIndex, newEndIndex,
      startPosition, oldEndPosition, newEndPosition
    };
  }

  function debounce(func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      var callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  }
})();
<|endoftext|>


<commit_before>import 'vtk.js/Sources/favicon';

import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkAxesActor from 'vtk.js/Sources/Rendering/Core/AxesActor';
import vtkConeSource from 'vtk.js/Sources/Filters/Sources/ConeSource';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkInteractorStyleUnicam from 'vtk.js/Sources/Interaction/Style/InteractorStyleUnicam';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkMouseCameraTrackballZoomToMouseManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballZoomToMouseManipulator';
import vtkOrientationMarkerWidget from 'vtk.js/Sources/Interaction/Widgets/OrientationMarkerWidget';

import controlPanel from './controlPanel.html';

// ----------------------------------------------------------------------------
// Renderer setup
// ----------------------------------------------------------------------------

const fullScreenRenderWindow = vtkFullScreenRenderWindow.newInstance({
  background: [0, 0, 0],
});
const renderWindow = fullScreenRenderWindow.getRenderWindow();
const renderer = fullScreenRenderWindow.getRenderer();
fullScreenRenderWindow.addController(controlPanel);

// ----------------------------------------------------------------------------
// Interactor style setup
// ----------------------------------------------------------------------------

const interactorStyle = vtkInteractorStyleUnicam.newInstance();
interactorStyle.setWorldUpVec([0, 1, 0]);
interactorStyle.addMouseManipulator(
  vtkMouseCameraTrackballZoomToMouseManipulator.newInstance({
    scrollEnabled: true,
  })
);
interactorStyle.setRotationFactor(2);
interactorStyle.setFocusSphereColor(1, 0, 0);
interactorStyle.setFocusSphereRadiusFactor(1.2);
renderWindow.getInteractor().setInteractorStyle(interactorStyle);

// ----------------------------------------------------------------------------
// Basic actor setup
// ----------------------------------------------------------------------------

const coneSource = vtkConeSource.newInstance({ height: 1.0 });
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(coneSource.getOutputPort());

const actor = vtkActor.newInstance();
actor.rotateZ(90);
actor.setMapper(mapper);

renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();

// ----------------------------------------------------------------------------
// Orientation widget setup
// ----------------------------------------------------------------------------
const axes = vtkAxesActor.newInstance({ pickable: false });
const orientationWidget = vtkOrientationMarkerWidget.newInstance({
  actor: axes,
  interactor: renderWindow.getInteractor(),
});
orientationWidget.setViewportCorner(
  vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT
);
orientationWidget.setMinPixelSize(100);
orientationWidget.setMaxPixelSize(300);

// ----------------------------------------------------------------------------
// UI setup
// ----------------------------------------------------------------------------

function updateWorldUpVec() {
  let useWorldUpVec = document.querySelector('.useWorldUpVec').checked;

  const coordinateElements = Array.from(
    document.querySelector('.coordinates').children
  );
  coordinateElements.forEach((element) => {
    element.disabled = !useWorldUpVec;
  });

  if (useWorldUpVec) {
    const coordinates = coordinateElements.map((item) =>
      Number.parseFloat(item.value)
    );
    const validCoordinates = !coordinates.some((value) => Number.isNaN(value));

    if (validCoordinates) {
      interactorStyle.setWorldUpVec(...coordinates);
    } else {
      useWorldUpVec = false;
    }
  }

  interactorStyle.setUseWorldUpVec(useWorldUpVec);
  renderWindow.render();
}

document.querySelector('.useWorldUpVec').oninput = updateWorldUpVec;
document.querySelector('.coordinates').oninput = updateWorldUpVec;

document.querySelector('.useOrientationMarker').oninput = (ev) => {
  orientationWidget.setEnabled(ev.target.checked);
};

document.querySelector('.useParallelCamera').oninput = (ev) => {
  renderer.getActiveCamera().setParallelProjection(ev.target.checked);
  renderWindow.render();
};

renderer
  .getActiveCamera()
  .onModified(orientationWidget.updateMarkerOrientation);

updateWorldUpVec();
<commit_msg>docs(InteractorStyleUnicam): pass isNaN directly<commit_after>import 'vtk.js/Sources/favicon';

import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkAxesActor from 'vtk.js/Sources/Rendering/Core/AxesActor';
import vtkConeSource from 'vtk.js/Sources/Filters/Sources/ConeSource';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkInteractorStyleUnicam from 'vtk.js/Sources/Interaction/Style/InteractorStyleUnicam';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkMouseCameraTrackballZoomToMouseManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballZoomToMouseManipulator';
import vtkOrientationMarkerWidget from 'vtk.js/Sources/Interaction/Widgets/OrientationMarkerWidget';

import controlPanel from './controlPanel.html';

// ----------------------------------------------------------------------------
// Renderer setup
// ----------------------------------------------------------------------------

const fullScreenRenderWindow = vtkFullScreenRenderWindow.newInstance({
  background: [0, 0, 0],
});
const renderWindow = fullScreenRenderWindow.getRenderWindow();
const renderer = fullScreenRenderWindow.getRenderer();
fullScreenRenderWindow.addController(controlPanel);

// ----------------------------------------------------------------------------
// Interactor style setup
// ----------------------------------------------------------------------------

const interactorStyle = vtkInteractorStyleUnicam.newInstance();
interactorStyle.setWorldUpVec([0, 1, 0]);
interactorStyle.addMouseManipulator(
  vtkMouseCameraTrackballZoomToMouseManipulator.newInstance({
    scrollEnabled: true,
  })
);
interactorStyle.setRotationFactor(2);
interactorStyle.setFocusSphereColor(1, 0, 0);
interactorStyle.setFocusSphereRadiusFactor(1.2);
renderWindow.getInteractor().setInteractorStyle(interactorStyle);

// ----------------------------------------------------------------------------
// Basic actor setup
// ----------------------------------------------------------------------------

const coneSource = vtkConeSource.newInstance({ height: 1.0 });
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(coneSource.getOutputPort());

const actor = vtkActor.newInstance();
actor.rotateZ(90);
actor.setMapper(mapper);

renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();

// ----------------------------------------------------------------------------
// Orientation widget setup
// ----------------------------------------------------------------------------
const axes = vtkAxesActor.newInstance({ pickable: false });
const orientationWidget = vtkOrientationMarkerWidget.newInstance({
  actor: axes,
  interactor: renderWindow.getInteractor(),
});
orientationWidget.setViewportCorner(
  vtkOrientationMarkerWidget.Corners.BOTTOM_RIGHT
);
orientationWidget.setMinPixelSize(100);
orientationWidget.setMaxPixelSize(300);

// ----------------------------------------------------------------------------
// UI setup
// ----------------------------------------------------------------------------

function updateWorldUpVec() {
  let useWorldUpVec = document.querySelector('.useWorldUpVec').checked;

  const coordinateElements = Array.from(
    document.querySelector('.coordinates').children
  );
  coordinateElements.forEach((element) => {
    element.disabled = !useWorldUpVec;
  });

  if (useWorldUpVec) {
    const coordinates = coordinateElements.map((item) =>
      Number.parseFloat(item.value)
    );
    const validCoordinates = !coordinates.some(Number.isNaN);

    if (validCoordinates) {
      interactorStyle.setWorldUpVec(...coordinates);
    } else {
      useWorldUpVec = false;
    }
  }

  interactorStyle.setUseWorldUpVec(useWorldUpVec);
  renderWindow.render();
}

document.querySelector('.useWorldUpVec').oninput = updateWorldUpVec;
document.querySelector('.coordinates').oninput = updateWorldUpVec;

document.querySelector('.useOrientationMarker').oninput = (ev) => {
  orientationWidget.setEnabled(ev.target.checked);
};

document.querySelector('.useParallelCamera').oninput = (ev) => {
  renderer.getActiveCamera().setParallelProjection(ev.target.checked);
  renderWindow.render();
};

renderer
  .getActiveCamera()
  .onModified(orientationWidget.updateMarkerOrientation);

updateWorldUpVec();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { facebookLogin } from '../actions';

class AuthScreen extends Component {
  componentDidMount() {
    this.props.facebookLogin();
    // if we had logged before
    //this.onAuthComplete(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.onAuthComplete(nextProps);
  }

  onAuthComplete(props) {
    if (props.token) {
      this.props.navigation.navigate('map');
    }
  }

  render() {
    return (
      <View />
    );
  }
}

function mapStateToProps({ auth }) {
  return { token: auth.token };
}

export default connect(mapStateToProps, { facebookLogin })(AuthScreen);
<commit_msg>Removed Text from AuthScreen<commit_after>import React, { Component } from 'react';
import { View } from 'react-native';
import { connect } from 'react-redux';
import { facebookLogin } from '../actions';

class AuthScreen extends Component {
  componentDidMount() {
    this.props.facebookLogin();
    // if we had logged before
    //this.onAuthComplete(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.onAuthComplete(nextProps);
  }

  onAuthComplete(props) {
    if (props.token) {
      this.props.navigation.navigate('map');
    }
  }

  render() {
    return (
      <View />
    );
  }
}

function mapStateToProps({ auth }) {
  return { token: auth.token };
}

export default connect(mapStateToProps, { facebookLogin })(AuthScreen);
<|endoftext|>


<commit_before>export { URLComposerCSV };

/**
 * Compose a URL for downloading cells data (as .CSV format) from a Google Sheets by using Google Visualzation Table Query API.
 * The target spreadsheet should be shared by either "Public on the web" or "Anyone with the link".
 *
 * (GVizTQ = Google Visualzation Table Query)
 *
 * The follwoings are some composed examples:
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range=AH59:AJ98&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?gid=816353147&range=AH59:AK98&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?gid=1504323928&range=B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?sheet=Evolution.Param&range=B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range=Evolution.Param!B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range='Evolution.Param'!B17&headers=0&tqx=out:csv
 *
 */
class UrlComposer {

  /**
   * If sheetId is null, sheetName is null, and no sheet name in the range's A1 notation, the first (most left) visible sheet
   * inside the spreadsheet will be used.
   *
   * @param {string} spreadsheetId
   *   The component after the "https://docs.google.com/spreadsheets/d/".
   *
   * @param {string} range
   *   The cells' A1 notation of the cells. It describes the (name and) range of the sheet inside the spreadsheet.
   *   - "A1" refers to one cell of the first (most left) visible sheet.
   *   - "B2:C5" refers to cells of a rectangle of the first (most left) visible sheet.
   *   - "Books!D8:D" refers to the column D of sheet named "Books" from rows 8 to the last rows.
   *   - "'Name has space'!7:10" refers to the rows 7 to 10 of sheet named "Name has space".
   *
   * @param {number} headers
   *   The component after the "headers=". It means how many header rows. It should be an zero or positive integer.
   *
   * @param {number} sheetId
   *   The component after the "gid=". If the sheetName is used (or the sheet name in the range's A1 notation is specified),
   * keep this sheetId null (or undefined).
   *
   * @param {string} sheetName
   *   The component after the "sheet=". If the sheetId is used (or the sheet name in in the range's A1 notation is specified),
   * keep this sheetName null (or undefined).
   *
   * @see {@link https://developers.google.com/sheets/api/guides/concepts}
   * @see {@link https://developers.google.com/chart/interactive/docs/dev/implementing_data_source}
   * @see {@link https://developers.google.com/chart/interactive/docs/spreadsheets}
   * @see {@link https://developers.google.com/chart/interactive/docs/querylanguage}
   */
  constructor( spreadsheetId, range, headers = 0, sheetId = null, sheetName = null ) {
    this.spreadsheetId = spreadsheetId;
    this.range = range;
    this.headers = headers;
    this.sheetId = sheetId;
    this.sheetName = sheetName;
  }

  getCsvUrl() {
    // Because sheetId could be 0, it should be checked by comparing to null directly (i.e. should no use ( !this.sheetId )).
    let url = `${URLComposer.spreadsheetUrlPrefix}/${this.spreadsheetId}/gviz/tq?&tqx=out:csv${
      ( this.sheetId != null ) ? `&gid=${this.sheetId}` : `${
      ( this.sheetName != null ) ? `&sheet=${this.sheetName}` : "" }` }${
      ( this.range != null ) ? `&range=${this.range}` : "" }&headers=${this.headers}`;

    return url;
  }
}

/** The web address of Google Sheets. */
URLComposer.spreadsheetUrlPrefix = "https://docs.google.com/spreadsheets/d";
<commit_msg>Update GVizTQ.js<commit_after>export { UrlComposer };

/**
 * Compose a URL for downloading cells data (as .CSV format) from a Google Sheets by using Google Visualzation Table Query API.
 * The target spreadsheet should be shared by either "Public on the web" or "Anyone with the link".
 *
 * (GVizTQ = Google Visualzation Table Query)
 *
 * The follwoings are some composed examples:
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range=AH59:AJ98&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?gid=816353147&range=AH59:AK98&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?gid=1504323928&range=B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?sheet=Evolution.Param&range=B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range=Evolution.Param!B17&headers=0&tqx=out:csv
 *
 * @example
 * https://docs.google.com/spreadsheets/d/18YyEoy-OfSkODfw8wqBRApSrRnBTZpjRpRiwIKy8a0M/gviz/tq?range='Evolution.Param'!B17&headers=0&tqx=out:csv
 *
 */
class UrlComposer {

  /**
   * If sheetId is null, sheetName is null, and no sheet name in the range's A1 notation, the first (most left) visible sheet
   * inside the spreadsheet will be used.
   *
   * @param {string} spreadsheetId
   *   The component after the "https://docs.google.com/spreadsheets/d/".
   *
   * @param {string} range
   *   The cells' A1 notation of the cells. It describes the (name and) range of the sheet inside the spreadsheet.
   *   - "A1" refers to one cell of the first (most left) visible sheet.
   *   - "B2:C5" refers to cells of a rectangle of the first (most left) visible sheet.
   *   - "Books!D8:D" refers to the column D of sheet named "Books" from rows 8 to the last rows.
   *   - "'Name has space'!7:10" refers to the rows 7 to 10 of sheet named "Name has space".
   *
   * @param {number} headers
   *   The component after the "headers=". It means how many header rows. It should be an zero or positive integer.
   *
   * @param {number} sheetId
   *   The component after the "gid=". If the sheetName is used (or the sheet name in the range's A1 notation is specified),
   * keep this sheetId null (or undefined).
   *
   * @param {string} sheetName
   *   The component after the "sheet=". If the sheetId is used (or the sheet name in in the range's A1 notation is specified),
   * keep this sheetName null (or undefined).
   *
   * @see {@link https://developers.google.com/sheets/api/guides/concepts}
   * @see {@link https://developers.google.com/chart/interactive/docs/dev/implementing_data_source}
   * @see {@link https://developers.google.com/chart/interactive/docs/spreadsheets}
   * @see {@link https://developers.google.com/chart/interactive/docs/querylanguage}
   */
  constructor( spreadsheetId, range, headers = 0, sheetId = null, sheetName = null ) {
    this.spreadsheetId = spreadsheetId;
    this.range = range;
    this.headers = headers;
    this.sheetId = sheetId;
    this.sheetName = sheetName;
  }

  getCsvUrl() {
    // Because sheetId could be 0, it should be checked by comparing to null directly (i.e. should no use ( !this.sheetId )).
    let url = `${URLComposer.spreadsheetUrlPrefix}/${this.spreadsheetId}/${URLComposer.GoogleVisualizationTableQueryUrlPostfix}?&tqx=out:csv${
      ( this.sheetId != null ) ? `&gid=${this.sheetId}` : `${
      ( this.sheetName != null ) ? `&sheet=${this.sheetName}` : "" }` }${
      ( this.range != null ) ? `&range=${this.range}` : "" }&headers=${this.headers}`;

    return url;
  }
}

/** The url prefix of Google Sheets. */
URLComposer.spreadsheetUrlPrefix = "https://docs.google.com/spreadsheets/d";

/** The url postfix of Google Visualization Table Query. */
URLComposer.GoogleVisualizationTableQueryUrlPostfix = "gviz/tq";
<|endoftext|>


<commit_before>/*
 * Copyright 2011 eBay Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';
function removeDashes(str) {
    return str.replace(/-([a-z])/g, function (match, lower) {
        return lower.toUpperCase();
    });
}
var extend = require('raptor-util').extend;
var ForNode = require('./ForNode');
var IfNode = require('./IfNode');
var ElseIfNode = require('./ElseIfNode');
var ElseNode = require('./ElseNode');
var WithNode = require('./WithNode');
var TagHandlerNode = require('./TagHandlerNode');
var IncludeNode = require('./IncludeNode');

var coreAttrHandlers = [
    [
        'c-space', function(attr, node) {
            this['c-whitespace'](attr, node);
        }
    ],
    [
        'c-whitespace', function(attr, node) {
            if (attr === 'preserve') {
                node.setPreserveWhitespace(true);
            }
        }
    ],
    [
        'c-escape-xml', function(attr, node) {
            node.setEscapeXmlBodyText(attr !== 'false');
        }
    ],
    [
        'c-parse-body-text', function(attr, node) {
            node.parseBodyText = attr !== 'false';
        }
    ],
    [
        'attrs', function(attr, node) {
            if (!node.addDynamicAttributes) {
                node.addError('Node does not support the "attrs" attribute');
            } else {
                node.addDynamicAttributes(attr);
            }
        }
    ],
    [
        'for-each', function(attr, node) {
            this['for'](attr, node);
        }
    ],
    [
        'for', function(attr, node) {
            var forEachProps = this.compiler.parseAttribute(attr, {
                    each: { type: 'custom' },
                    separator: { type: 'expression' },
                    'iterator': { type: 'expression' },
                    'status-var': { type: 'identifier' },
                    'for-loop': {
                        type: 'boolean',
                        allowExpressions: false
                    }
                }, {
                    removeDashes: true,
                    defaultName: 'each',
                    errorHandler: function (message) {
                        node.addError('Invalid for attribute of "' + attr + '". Error: ' + message);
                    }
                });
            forEachProps.pos = node.getPosition();
            //Copy the position property
            var forEachNode = this.compiler.createNode(ForNode, forEachProps);
            //Surround the existing node with an "forEach" node by replacing the current
            //node with the new "forEach" node and then adding the current node as a child
            node.parentNode.replaceChild(forEachNode, node);
            forEachNode.appendChild(node);
        }
    ],
    [
        'if', function(attr, node) {
            var ifNode = this.compiler.createNode(IfNode, {
                    test: this.template.makeExpression(attr),
                    pos: node.getPosition()
                });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(ifNode, node);
            ifNode.appendChild(node);
        }
    ],
    [
        'else-if', function(attr, node) {
            var elseIfNode = this.compiler.createNode(ElseIfNode, {
                    test: this.template.makeExpression(attr),
                    pos: node.getPosition()
                });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(elseIfNode, node);
            elseIfNode.appendChild(node);
        }
    ],
    [
        'else', function(attr, node) {
            var elseNode = this.compiler.createNode(ElseNode, { pos: node.getPosition() });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(elseNode, node);
            elseNode.appendChild(node);
        }
    ],
    [
        'with', function(attr, node) {
            var withNode = this.compiler.createNode(WithNode, {
                    vars: attr,
                    pos: node.getPosition()
                });
            node.parentNode.replaceChild(withNode, node);
            withNode.appendChild(node);
        }
    ],
    [
        'c-trim-body-indent', function(attr, node) {
            if (attr === 'true') {
                node.trimBodyIndent = true;
            }
        }
    ],
    [
        'body-only-if', function(attr, node) {
            if (!node.setStripExpression) {
                node.addError('The c-strip directive is not allowed for target node');
            }
            node.setStripExpression(attr);
        }
    ],
    [
        'c-input', function(attr, node) {
            this.inputAttr = attr;
        }
    ],
    [
        'c-data', function(attr, node) {
            this.inputAttr = attr;
        }
    ]
];

function Transformer(template, compiler) {
    this.template = template;
    this.compiler = compiler;
    this.inputAttr = null;
}

Transformer.prototype = {
    transformNode: function(node) {

        for (var i=0, len=coreAttrHandlers.length; i<len; i++) {
            var attrHandler = coreAttrHandlers[i];
            var name = attrHandler[0];
            if (name === 'for' && node.tagName === 'label') {
                continue;
            }
            var attr = node.getAttribute(name);
            if (attr != null) {
                node.removeAttribute(name);
                node = this[name](attr, node) || node;
            }
        }

        return node;
    }
};

coreAttrHandlers.forEach(function(attrHandler) {
    var name = attrHandler[0];
    var func = attrHandler[1];
    Transformer.prototype[name] = func;
});

function handleAttr(node, compiler, template) {
    var parentNode = node.parentNode;
    if (!parentNode.isElementNode()) {
        node.addError(node.toString() + ' tag is not nested within an element tag.');
        return;
    }
    var hasValue = node.hasAttribute('value');
    var attrName = node.getAttribute('name');
    var attrValue = node.getAttribute('value');
    var attrUri = node.getAttribute('namespace') || '';
    var attrPrefix = node.getAttribute('prefix') || '';
    if (parentNode.hasAttributeNS(attrUri, attrName)) {
        node.addError(node.toString() + ' tag adds duplicate attribute with name "' + attrName + '"' + (attrUri ? ' and URI "' + attrUri + '"' : ''));
        return;
    }
    node.removeAttribute('name');
    node.removeAttribute('value');
    node.removeAttribute('namespace');
    node.removeAttribute('prefix');
    if (node.hasAttributesAnyNS()) {
        var invalidAttrs = node.getAllAttributes().map(function (attr) {
                return attr.qName;
            });
        node.addError('Invalid attributes for tag ' + node.toString() + ': ' + invalidAttrs.join(', '));
        return;
    }
    //Cleanup whitespace between <attr> tags
    if (node.previousSibling && node.previousSibling.isTextNode() && node.previousSibling.getText().trim() === '') {
        node.previousSibling.detach();
    }
    if (node.nextSibling && node.nextSibling.isTextNode() && node.nextSibling.getText().trim() === '') {
        node.nextSibling.detach();
    }
    if (node.nextSibling && node.nextSibling.isTextNode()) {
        node.nextSibling.setText(node.nextSibling.getText().replace(/^\n\s*/, ''));
    }
    node.detach();
    //Remove the node out of the tree
    compiler.transformTree(node, template);
    if (hasValue) {
        parentNode.setAttributeNS(attrUri, attrName, attrValue, attrPrefix);
    } else {
        node.setEscapeXmlContext('ATTRIBUTE');
        //Escape body text and expressions as attributes
        parentNode.setAttributeNS(attrUri, attrName, node.getBodyContentExpression(template), attrPrefix, false);
    }
}

function findNestedAttrs(node, compiler, template) {
    node.forEachChild(function (child) {
        if (child.qName === 'attr') {
            handleAttr(child, compiler, template);
        }
    });
}

module.exports = function transform(node, compiler, template) {

    //Find and handle nested <attrs> elements
    findNestedAttrs(node, compiler, template);

    var tag;

    function convertAttrValue(attr, type, attrDef) {
        type = type || (attrDef ? attrDef.type : 'string') || 'string';

        try {
            return compiler.convertType(attr.value, type, attrDef ? attrDef.allowExpressions !== false : true);
        } catch (e) {
            node.addError('Invalid attribute value of "' + attr.value + '" for attribute "' + attr.name + '": ' + e.message);
            return attr.value;
        }
    }

    function forEachProp(callback, thisObj) {
        var foundProps = {};

        node.forEachAttributeAnyNS(function (attr) {
            var attrDef = compiler.taglibs.getAttribute(node, attr);
            if (!attrDef) {
                // var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri);
                //Tag doesn't allow dynamic attributes
                node.addError('The tag "' + tag.name + '" in taglib "' + tag.taglibId + '" does not support attribute "' + attr + '"');
                return;
            }

            var type = attrDef.type || 'string';

            var value;

            if (compiler.isExpression(attr.value)) {
                value = attr.value;
            } else {
                if (type === 'path') {
                    var pathVar;
                    if (compiler.hasExpression(attr.value)) {
                        value = convertAttrValue(attr, 'string', attrDef);
                    } else {
                        // Resolve the static string to a full path only once
                        pathVar = template.addStaticVar(attr.value, 'require.resolve(' + compiler.convertType(attr.value, 'string', true) + ')');
                        value = compiler.makeExpression(pathVar);
                    }
                } else if (type === 'template') {
                    var templateVar;
                    if (compiler.hasExpression(attr.value)) {
                        value = compiler.makeExpression('__helpers.l(' + convertAttrValue(attr, 'string', attrDef) + ')');
                    } else {
                        // Resolve the static string to a full path only once
                        templateVar = template.addStaticVar(attr.value, '__helpers.l(require.resolve(' + compiler.convertType(attr.value, 'string', true) + '))');
                        value = compiler.makeExpression(templateVar);
                    }
                } else {
                    value = convertAttrValue(attr, type, attrDef);
                }
            }
            var propName;
            if (attrDef.dynamicAttribute) {
                propName = attr.qName;
            } else {
                if (attrDef.targetProperty) {
                    propName = attrDef.targetProperty;
                } else if (attrDef.preserveName) {
                    propName = attr.localName;
                } else {
                    propName = removeDashes(attr.localName);
                }
            }

            foundProps[propName] = true;
            callback.call(thisObj, propName, value, attrDef);
        });

        tag.forEachAttribute(function (attr) {
            if (attr.hasOwnProperty('defaultValue') && !foundProps[attr.name]) {
                callback.call(thisObj, attr.name, template.makeExpression(JSON.stringify(attr.defaultValue)), '', attr);
            }
        });
    }

    tag = node.tag || compiler.taglibs.getTag(node);

    var transformer = new Transformer(template, compiler);
    node = transformer.transformNode(node);
    var inputAttr = transformer.inputAttr;

    if (tag) {
        if (tag.preserveWhitespace) {
            node.setPreserveWhitespace(true);
        }
        if (tag.renderer || tag.template) {
            if (tag.renderer) {
                //Instead of compiling as a static XML element, we'll
                //make the node render as a tag handler node so that
                //writes code that invokes the handler
                TagHandlerNode.convertNode(node, tag);
                if (inputAttr) {
                    node.setInputExpression(template.makeExpression(inputAttr));
                }
            } else {
                var templatePath = compiler.getRequirePath(tag.template);
                // The tag is mapped to a template that will be used to perform
                // the rendering so convert the node into a "IncludeNode" that can
                // be used to include the output of rendering a template
                IncludeNode.convertNode(node, templatePath);
            }

            forEachProp(function (name, value, attrDef) {
                if (attrDef.dynamicAttribute && attrDef.targetProperty) {
                    if (attrDef.removeDashes === true) {
                        name = removeDashes(name);
                    }
                    if (node.addDynamicAttribute) {
                        node.addDynamicAttribute(name, value);
                        node.setDynamicAttributesProperty(attrDef.targetProperty);
                    } else {
                        node.setProperty(name, value);
                    }
                } else {
                    node.setProperty(name, value);
                }
            });

        } else if (tag.nodeClass) {
            var NodeCompilerClass = require(tag.nodeClass);
            compiler.inheritNode(NodeCompilerClass);
            extend(node, NodeCompilerClass.prototype);
            NodeCompilerClass.call(node);
            node.setNodeClass(NodeCompilerClass);
            forEachProp(function (name, value) {
                node.setProperty(name, value);
            });
        }
    }
};
<commit_msg>Fixed #13 remove-dashes now works for dynamic attributes even if target-property is null<commit_after>/*
 * Copyright 2011 eBay Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';
function removeDashes(str) {
    return str.replace(/-([a-z])/g, function (match, lower) {
        return lower.toUpperCase();
    });
}
var extend = require('raptor-util').extend;
var ForNode = require('./ForNode');
var IfNode = require('./IfNode');
var ElseIfNode = require('./ElseIfNode');
var ElseNode = require('./ElseNode');
var WithNode = require('./WithNode');
var TagHandlerNode = require('./TagHandlerNode');
var IncludeNode = require('./IncludeNode');

var coreAttrHandlers = [
    [
        'c-space', function(attr, node) {
            this['c-whitespace'](attr, node);
        }
    ],
    [
        'c-whitespace', function(attr, node) {
            if (attr === 'preserve') {
                node.setPreserveWhitespace(true);
            }
        }
    ],
    [
        'c-escape-xml', function(attr, node) {
            node.setEscapeXmlBodyText(attr !== 'false');
        }
    ],
    [
        'c-parse-body-text', function(attr, node) {
            node.parseBodyText = attr !== 'false';
        }
    ],
    [
        'attrs', function(attr, node) {
            if (!node.addDynamicAttributes) {
                node.addError('Node does not support the "attrs" attribute');
            } else {
                node.addDynamicAttributes(attr);
            }
        }
    ],
    [
        'for-each', function(attr, node) {
            this['for'](attr, node);
        }
    ],
    [
        'for', function(attr, node) {
            var forEachProps = this.compiler.parseAttribute(attr, {
                    each: { type: 'custom' },
                    separator: { type: 'expression' },
                    'iterator': { type: 'expression' },
                    'status-var': { type: 'identifier' },
                    'for-loop': {
                        type: 'boolean',
                        allowExpressions: false
                    }
                }, {
                    removeDashes: true,
                    defaultName: 'each',
                    errorHandler: function (message) {
                        node.addError('Invalid for attribute of "' + attr + '". Error: ' + message);
                    }
                });
            forEachProps.pos = node.getPosition();
            //Copy the position property
            var forEachNode = this.compiler.createNode(ForNode, forEachProps);
            //Surround the existing node with an "forEach" node by replacing the current
            //node with the new "forEach" node and then adding the current node as a child
            node.parentNode.replaceChild(forEachNode, node);
            forEachNode.appendChild(node);
        }
    ],
    [
        'if', function(attr, node) {
            var ifNode = this.compiler.createNode(IfNode, {
                    test: this.template.makeExpression(attr),
                    pos: node.getPosition()
                });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(ifNode, node);
            ifNode.appendChild(node);
        }
    ],
    [
        'else-if', function(attr, node) {
            var elseIfNode = this.compiler.createNode(ElseIfNode, {
                    test: this.template.makeExpression(attr),
                    pos: node.getPosition()
                });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(elseIfNode, node);
            elseIfNode.appendChild(node);
        }
    ],
    [
        'else', function(attr, node) {
            var elseNode = this.compiler.createNode(ElseNode, { pos: node.getPosition() });
            //Surround the existing node with an "if" node by replacing the current
            //node with the new "if" node and then adding the current node as a child
            node.parentNode.replaceChild(elseNode, node);
            elseNode.appendChild(node);
        }
    ],
    [
        'with', function(attr, node) {
            var withNode = this.compiler.createNode(WithNode, {
                    vars: attr,
                    pos: node.getPosition()
                });
            node.parentNode.replaceChild(withNode, node);
            withNode.appendChild(node);
        }
    ],
    [
        'c-trim-body-indent', function(attr, node) {
            if (attr === 'true') {
                node.trimBodyIndent = true;
            }
        }
    ],
    [
        'body-only-if', function(attr, node) {
            if (!node.setStripExpression) {
                node.addError('The c-strip directive is not allowed for target node');
            }
            node.setStripExpression(attr);
        }
    ],
    [
        'c-input', function(attr, node) {
            this.inputAttr = attr;
        }
    ],
    [
        'c-data', function(attr, node) {
            this.inputAttr = attr;
        }
    ]
];

function Transformer(template, compiler) {
    this.template = template;
    this.compiler = compiler;
    this.inputAttr = null;
}

Transformer.prototype = {
    transformNode: function(node) {

        for (var i=0, len=coreAttrHandlers.length; i<len; i++) {
            var attrHandler = coreAttrHandlers[i];
            var name = attrHandler[0];
            if (name === 'for' && node.tagName === 'label') {
                continue;
            }
            var attr = node.getAttribute(name);
            if (attr != null) {
                node.removeAttribute(name);
                node = this[name](attr, node) || node;
            }
        }

        return node;
    }
};

coreAttrHandlers.forEach(function(attrHandler) {
    var name = attrHandler[0];
    var func = attrHandler[1];
    Transformer.prototype[name] = func;
});

function handleAttr(node, compiler, template) {
    var parentNode = node.parentNode;
    if (!parentNode.isElementNode()) {
        node.addError(node.toString() + ' tag is not nested within an element tag.');
        return;
    }
    var hasValue = node.hasAttribute('value');
    var attrName = node.getAttribute('name');
    var attrValue = node.getAttribute('value');
    var attrUri = node.getAttribute('namespace') || '';
    var attrPrefix = node.getAttribute('prefix') || '';
    if (parentNode.hasAttributeNS(attrUri, attrName)) {
        node.addError(node.toString() + ' tag adds duplicate attribute with name "' + attrName + '"' + (attrUri ? ' and URI "' + attrUri + '"' : ''));
        return;
    }
    node.removeAttribute('name');
    node.removeAttribute('value');
    node.removeAttribute('namespace');
    node.removeAttribute('prefix');
    if (node.hasAttributesAnyNS()) {
        var invalidAttrs = node.getAllAttributes().map(function (attr) {
                return attr.qName;
            });
        node.addError('Invalid attributes for tag ' + node.toString() + ': ' + invalidAttrs.join(', '));
        return;
    }
    //Cleanup whitespace between <attr> tags
    if (node.previousSibling && node.previousSibling.isTextNode() && node.previousSibling.getText().trim() === '') {
        node.previousSibling.detach();
    }
    if (node.nextSibling && node.nextSibling.isTextNode() && node.nextSibling.getText().trim() === '') {
        node.nextSibling.detach();
    }
    if (node.nextSibling && node.nextSibling.isTextNode()) {
        node.nextSibling.setText(node.nextSibling.getText().replace(/^\n\s*/, ''));
    }
    node.detach();
    //Remove the node out of the tree
    compiler.transformTree(node, template);
    if (hasValue) {
        parentNode.setAttributeNS(attrUri, attrName, attrValue, attrPrefix);
    } else {
        node.setEscapeXmlContext('ATTRIBUTE');
        //Escape body text and expressions as attributes
        parentNode.setAttributeNS(attrUri, attrName, node.getBodyContentExpression(template), attrPrefix, false);
    }
}

function findNestedAttrs(node, compiler, template) {
    node.forEachChild(function (child) {
        if (child.qName === 'attr') {
            handleAttr(child, compiler, template);
        }
    });
}

module.exports = function transform(node, compiler, template) {

    //Find and handle nested <attrs> elements
    findNestedAttrs(node, compiler, template);

    var tag;

    function convertAttrValue(attr, type, attrDef) {
        type = type || (attrDef ? attrDef.type : 'string') || 'string';

        try {
            return compiler.convertType(attr.value, type, attrDef ? attrDef.allowExpressions !== false : true);
        } catch (e) {
            node.addError('Invalid attribute value of "' + attr.value + '" for attribute "' + attr.name + '": ' + e.message);
            return attr.value;
        }
    }

    function forEachProp(callback, thisObj) {
        var foundProps = {};

        node.forEachAttributeAnyNS(function (attr) {
            var attrDef = compiler.taglibs.getAttribute(node, attr);
            if (!attrDef) {
                // var isAttrForTaglib = compiler.taglibs.isTaglib(attrUri);
                //Tag doesn't allow dynamic attributes
                node.addError('The tag "' + tag.name + '" in taglib "' + tag.taglibId + '" does not support attribute "' + attr + '"');
                return;
            }

            var type = attrDef.type || 'string';

            var value;

            if (compiler.isExpression(attr.value)) {
                value = attr.value;
            } else {
                if (type === 'path') {
                    var pathVar;
                    if (compiler.hasExpression(attr.value)) {
                        value = convertAttrValue(attr, 'string', attrDef);
                    } else {
                        // Resolve the static string to a full path only once
                        pathVar = template.addStaticVar(attr.value, 'require.resolve(' + compiler.convertType(attr.value, 'string', true) + ')');
                        value = compiler.makeExpression(pathVar);
                    }
                } else if (type === 'template') {
                    var templateVar;
                    if (compiler.hasExpression(attr.value)) {
                        value = compiler.makeExpression('__helpers.l(' + convertAttrValue(attr, 'string', attrDef) + ')');
                    } else {
                        // Resolve the static string to a full path only once
                        templateVar = template.addStaticVar(attr.value, '__helpers.l(require.resolve(' + compiler.convertType(attr.value, 'string', true) + '))');
                        value = compiler.makeExpression(templateVar);
                    }
                } else {
                    value = convertAttrValue(attr, type, attrDef);
                }
            }
            var propName;
            if (attrDef.dynamicAttribute) {
                propName = attr.qName;
            } else {
                if (attrDef.targetProperty) {
                    propName = attrDef.targetProperty;
                } else if (attrDef.preserveName) {
                    propName = attr.localName;
                } else {
                    propName = removeDashes(attr.localName);
                }
            }

            foundProps[propName] = true;
            callback.call(thisObj, propName, value, attrDef);
        });

        tag.forEachAttribute(function (attr) {
            if (attr.hasOwnProperty('defaultValue') && !foundProps[attr.name]) {
                callback.call(thisObj, attr.name, template.makeExpression(JSON.stringify(attr.defaultValue)), '', attr);
            }
        });
    }

    tag = node.tag || compiler.taglibs.getTag(node);

    var transformer = new Transformer(template, compiler);
    node = transformer.transformNode(node);
    var inputAttr = transformer.inputAttr;

    if (tag) {
        if (tag.preserveWhitespace) {
            node.setPreserveWhitespace(true);
        }
        if (tag.renderer || tag.template) {
            if (tag.renderer) {
                //Instead of compiling as a static XML element, we'll
                //make the node render as a tag handler node so that
                //writes code that invokes the handler
                TagHandlerNode.convertNode(node, tag);
                if (inputAttr) {
                    node.setInputExpression(template.makeExpression(inputAttr));
                }
            } else {
                var templatePath = compiler.getRequirePath(tag.template);
                // The tag is mapped to a template that will be used to perform
                // the rendering so convert the node into a "IncludeNode" that can
                // be used to include the output of rendering a template
                IncludeNode.convertNode(node, templatePath);
            }

            forEachProp(function (name, value, attrDef) {
                if (attrDef.dynamicAttribute) {
                    if (attrDef.removeDashes === true) {
                        name = removeDashes(name);
                    }
                    if (node.addDynamicAttribute && attrDef.targetProperty) {
                        node.addDynamicAttribute(name, value);
                        node.setDynamicAttributesProperty(attrDef.targetProperty);
                    } else {
                        node.setProperty(name, value);
                    }
                } else {
                    node.setProperty(name, value);
                }
            });

        } else if (tag.nodeClass) {
            var NodeCompilerClass = require(tag.nodeClass);
            compiler.inheritNode(NodeCompilerClass);
            extend(node, NodeCompilerClass.prototype);
            NodeCompilerClass.call(node);
            node.setNodeClass(NodeCompilerClass);
            forEachProp(function (name, value) {
                node.setProperty(name, value);
            });
        }
    }
};
<|endoftext|>


<commit_before>/*
 * === ABOUT US ===
 * @name:		Orbitron
 * @website:	http://www.team-orbitron.com
 * === ABOUT PROJECT ===
 * @author:		Orbitron
 * @project:	Achievements
 * @version:	v1.0.6
 * @website:	https://raw.githubusercontent.com/OfficialOrbitron/ModPE/master/Scripts/Achievements.js
 *
 * Testet with:
 * MCPE: v0.9.5
 * BlockLauncher: v1.7.9
 *
 */

// Project info
var project		= "Achievements";
var sname		= "ACH";
var version		= "1.0.6";
var author		= "Orbitron";

// Values
var achievement	= [
	{
		"id": 1,
		"reached": false,
		"message": "Monster Hunter!"
	},
	{
		"id": 2,
		"reached": false,
		"message": "Cow Tipper"
	},
	{
		"id": 3,
		"reached": false,
		"message": "Sniper Duel"
	},
	{
		"id": 4,
		"reached": false,
		"message": "Getting Wood"
	},
	{
		"id": 5,
		"reached": false,
		"message": "DIAMONDS!"
	},
	{
		"id": 6,
		"reached": false,
		"message": "Benchmarking"
	},
	{
		"id": 7,
		"reached": false,
		"message": "Hot Topic"
	},
	{
		"id": 8,
		"reached": false,
		"message": "Time to Mine!"
	},
	{
		"id": 9,
		"reached": false,
		"message": "Acquire Hardware"
	},
	{
		"id": 10,
		"reached": false,
		"message": "Time to Farm!"
	},
	{
		"id": 11,
		"reached": false,
		"message": "Bake Bread"
	},
	{
		"id": 12,
		"reached": false,
		"message": "The Lie"
	},
	{
		"id": 13,
		"reached": false,
		"message": "Getting an Upgrade"
	},
	{
		"id": 14,
		"reached": false,
		"message": "Time to Strike!"
	},
	{
		"id": 15,
		"reached": false,
		"message": "Librarian"
	}
];

// Main functions
function useItem(x, y, z, itemId, blockId, side)
{
	if(achievement[5]["reached"] === true && itemId == 58)
	{
		addonShowAchievement(5);
	}
	if(achievement[6]["reached"] === true && itemId == 61)
	{
		addonShowAchievement(6);
	}
	if(achievement[7]["reached"] === true && itemId == 270)
	{
		addonShowAchievement(7);
	}
	if(achievement[8]["reached"] === true && itemId == 265)
	{
		addonShowAchievement(8);
	}
	if(achievement[9]["reached"] === true && itemId == 290)
	{
		addonShowAchievement(9);
	}
	if(achievement[10]["reached"] === true && itemId == 297)
	{
		addonShowAchievement(10);
	}
	if(achievement[11]["reached"] === true && itemId == 354)
	{
		addonShowAchievement(11);
	}
	if(achievement[12]["reached"] === true)
	{
		if (itemId == 274 || itemId == 257 || itemId == 285 || itemId == 278)
		{
			addonShowAchievement(12);
		}
	}
	if(achievement[13]["reached"] === true && itemId == 268)
	{
		addonShowAchievement(13);
	}
	if(achievement[14]["reached"] === true && itemId == 47)
	{
		addonShowAchievement(14);
	}
}
function attackHook(attacker, victim)
{
	if(achievement[0]["reached"] === true)
	{
		if(Entity.getEntityTypeId(victim) == 32 || Entity.getEntityTypeId(victim) == 33 || Entity.getEntityTypeId(victim) == 34 || Entity.getEntityTypeId(victim) == 35 || Entity.getEntityTypeId(victim) == 36)
		{
			addonShowAchievement(0);
		}
	}
	if(achievement[1]["reached"] === true && Entity.getEntityTypeId(victim) == 11)
	{
		addonShowAchievement(1);
	}
	if(achievement[2]["reached"] === true && Entity.getEntityTypeId(victim) == 34 && getCarriedItem() == 261)
	{
		addonShowAchievement(2);
	}
}
function procCmd(command)
{
	var cmd = command.toLowerCase().split(" ");
	switch(cmd[0])
	{
		case "ach":
		case "achievements":

			switch(cmd[1])
			{
				case "save":

					for(var i = 0; i < achievement.length; i++)
					{
						ModPE.saveData("a" + i, achievement[i]["reached"]);
					}
					addonColourMessage("Saved achievements!");
					break;

				case "load":

					for(var i = 0; i < achievement.length; i++)
					{
						achievement[i]["reached"] = ModPE.readData("a" + i);
					}
					addonColourMessage("Loaded achievements!");
					break;

				case "reset":

					for(var i = 0; i < achievement.length; i++)
					{
						achievement[i]["reached"] = false;
						ModPE.saveData("a" + i, achievement[i]);
					}
					addonColourMessage("Resetted achievements!");
					break;

				default:

					addonErrorMessage("Command " + p[1] + " does not exist!");
					break;
			}

		default:

			break;
	}
}
function destroyBlock(x, y, z, side)
{
	if (achievement[3]["reached"] === true && getTile(x, y, z) == 17)
	{
		addonShowAchievement(3);
	}
	if (achievement[4]["reached"] === true && getTile(x, y, z) == 56 && getCarriedItem() == 257)
	{
		addonShowAchievement(4);
	}
}
function newLevel()
{
	for(var i = 0; i < achievement.length; i++)
	{
		achievement[i]["reached"] = ModPE.readData("a" + i);
	}
	clientMessage(ChatColor.GRAY + "[INFO] " + ChatColor.WHITE + project + " loaded");
}
function leaveGame()
{
	for(var i = 0; i < achievement.length; i++)
	{
		ModPE.saveData("a" + i, achievement[i]["reached"]);
	}
}

// Additional functions
function addonColourMessage(string)
{
	clientMessage(ChatColor.GRAY + "["+ ChatColor.RED + sname + ChatColor.GRAY +"] " + ChatColor.WHITE + string);
}
function addonErrorMessage(string)
{
	clientMessage(ChatColor.GRAY + "["+ ChatColor.RED + sname + ChatColor.GRAY +"] " + ChatColor.RED + string);
}
function addonShowAchievement(ID)
{
	achievement[ID]["reached"] = true;
	clientMessage("Achievement get! " + achievement[ID]["message"]);
}<commit_msg>Fixed code<commit_after>/*
 * === ABOUT US ===
 * @name:		Orbitron
 * @website:	http://www.team-orbitron.com
 * === ABOUT PROJECT ===
 * @author:		Orbitron
 * @project:	Achievements
 * @version:	v1.0.6
 * @website:	https://raw.githubusercontent.com/OfficialOrbitron/ModPE/master/Scripts/Achievements.js
 *
 * Testet with:
 * MCPE: v0.9.5
 * BlockLauncher: v1.7.9
 *
 */

// Project info
var project		= "Achievements";
var sname		= "ACH";
var version		= "1.0.6";
var author		= "Orbitron";

// Values
var achievement	= [
	{
		"id": 1,
		"reached": false,
		"message": "Monster Hunter!"
	},
	{
		"id": 2,
		"reached": false,
		"message": "Cow Tipper"
	},
	{
		"id": 3,
		"reached": false,
		"message": "Sniper Duel"
	},
	{
		"id": 4,
		"reached": false,
		"message": "Getting Wood"
	},
	{
		"id": 5,
		"reached": false,
		"message": "DIAMONDS!"
	},
	{
		"id": 6,
		"reached": false,
		"message": "Benchmarking"
	},
	{
		"id": 7,
		"reached": false,
		"message": "Hot Topic"
	},
	{
		"id": 8,
		"reached": false,
		"message": "Time to Mine!"
	},
	{
		"id": 9,
		"reached": false,
		"message": "Acquire Hardware"
	},
	{
		"id": 10,
		"reached": false,
		"message": "Time to Farm!"
	},
	{
		"id": 11,
		"reached": false,
		"message": "Bake Bread"
	},
	{
		"id": 12,
		"reached": false,
		"message": "The Lie"
	},
	{
		"id": 13,
		"reached": false,
		"message": "Getting an Upgrade"
	},
	{
		"id": 14,
		"reached": false,
		"message": "Time to Strike!"
	},
	{
		"id": 15,
		"reached": false,
		"message": "Librarian"
	}
];

// Main functions
function useItem(x, y, z, itemId, blockId, side, itemDamage, blockDamage)
{
	if(achievement[5]["reached"] === false && itemId == 58)
	{
		addonShowAchievement(5);
	}
	if(achievement[6]["reached"] === false && itemId == 61)
	{
		addonShowAchievement(6);
	}
	if(achievement[7]["reached"] === false && itemId == 270)
	{
		addonShowAchievement(7);
	}
	if(achievement[8]["reached"] === false && itemId == 265)
	{
		addonShowAchievement(8);
	}
	if(achievement[9]["reached"] === false && itemId == 290)
	{
		addonShowAchievement(9);
	}
	if(achievement[10]["reached"] === false && itemId == 297)
	{
		addonShowAchievement(10);
	}
	if(achievement[11]["reached"] === false && itemId == 354)
	{
		addonShowAchievement(11);
	}
	if(achievement[12]["reached"] === false)
	{
		if (itemId == 274 || itemId == 257 || itemId == 285 || itemId == 278)
		{
			addonShowAchievement(12);
		}
	}
	if(achievement[13]["reached"] === false && itemId == 268)
	{
		addonShowAchievement(13);
	}
	if(achievement[14]["reached"] === false && itemId == 47)
	{
		addonShowAchievement(14);
	}
}
function attackHook(attacker, victim)
{
	if(achievement[0]["reached"] === false)
	{
		if(Entity.getEntityTypeId(victim) == 32 || Entity.getEntityTypeId(victim) == 33 || Entity.getEntityTypeId(victim) == 34 || Entity.getEntityTypeId(victim) == 35 || Entity.getEntityTypeId(victim) == 36)
		{
			addonShowAchievement(0);
		}
	}
	if(achievement[1]["reached"] === false && Entity.getEntityTypeId(victim) == 11)
	{
		addonShowAchievement(1);
	}
	if(achievement[2]["reached"] === false && Entity.getEntityTypeId(victim) == 34 && Player.getCarriedItem() == 261)
	{
		addonShowAchievement(2);
	}
}
function procCmd(command)
{
	var cmd = command.toLowerCase().split(" ");
	switch(cmd[0])
	{
		case "ach":
		case "achievements":

			switch(cmd[1])
			{
				case "save":

					for(var i = 0; i < achievement.length; i++)
					{
						ModPE.saveData("a" + i, achievement[i]["reached"]);
					}
					addonColourMessage("Saved achievements!");
					break;

				case "load":

					for(var i = 0; i < achievement.length; i++)
					{
						achievement[i]["reached"] = ModPE.readData("a" + i);
					}
					addonColourMessage("Loaded achievements!");
					break;

				case "reset":

					for(var i = 0; i < achievement.length; i++)
					{
						achievement[i]["reached"] = false;
						ModPE.saveData("a" + i, achievement[i]);
					}
					addonColourMessage("Resetted achievements!");
					break;

				default:

					addonErrorMessage("Command " + p[1] + " does not exist!");
					break;
			}

		default:

			break;
	}
}
function destroyBlock(x, y, z, side)
{
	if (achievement[3]["reached"] === false && Level.getTile(x, y, z) == 17)
	{
		addonShowAchievement(3);
	}
	if (achievement[4]["reached"] === false && Level.getTile(x, y, z) == 56 && Player.getCarriedItem() == 257)
	{
		addonShowAchievement(4);
	}
}
function newLevel()
{
	for(var i = 0; i < achievement.length; i++)
	{
		achievement[i]["reached"] = ModPE.readData("a" + i);
	}
	clientMessage(ChatColor.GRAY + "[INFO] " + ChatColor.WHITE + project + " loaded");
}
function leaveGame()
{
	for(var i = 0; i < achievement.length; i++)
	{
		ModPE.saveData("a" + i, achievement[i]["reached"]);
	}
}

// Additional functions
function addonColourMessage(string)
{
	clientMessage(ChatColor.GRAY + "["+ ChatColor.RED + sname + ChatColor.GRAY +"] " + ChatColor.WHITE + string);
}
function addonErrorMessage(string)
{
	clientMessage(ChatColor.GRAY + "["+ ChatColor.RED + sname + ChatColor.GRAY +"] " + ChatColor.RED + string);
}
function addonShowAchievement(ID)
{
	achievement[ID]["reached"] = true;
	clientMessage("Achievement get! " + achievement[ID]["message"]);
}<|endoftext|>


<commit_before>// ==UserScript==
// @name         Remove Suggested Meetups
// @namespace    https://github.com/KyleMit/CustomizeTheWeb
// @version      1.1
// @description  Say goodbye to annoying suggested meetup requests that you can't get rid of
// @author       KyleMit
// @license      MIT
// @icon         http://kylemitofsky.com/favicon.png
// @run-at       document-end
// @match        https://www.meetup.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js
// @grant        none
// @homepage    https://github.com/KyleMit/CustomizeTheWeb#readme
// @homepageURL https://github.com/KyleMit/CustomizeTheWeb#readme
// @downloadURL https://github.com/KyleMit/CustomizeTheWeb/Scripts/FilterMeetup.js
// @updateURL   https://github.com/KyleMit/CustomizeTheWeb/Scripts/FilterMeetup.js
// @supportURL  https://github.com/KyleMit/CustomizeTheWeb/issues
// ==/UserScript==

/* global $ */

'use strict';

(function() {
    'use strict';

    var blacklist = ["WuXingCMA","Expressive-Arts-Beginning-Anew-Finding-Forgiveness"];
    var blRegex = new RegExp(blacklist.join("|"));
    $("a").filter(function(i,el) { return (blRegex.test(el.href)); })
	      .closest("li.event-listing")
	      .remove();
})();
<commit_msg>Update FilterMeetup.js<commit_after>// ==UserScript==
// @name         Remove Suggested Meetups
// @namespace    https://github.com/KyleMit/CustomizeTheWeb
// @version      1.1
// @description  Say goodbye to annoying suggested meetup requests that you can't get rid of
// @author       KyleMit
// @license      MIT
// @icon         http://kylemitofsky.com/favicon.png
// @run-at       document-end
// @match        https://www.meetup.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js
// @grant        none
// @homepage    https://github.com/KyleMit/CustomizeTheWeb#readme
// @homepageURL https://github.com/KyleMit/CustomizeTheWeb#readme
// @downloadURL https://github.com/KyleMit/CustomizeTheWeb/Scripts/FilterMeetup.js
// @updateURL   https://github.com/KyleMit/CustomizeTheWeb/Scripts/FilterMeetup.js
// @supportURL  https://github.com/KyleMit/CustomizeTheWeb/issues
// ==/UserScript==

/* global $ */

'use strict';

(function() {

    var blacklist = ["WuXingCMA","Expressive-Arts-Beginning-Anew-Finding-Forgiveness"];
    var blRegex = new RegExp(blacklist.join("|"));
    $("a").filter(function(i,el) { return (blRegex.test(el.href)); })
	      .closest("li.event-listing")
	      .remove();
})();
<|endoftext|>