<commit_before>/**
 * DataViewer class
 *
 * @author Aaron Ponti
 *
 */

/**
 * A viewer to display DataModel entities to the html page.
 */
function DataViewer() {

    "use strict";

};

/**
 * Displays experiment info
 *
 * @param exp openBIS Experiment object
 */
DataViewer.prototype.initView = function() {

    // Div IDs
    var experimentNameView, detailView;

    // Aliases
    var exp = DATAMODEL.exp;
    var dataSetCodes = DATAMODEL.dataSetCodes;

    // Get the experiment name view
    experimentNameView = $("#experimentNameView");
    experimentNameView.empty();

    // Get the detail view
    detailView = $("#detailView");
    detailView.empty();

    var spOp = "";
    var spCl = "";

    // Extract experiment name and underline it in code
    var name = "";
    var code = "";
    var indx = exp.code.lastIndexOf("_");
    if (indx != -1) {
        // Make sure we got the 18 random alphanumeric chars
        var suffix = exp.code.substr(indx);
        if (suffix.length == 19) {
            name = exp.code.substr(0, indx);
            code = "" + name + "" + suffix;
        } else {
            name = code;
        }
    }

    // Display the experiment name and code
    experimentNameView.append("
" + name + " (" + code + ")
");

    // Display the experiment description
    detailView.append(
            "
" + spOp + "Description" + spCl + "
" +
            "
" + exp.properties.MICROSCOPY_EXPERIMENT_DESCRIPTION + "
");

    // Display the viewer (it will take care of refreshing automatically when
    // the series cahnges, so we do no need to worry about it.
    this.displayViewer(dataSetCodes);

    // Refresh the series-dependent part of the UI. The same function will be attached
    // to the ChangeListener of the series selector widget, so that the various parts of
    // the UI are updated when the user chooses another series in the file.
    this.refreshView(dataSetCodes[0]);

};

/**
 * Update the view in response to a change in the selected series.
 * @param selectedSeries Index of the selected series.
 */
DataViewer.prototype.refreshView = function(dataSetCode) {

    // Display the metadata (for the first dataset)
    this.displayMetadata(dataSetCode);

    // Display the export action
    this.displayActions(DATAMODEL.exp);

};

/**
 * Display metadata for specified dataset code.
 * @param dataSetCode Data set code for which to display the metadata.
 */
DataViewer.prototype.displayMetadata = function(dataSetCode) {

    var spOp = "";
    var spCl = "";

    // Find data set object with given code
    var dataSet = [];
    for (var i = 0; i < DATAMODEL.dataSetCodes.length; i++) {
        if (DATAMODEL.dataSets[i].code == dataSetCode) {
            dataSet = DATAMODEL.dataSets[i];
            break;
        }
    }

    // Check that the dataset was found
    if (dataSet.length == 0) {
        this.displayStatus("Dataset with code " + dataSetCode + " not found!", "error");
        return;
    }

    // Get the metadata
    var metadata = dataSet.properties.MICROSCOPY_IMG_CONTAINER_METADATA;

    // Get the parameter view
    var paramView = $("#paramView");
    paramView.empty();

    var metadataObj;
    if (window.DOMParser)
    {
        var parser = new DOMParser();
        metadataObj = parser.parseFromString(metadata, "text/xml");
    }
    else // Internet Explorer
    {
        metadataObj = new ActiveXObject("Microsoft.XMLDOM");
        metadataObj.async = false;
        metadataObj.loadXML(metadata);
    }

    // Get the metadata for the series
    var seriesMetadata = metadataObj.children[0];
    var sizeX = seriesMetadata.attributes.getNamedItem("sizeX").value;
    var sizeY = seriesMetadata.attributes.getNamedItem("sizeY").value;
    var sizeZ = seriesMetadata.attributes.getNamedItem("sizeZ").value;
    var sizeC = seriesMetadata.attributes.getNamedItem("sizeC").value;
    var sizeT = seriesMetadata.attributes.getNamedItem("sizeT").value;
    var voxelX = seriesMetadata.attributes.getNamedItem("voxelX").value;
    var voxelY = seriesMetadata.attributes.getNamedItem("voxelY").value;
    var voxelZ = seriesMetadata.attributes.getNamedItem("voxelZ").value;

    // Format the metadata
    var sVoxelX = (new Number(voxelX)).toPrecision(2);
    var sVoxelY = (new Number(voxelY)).toPrecision(2);
    var sVoxelZ = (new Number(voxelZ)).toPrecision(2);

    // Display the metadata
    paramView.append(
            "
" + spOp + "Dataset sizes" + spCl + "
" +
            "

" +
                "
" +
                    "X	Y	Z	C	T	" +
                    "vX [µm]	vY [µm]	vZ [µm]	" +
                "
" +
                "
" +
                    "" + sizeX + "	" + sizeY + "	" + sizeZ + "	" +
                    "" + sizeC + "	" + sizeT + "	" +
                    "" + sVoxelX + "	" + sVoxelY + "	" + sVoxelZ + "	" +
                "
" +
            "

");
}

/**
 * Build and display the code to trigger the server-side aggregation
 * plugin 'copy_datasets_to_userdir'
 * @param node: DataTree node
 */
DataViewer.prototype.displayActions = function(exp) {

    // Get the detailViewAction div and empty it
    var detailViewAction = $("#detailViewAction");
    detailViewAction.empty();

    // Add actions
    detailViewAction.append(
        "
Actions
");

    // Get the experiment identifier
    var experimentId = exp.identifier;
    if (undefined === experimentId) {
        DATAVIEWER.displayStatus("Could not retrieve experiment identifier!", "error");
        return;
    }

    // Display metadata action
    $("#detailViewAction").append(
            "" +
            " " +
            "View/Edit metadata ");

    // Build and display the call
    callAggregationPlugin = DATAMODEL.copyDatasetsToUserDir;

    // Display the "Export to your folder" button only if enabled in the configuration file
    if (CONFIG['enableExportToUserFolder'] == true) {

        $("#detailViewAction").append(
                "" +
                " " +
                "Export to your folder ");
    }

    // Build and display the call for a zip archive
    $("#detailViewAction").append(
            "" +
            " " +
            "Download ");

};

/**
 * Display status text color-coded by level.
 * @param status: text to be displayed
 * @param level: one of "success", "info", "warning", "error". Default is
 * "info"
 *
 * @param tree DynaTree object
 */
DataViewer.prototype.displayStatus = function (status, level) {

    // Display the status
    $("#detailViewStatus").empty();

    switch (level) {
        case "success":
            cls = "success";
            break;
        case "info":
            cls = "info";
            break;
        case "warning":
            cls = "warning";
            break;
        case "error":
            cls = "danger";
            break;
        default:
            cls = "info";
            break;
    }

    status = "
" +
        status + "
";
    $("#detailViewStatus").html(status);

};

/**
 * Display the data viewer for a specified list of dataset codes.
 * @param dataSetCodes List of dataset codes to pass on to the ImageViewer.
 */
DataViewer.prototype.displayViewer = function(dataSetCodes) {

    // We need jQuery, openbis-screening and ImageViewerWidget
    require([ "jquery", "openbis-screening", "components/imageviewer/ImageViewerWidget" ], function($, openbis, ImageViewerWidget) {

        // Create the image viewer component for the specific data sets
        var widget = new ImageViewerWidget(window.DATAMODEL.openbisServer, dataSetCodes);

        // Do the customization once the component is loaded
        widget.addLoadListener(function() {
            var view = widget.getDataSetChooserWidget().getView();

            // Example of how to customize a widget
            view.getDataSetText = function(dataSetCode) {
                indx = DATAMODEL.dataSetCodes.indexOf(dataSetCode)
                return DATAMODEL.dataSets[indx].properties.MICROSCOPY_IMG_CONTAINER_NAME;
            };

            // Example of how to add a change listener to a widget
            widget.getDataSetChooserWidget().addChangeListener(function(event) {
                DATAVIEWER.refreshView(event.getNewValue());
            });
        });

        // Render the component and add it to the page
        $("#imageViewer").empty();
        $("#imageViewer").append(widget.render());

    });

};<commit_msg>Use jQuery.parseXML() instead of DOMParser() for portability to parse metadata XML.<commit_after>/**
 * DataViewer class
 *
 * @author Aaron Ponti
 *
 */

/**
 * A viewer to display DataModel entities to the html page.
 */
function DataViewer() {

    "use strict";

};

/**
 * Displays experiment info
 *
 * @param exp openBIS Experiment object
 */
DataViewer.prototype.initView = function() {

    // Div IDs
    var experimentNameView, detailView;

    // Aliases
    var exp = DATAMODEL.exp;
    var dataSetCodes = DATAMODEL.dataSetCodes;

    // Get the experiment name view
    experimentNameView = $("#experimentNameView");
    experimentNameView.empty();

    // Get the detail view
    detailView = $("#detailView");
    detailView.empty();

    var spOp = "";
    var spCl = "";

    // Extract experiment name and underline it in code
    var name = "";
    var code = "";
    var indx = exp.code.lastIndexOf("_");
    if (indx != -1) {
        // Make sure we got the 18 random alphanumeric chars
        var suffix = exp.code.substr(indx);
        if (suffix.length == 19) {
            name = exp.code.substr(0, indx);
            code = "" + name + "" + suffix;
        } else {
            name = code;
        }
    }

    // Display the experiment name and code
    experimentNameView.append("
" + name + " (" + code + ")
");

    // Display the experiment description
    detailView.append(
            "
" + spOp + "Description" + spCl + "
" +
            "
" + exp.properties.MICROSCOPY_EXPERIMENT_DESCRIPTION + "
");

    // Display the viewer (it will take care of refreshing automatically when
    // the series cahnges, so we do no need to worry about it.
    this.displayViewer(dataSetCodes);

    // Refresh the series-dependent part of the UI. The same function will be attached
    // to the ChangeListener of the series selector widget, so that the various parts of
    // the UI are updated when the user chooses another series in the file.
    this.refreshView(dataSetCodes[0]);

};

/**
 * Update the view in response to a change in the selected series.
 * @param selectedSeries Index of the selected series.
 */
DataViewer.prototype.refreshView = function(dataSetCode) {

    // Display the metadata (for the first dataset)
    this.displayMetadata(dataSetCode);

    // Display the export action
    this.displayActions(DATAMODEL.exp);

};

/**
 * Display metadata for specified dataset code.
 * @param dataSetCode Data set code for which to display the metadata.
 */
DataViewer.prototype.displayMetadata = function(dataSetCode) {

    var spOp = "";
    var spCl = "";

    // Find data set object with given code
    var dataSet = [];
    for (var i = 0; i < DATAMODEL.dataSetCodes.length; i++) {
        if (DATAMODEL.dataSets[i].code == dataSetCode) {
            dataSet = DATAMODEL.dataSets[i];
            break;
        }
    }

    // Check that the dataset was found
    if (dataSet.length == 0) {
        this.displayStatus("Dataset with code " + dataSetCode + " not found!", "error");
        return;
    }

    // Get the metadata
    var metadata = dataSet.properties.MICROSCOPY_IMG_CONTAINER_METADATA;

    // Get the parameter view
    var paramView = $("#paramView");
    paramView.empty();

    // Use JQuery to parse the metadata XML into an object
    var metadataObj = $.parseXML(metadata);

    // Check whether we found metadata information
    if (! metadataObj.hasChildNodes()) {
        paramView.empty();
        paramView.append("No metadata information found.");
        return;
    }

    // Get the metadata for the series and display it
    var seriesMetadata = metadataObj.childNodes[0];
    var sizeX = seriesMetadata.attributes.getNamedItem("sizeX").value;
    var sizeY = seriesMetadata.attributes.getNamedItem("sizeY").value;
    var sizeZ = seriesMetadata.attributes.getNamedItem("sizeZ").value;
    var sizeC = seriesMetadata.attributes.getNamedItem("sizeC").value;
    var sizeT = seriesMetadata.attributes.getNamedItem("sizeT").value;
    var voxelX = seriesMetadata.attributes.getNamedItem("voxelX").value;
    var voxelY = seriesMetadata.attributes.getNamedItem("voxelY").value;
    var voxelZ = seriesMetadata.attributes.getNamedItem("voxelZ").value;

    // Format the metadata
    var sVoxelX = (new Number(voxelX)).toPrecision(2);
    var sVoxelY = (new Number(voxelY)).toPrecision(2);
    var sVoxelZ = (new Number(voxelZ)).toPrecision(2);

    // Display the metadata
    paramView.append(
            "
" + spOp + "Dataset sizes" + spCl + "
" +
            "

" +
                "
" +
                    "X	Y	Z	C	T	" +
                    "vX [µm]	vY [µm]	vZ [µm]	" +
                "
" +
                "
" +
                    "" + sizeX + "	" + sizeY + "	" + sizeZ + "	" +
                    "" + sizeC + "	" + sizeT + "	" +
                    "" + sVoxelX + "	" + sVoxelY + "	" + sVoxelZ + "	" +
                "
" +
            "

");
}

/**
 * Build and display the code to trigger the server-side aggregation
 * plugin 'copy_datasets_to_userdir'
 * @param node: DataTree node
 */
DataViewer.prototype.displayActions = function(exp) {

    // Get the detailViewAction div and empty it
    var detailViewAction = $("#detailViewAction");
    detailViewAction.empty();

    // Add actions
    detailViewAction.append(
        "
Actions
");

    // Get the experiment identifier
    var experimentId = exp.identifier;
    if (undefined === experimentId) {
        DATAVIEWER.displayStatus("Could not retrieve experiment identifier!", "error");
        return;
    }

    // Display metadata action
    $("#detailViewAction").append(
            "" +
            " " +
            "View/Edit metadata ");

    // Build and display the call
    callAggregationPlugin = DATAMODEL.copyDatasetsToUserDir;

    // Display the "Export to your folder" button only if enabled in the configuration file
    if (CONFIG['enableExportToUserFolder'] == true) {

        $("#detailViewAction").append(
                "" +
                " " +
                "Export to your folder ");
    }

    // Build and display the call for a zip archive
    $("#detailViewAction").append(
            "" +
            " " +
            "Download ");

};

/**
 * Display status text color-coded by level.
 * @param status: text to be displayed
 * @param level: one of "success", "info", "warning", "error". Default is
 * "info"
 *
 * @param tree DynaTree object
 */
DataViewer.prototype.displayStatus = function (status, level) {

    // Display the status
    $("#detailViewStatus").empty();

    switch (level) {
        case "success":
            cls = "success";
            break;
        case "info":
            cls = "info";
            break;
        case "warning":
            cls = "warning";
            break;
        case "error":
            cls = "danger";
            break;
        default:
            cls = "info";
            break;
    }

    status = "
" +
        status + "
";
    $("#detailViewStatus").html(status);

};

/**
 * Display the data viewer for a specified list of dataset codes.
 * @param dataSetCodes List of dataset codes to pass on to the ImageViewer.
 */
DataViewer.prototype.displayViewer = function(dataSetCodes) {

    // We need jQuery, openbis-screening and ImageViewerWidget
    require([ "jquery", "openbis-screening", "components/imageviewer/ImageViewerWidget" ], function($, openbis, ImageViewerWidget) {

        // Create the image viewer component for the specific data sets
        var widget = new ImageViewerWidget(DATAMODEL.openbisServer, dataSetCodes);

        // Do the customization once the component is loaded
        widget.addLoadListener(function() {
            var view = widget.getDataSetChooserWidget().getView();

            // Example of how to customize a widget
            view.getDataSetText = function(dataSetCode) {
                indx = DATAMODEL.dataSetCodes.indexOf(dataSetCode)
                return DATAMODEL.dataSets[indx].properties.MICROSCOPY_IMG_CONTAINER_NAME;
            };

            // Example of how to add a change listener to a widget
            widget.getDataSetChooserWidget().addChangeListener(function(event) {
                DATAVIEWER.refreshView(event.getNewValue());
            });
        });

        // Render the component and add it to the page
        $("#imageViewer").empty();
        $("#imageViewer").append(widget.render());

    });

};<|endoftext|>


<commit_before>describe('scroll when focus line is out of viewport', function () {
  before(function (done) {
    helper.newPad(function(){
      cleanPad(function(){
        forceUseMonospacedFont();
        scrollWhenPlaceCaretInTheLastLineOfViewport();
        createPadWithSeveralLines(function(){
          resizeEditorHeight();
          done();
        });
      });
    });
    this.timeout(20000);
  });

  context('when user presses any arrow keys on a line above the viewport', function(){
    context('and scroll percentage config is set to 0.2 on settings.json', function(){
      var lineCloseOfTopOfPad = 10;
      before(function (done) {
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true);
        scrollEditorToBottomOfPad();

        placeCaretInTheBeginningOfLine(lineCloseOfTopOfPad, function(){ // place caret in the 10th line
          // warning: even pressing right arrow, the caret does not change of position
          // the column where the caret is, it has not importance, only the line
          pressAndReleaseRightArrow(); // I don't think this is working in Edge.
          done();
        });
      });

      it('keeps the focus line scrolled 20% from the top of the viewport', function (done) {
        // default behavior is to put the line in the top of viewport, but as
        // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
        // (2 lines, which are the 20% of the 10 that are visible on viewport)
        var firstLineOfViewport = getFirstLineVisibileOfViewport();
        expect(lineCloseOfTopOfPad).to.be(firstLineOfViewport + 2);
        done();
      });
    });
  });

  context('when user presses any arrow keys on a line below the viewport', function(){
    context('and scroll percentage config is set to 0.7 on settings.json', function(){
      var lineCloseToBottomOfPad = 50;
      before(function (done) {
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.7);

        // firstly, scroll to make the lineCloseToBottomOfPad visible. After that, scroll to make it out of viewport
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lineCloseToBottomOfPad); // place caret in the 50th line
        setTimeout(function() {
          // warning: even pressing right arrow, the caret does not change of position
          pressAndReleaseLeftArrow();
          done();
        }, 1000);
      });

      it('keeps the focus line scrolled 70% from the bottom of the viewport', function (done) {
        // default behavior is to put the line in the top of viewport, but as
        // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.7, we have an extra 70% of lines scrolled
        // (7 lines, which are the 70% of the 10 that are visible on viewport)
        var lastLineOfViewport = getLastLineVisibleOfViewport();
        expect(lineCloseToBottomOfPad).to.be(lastLineOfViewport - 7);
        done();
      });
    });
  });

  context('when user presses arrow up on the first line of the viewport', function(){
    context('and percentageToScrollWhenUserPressesArrowUp is set to 0.3 -- Broken in All browsers??', function () {
      var lineOnTopOfViewportWhenThePadIsScrolledDown;
      before(function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test

        setPercentageToScrollWhenUserPressesArrowUp(0.3);

        // we need some room to make the scroll up
        scrollEditorToBottomOfPad();
        lineOnTopOfViewportWhenThePadIsScrolledDown = 91;
        placeCaretAtTheEndOfLine(lineOnTopOfViewportWhenThePadIsScrolledDown);
        // setTimeout(function() {
          // warning: even pressing up arrow, the caret does not change of position
          pressAndReleaseUpArrow();
          done();
        // }, 2000);
      });

      it('keeps the focus line scrolled 30% of the top of the viewport', function (done) {
        // if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        return done(); // skip this test
        // default behavior is to put the line in the top of viewport, but as
        // PercentageToScrollWhenUserPressesArrowUp is set to 0.3, we have an extra 30% of lines scrolled
        // (3 lines, which are the 30% of the 10 that are visible on viewport)
        var firstLineOfViewport = getFirstLineVisibileOfViewport();
        expect(firstLineOfViewport).to.be(lineOnTopOfViewportWhenThePadIsScrolledDown - 3);
        done();
      })
    });
  });

// Below tests are broken in Edge

  context('when user edits the last line of viewport -- Known Broken in Edge', function(){

    context('and scroll percentage config is set to 0 on settings.json -- Broken in Edge', function(){
      var lastLineOfViewportBeforeEnter = 10;
      before(function () {
        // the default value
        resetScrollPercentageWhenFocusLineIsOutOfViewport();

        // make sure the last line on viewport is the 10th one
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
        pressEnter(); // doesn't work in Edge
      });

      it('keeps the focus line on the bottom of the viewport', function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
        expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
        done();
      });
    });

    context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3 -- Broken in Edge', function(){ // this value is arbitrary
      var lastLineOfViewportBeforeEnter = 9;
      before(function () {
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.3);

        // make sure the last line on viewport is the 10th one
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
        pressBackspace();
      });

      it('scrolls 30% of viewport up', function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
        // default behavior is to scroll one line at the bottom of viewport, but as
        // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3, we have an extra 30% of lines scrolled
        // (3 lines, which are the 30% of the 10 that are visible on viewport)
        expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 3);
        done();
      });
    });

    context('and it is set to a value that overflow the interval [0, 1] -- Broken in Edge', function(){
      var lastLineOfViewportBeforeEnter = 10;
      before(function(){
        var scrollPercentageWhenFocusLineIsOutOfViewport = 1.5;
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
        setScrollPercentageWhenFocusLineIsOutOfViewport(scrollPercentageWhenFocusLineIsOutOfViewport);
        pressEnter(); // doesn't work in Edge
      });

      it('keeps the default behavior of moving the focus line on the bottom of the viewport -- Broken in Edge', function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
        expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
        done();
      });
    });
  });

  context('when user edits a line above the viewport -- Broken in Edge', function(){
    context('and scroll percentage config is set to 0 on settings.json -- Broken in Edge', function(){
      var lineCloseOfTopOfPad = 10;
      before(function () {
        // the default value
        setScrollPercentageWhenFocusLineIsOutOfViewport(0);

        // firstly, scroll to make the lineCloseOfTopOfPad visible. After that, scroll to make it out of viewport
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lineCloseOfTopOfPad); // place caret in the 10th line
        scrollEditorToBottomOfPad();
        pressBackspace(); // edit the line where the caret is, which is above the viewport
      });

      it('keeps the focus line on the top of the viewport -- Broken in Edge', function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        var firstLineOfViewportAfterEnter = getFirstLineVisibileOfViewport();
        expect(firstLineOfViewportAfterEnter).to.be(lineCloseOfTopOfPad);
        done();
      });
    });

    context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2 -- Broken in Edge', function(){ // this value is arbitrary
      var lineCloseToBottomOfPad = 50;
      before(function () {
        // we force the line edited to be above the top of the viewport
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true); // set scroll jump to 20%
        scrollEditorToTopOfPad();
        placeCaretAtTheEndOfLine(lineCloseToBottomOfPad);
        scrollEditorToBottomOfPad();
        pressBackspace(); // edit line
      });

      it('scrolls 20% of viewport down', function (done) {
        if(window.navigator.userAgent.indexOf("Edge") > -1) return done(); // Skip the test if we're in Edge
        // default behavior is to scroll one line at the top of viewport, but as
        // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
        // (2 lines, which are the 20% of the 10 that are visible on viewport)
        var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
        expect(lineCloseToBottomOfPad).to.be(firstLineVisibileOfViewport + 2);
        done();
      });
    });
  });

  // End of tests that are broken in Edge

  context('when user places the caret at the last line visible of viewport', function(){
    var lastLineVisible;
    context('and scroll percentage config is set to 0 on settings.json', function(){
      before(function (done) {
        // reset to the default value
        resetScrollPercentageWhenFocusLineIsOutOfViewport();

        placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
          scrollEditorToTopOfPad();
          lastLineVisible = getLastLineVisibleOfViewport();
          placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
        });

      });

      it('does not scroll', function(done){
        setTimeout(function() {
          var lastLineOfViewport = getLastLineVisibleOfViewport();
          var lineDoesNotScroll = lastLineOfViewport === lastLineVisible;
          expect(lineDoesNotScroll).to.be(true);
          done();
        }, 1000);
      });
    });
    context('and scroll percentage config is set to 0.5 on settings.json', function(){
      before(function (done) {
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.5);
        scrollEditorToTopOfPad();
        placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
          // this timeout inside a callback is ugly but it necessary to give time to aceSelectionChange
          // realizes that the selection has been changed
          setTimeout(function() {
            lastLineVisible = getLastLineVisibleOfViewport();
            placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
          }, 1000);
        });
      });

      it('scrolls line to 50% of the viewport', function(done){
        helper.waitFor(function(){
          var lastLineOfViewport = getLastLineVisibleOfViewport();
          var lastLinesScrolledFiveLinesUp = lastLineOfViewport - 5 === lastLineVisible;
          return lastLinesScrolledFiveLinesUp;
        }).done(done);
      });
    });
  });

  // This is a special case. When user is selecting a text with arrow down or arrow left we have
  // to keep the last line selected on focus
  context('when the first line selected is out of the viewport and user presses shift arrow down', function(){
    var lastLineOfPad = 99;
    before(function (done) {
      scrollEditorToTopOfPad();

      // make a selection bigger than the viewport height
      var $firstLineOfSelection = getLine(0);
      var $lastLineOfSelection = getLine(lastLineOfPad);
      var lengthOfLastLine = $lastLineOfSelection.text().length;
      helper.selectLines($firstLineOfSelection, $lastLineOfSelection, 0, lengthOfLastLine);

      // place the last line selected on the viewport
      scrollEditorToBottomOfPad();

      // press a key to make the selection goes down
      // although we can't simulate the extending of selection. It's possible to send a key event
      // which is captured on ace2_inner scroll function.
      pressAndReleaseLeftArrow(true);
      done();
    });

    it('keeps the last line selected on focus', function (done) {
      var lastLineOfSelectionIsVisible = isLineOnViewport(lastLineOfPad);
      expect(lastLineOfSelectionIsVisible).to.be(true);
      done();
    });
  });

  // In this scenario we avoid the bouncing scroll. E.g Let's suppose we have a big line that is
  // the size of the viewport, and its top is above the viewport. When user presses '<-', this line
  // will scroll down because the top is out of the viewport. When it scrolls down, the bottom of
  // line gets below the viewport so when user presses '<-' again it scrolls up to make the bottom
  // of line visible. If user presses arrow keys more than one time, the editor will keep scrolling up and down
  context('when the line height is bigger than the scroll amount percentage * viewport height', function(){
    var scrollOfEditorBeforePressKey;
    var BIG_LINE_NUMBER = 0;
    var MIDDLE_OF_BIG_LINE = 51;
    before(function (done) {
      createPadWithALineHigherThanViewportHeight(this, BIG_LINE_NUMBER, function(){
        setScrollPercentageWhenFocusLineIsOutOfViewport(0.5); // set any value to force scroll to outside to viewport
        var $bigLine = getLine(BIG_LINE_NUMBER);

        // each line has about 5 chars, we place the caret in the middle of the line
        helper.selectLines($bigLine, $bigLine, MIDDLE_OF_BIG_LINE, MIDDLE_OF_BIG_LINE);

        scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport($bigLine);
        scrollOfEditorBeforePressKey = getEditorScroll();

        // press a key to force to scroll
        pressAndReleaseRightArrow();
        done();
      });
    });

    // reset pad to the original text
    after(function (done) {
      this.timeout(5000);
      cleanPad(function(){
        createPadWithSeveralLines(function(){
          resetEditorWidth();
          done();
        });
      });
    });

    // as the editor.line is inside of the viewport, it should not scroll
    it('should not scroll', function (done) {
      var scrollOfEditorAfterPressKey = getEditorScroll();
      expect(scrollOfEditorAfterPressKey).to.be(scrollOfEditorBeforePressKey);
      done();
    });
  });

  // Some plugins, for example the ep_page_view, change the editor dimensions. This plugin, for example,
  // adds padding-top to the ace_outer, which changes the viewport height
  describe('integration with plugins which changes the margin of editor', function(){
    context('when editor dimensions changes', function(){
      before(function () {
        // reset the size of editor. Now we show more than 10 lines as in the other tests
        resetResizeOfEditorHeight();
        scrollEditorToTopOfPad();

        // height of the editor viewport
        var editorHeight = getEditorHeight();

        // add a big padding-top, 50% of the viewport
        var paddingTopOfAceOuter = editorHeight/2;
        var chrome$ = helper.padChrome$;
        var $outerIframe = chrome$('iframe');
        $outerIframe.css('padding-top', paddingTopOfAceOuter);

        // we set a big value to check if the scroll is made
        setScrollPercentageWhenFocusLineIsOutOfViewport(1);
      });

      context('and user places the caret in the last line visible of the pad', function(){
        var lastLineVisible;
        beforeEach(function (done) {
          lastLineVisible = getLastLineVisibleOfViewport();
          placeCaretInTheBeginningOfLine(lastLineVisible, done);
        });

        it('scrolls the line where caret is', function(done){
          helper.waitFor(function(){
            var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
            var linesScrolled = firstLineVisibileOfViewport !== 0;
            return linesScrolled;
          }).done(done);
        });
      });
    });
  });

  /* ********************* Helper functions/constants ********************* */
  var TOP_OF_PAGE = 0;
  var BOTTOM_OF_PAGE = 5000; // we use a big value to force the page to be scrolled all the way down
  var LINES_OF_PAD = 100;
  var ENTER = 13;
  var BACKSPACE = 8;
  var LEFT_ARROW = 37;
  var UP_ARROW = 38;
  var RIGHT_ARROW = 39;
  var LINES_ON_VIEWPORT = 10;
  var WIDTH_OF_EDITOR_RESIZED = 100;
  var LONG_TEXT_CHARS = 100;

  var cleanPad = function(callback) {
    var inner$ = helper.padInner$;
    var $padContent = inner$('#innerdocbody');
    $padContent.html('');

    // wait for Etherpad to re-create first line
    helper.waitFor(function(){
      var lineNumber = inner$('div').length;
      return lineNumber === 1;
    }, 2000).done(callback);
  };

  var createPadWithSeveralLines = function(done) {
    var line = 'a
';
    var $firstLine = helper.padInner$('div').first();
    var lines = line.repeat(LINES_OF_PAD); //arbitrary number, we need to create lines that is over the viewport
    $firstLine.html(lines);

    helper.waitFor(function(){
      var linesCreated = helper.padInner$('div').length;
      return linesCreated === LINES_OF_PAD;
    }, 4000).done(done);
  };

  var createPadWithALineHigherThanViewportHeight = function(test, line, done) {
    var viewportHeight = 160; //10 lines * 16px (height of line)
    test.timeout(5000);
    cleanPad(function(){
      // make the editor smaller to make test easier
      // with that width the each line has about 5 chars
      resizeEditorWidth();

      // we create a line with 100 chars, which makes about 20 lines
      setLongTextOnLine(line);
      helper.waitFor(function () {
        var $firstLine = getLine(line);

        var heightOfLine = $firstLine.get(0).getBoundingClientRect().height;
        return heightOfLine >= viewportHeight;
      }, 4000).done(done);
    });
  };

  var setLongTextOnLine = function(line) {
    var $line = getLine(line);
    var longText = 'a'.repeat(LONG_TEXT_CHARS);
    $line.html(longText);
  };

  // resize the editor to make the tests easier
  var resizeEditorHeight = function() {
    var chrome$ = helper.padChrome$;
    chrome$('#editorcontainer').css('height', getSizeOfViewport());
  };

  // this makes about 5 chars per line
  var resizeEditorWidth = function() {
    var chrome$ = helper.padChrome$;
    chrome$('#editorcontainer').css('width', WIDTH_OF_EDITOR_RESIZED);
  };

  var resetResizeOfEditorHeight = function() {
    var chrome$ = helper.padChrome$;
    chrome$('#editorcontainer').css('height', '');
  };

  var resetEditorWidth = function () {
    var chrome$ = helper.padChrome$;
    chrome$('#editorcontainer').css('width', '');
  };

  var getEditorHeight = function() {
    var chrome$ = helper.padChrome$;
    var $editor = chrome$('#editorcontainer');
    var editorHeight = $editor.get(0).clientHeight;
    return editorHeight;
  };

  var getSizeOfViewport = function() {
    return getLinePositionOnViewport(LINES_ON_VIEWPORT) - getLinePositionOnViewport(0);
  };

  var scrollPageTo = function(value) {
    var outer$ = helper.padOuter$;
    var $ace_outer = outer$('#outerdocbody').parent();
    $ace_outer.parent().scrollTop(value);
  };

  var scrollEditorToTopOfPad = function() {
    scrollPageTo(TOP_OF_PAGE);
  };

  var scrollEditorToBottomOfPad = function() {
    scrollPageTo(BOTTOM_OF_PAGE);
  };

  var scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport = function ($bigLine) {
    var lineHeight = $bigLine.get(0).getBoundingClientRect().height;
    var middleOfLine = lineHeight/2;
    scrollPageTo(middleOfLine);
  };

  var getLine = function(lineNum) {
    var inner$ = helper.padInner$;
    var $line = inner$('div').eq(lineNum);
    return $line;
  };

  var placeCaretAtTheEndOfLine = function(lineNum) {
    var $targetLine = getLine(lineNum);
    var lineLength = $targetLine.text().length;
    helper.selectLines($targetLine, $targetLine, lineLength, lineLength);
  };

  var placeCaretInTheBeginningOfLine = function(lineNum, cb) {
    var $targetLine = getLine(lineNum);
    helper.selectLines($targetLine, $targetLine, 0, 0);
    helper.waitFor(function() {
      var $lineWhereCaretIs = getLineWhereCaretIs();
      return $targetLine.get(0) === $lineWhereCaretIs.get(0);
    }).done(cb);
  };

  var getLineWhereCaretIs = function() {
    var inner$ = helper.padInner$;
    var nodeWhereCaretIs = inner$.document.getSelection().anchorNode;
    var $lineWhereCaretIs = $(nodeWhereCaretIs).closest('div');
    return $lineWhereCaretIs;
  };

  var getFirstLineVisibileOfViewport = function() {
    return _.find(_.range(0, LINES_OF_PAD - 1), isLineOnViewport);
  };

  var getLastLineVisibleOfViewport = function() {
    return _.find(_.range(LINES_OF_PAD - 1, 0, -1), isLineOnViewport);
  };

  var pressKey = function(keyCode, shiftIsPressed){
    var inner$ = helper.padInner$;

    /*
     * These events use keydown and up, not keypress.
     * Do not change. Changing to keypress will break Edge.
     */
    var e = inner$.Event("keydown");

    e.shiftKey = shiftIsPressed || false;
    e.keyCode = keyCode;
    e.which = keyCode; // etherpad listens to 'which'
    inner$('#innerdocbody').trigger(e);
  };

  var releaseKey = function(keyCode){
    var inner$ = helper.padInner$;

    /*
     * These events use keydown and up, not keypress.
     * Do not change. Changing to keypress will break Edge.
     */
    var e = inner$.Event("keyup");

    e.keyCode = keyCode;
    e.which = keyCode; // etherpad listens to 'which'
    inner$('#innerdocbody').trigger(e);
  };

  var pressEnter = function() {
    pressKey(ENTER); // This doesn't work in Edge
  };

  var pressBackspace = function() {
    pressKey(BACKSPACE);
  };

  var pressAndReleaseUpArrow = function() {
    pressKey(UP_ARROW);
    releaseKey(UP_ARROW);
  };

  var pressAndReleaseRightArrow = function() {
    pressKey(RIGHT_ARROW);
    releaseKey(RIGHT_ARROW);
  };

  var pressAndReleaseLeftArrow = function(shiftIsPressed) {
    pressKey(LEFT_ARROW, shiftIsPressed);
    releaseKey(LEFT_ARROW);
  };

  var isLineOnViewport = function(lineNumber) {
    // in the function scrollNodeVerticallyIntoView from ace2_inner.js, iframePadTop is used to calculate
    // how much scroll is needed. Although the name refers to padding-top, this value is not set on the
    // padding-top.
    var iframePadTop = 8;
    var $line = getLine(lineNumber);
    var linePosition = $line.get(0).getBoundingClientRect();

    // position relative to the current viewport
    var linePositionTopOnViewport = linePosition.top - getEditorScroll() + iframePadTop;
    var linePositionBottomOnViewport = linePosition.bottom - getEditorScroll();

    var lineBellowTop = linePositionBottomOnViewport > 0;
    var lineAboveBottom = linePositionTopOnViewport < getClientHeightVisible();
    var isVisible = lineBellowTop && lineAboveBottom;

    return isVisible;
  };

  var getEditorScroll = function () {
    var outer$ = helper.padOuter$;
    var scrollTopFirefox = outer$('#outerdocbody').parent().scrollTop(); // works only on firefox
    var scrollTop = outer$('#outerdocbody').scrollTop() || scrollTopFirefox;
    return scrollTop;
  };

  // clientHeight includes padding, so we have to subtract it and consider only the visible viewport
  var getClientHeightVisible = function () {
    var outer$ = helper.padOuter$;
    var $ace_outer = outer$('#outerdocbody').parent();
    var ace_outerHeight = $ace_outer.get(0).clientHeight;
    var ace_outerPaddingTop = getIntValueOfCSSProperty($ace_outer, 'padding-top');
    var paddingAddedWhenPageViewIsEnable = getPaddingAddedWhenPageViewIsEnable();
    var clientHeight = ace_outerHeight - ( ace_outerPaddingTop + paddingAddedWhenPageViewIsEnable);

    return clientHeight;
  };

  // ep_page_view changes the dimensions of the editor. We have to guarantee
  // the viewport height is calculated right
  var getPaddingAddedWhenPageViewIsEnable = function () {
    var chrome$ = helper.padChrome$;
    var $outerIframe = chrome$('iframe');
    var paddingAddedWhenPageViewIsEnable = parseInt($outerIframe.css('padding-top'));
    return paddingAddedWhenPageViewIsEnable;
  };

  var getIntValueOfCSSProperty = function($element, property){
    var valueString = $element.css(property);
    return parseInt(valueString) || 0;
  };

  var forceUseMonospacedFont = function () {
    helper.padChrome$.window.clientVars.padOptions.useMonospaceFont = true;
  };

  var setScrollPercentageWhenFocusLineIsOutOfViewport = function(value, editionAboveViewport) {
    var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
    if (editionAboveViewport) {
      scrollSettings.percentage.editionAboveViewport = value;
    }else{
      scrollSettings.percentage.editionBelowViewport = value;
    }
  };

  var resetScrollPercentageWhenFocusLineIsOutOfViewport = function() {
    var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
    scrollSettings.percentage.editionAboveViewport = 0;
    scrollSettings.percentage.editionBelowViewport = 0;
  };

  var setPercentageToScrollWhenUserPressesArrowUp = function (value) {
    var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
    scrollSettings.percentageToScrollWhenUserPressesArrowUp = value;
  };

  var scrollWhenPlaceCaretInTheLastLineOfViewport = function() {
    var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
    scrollSettings.scrollWhenCaretIsInTheLastLineOfViewport = true;
  };

  var getLinePositionOnViewport = function(lineNumber) {
    var $line = getLine(lineNumber);
    var linePosition = $line.get(0).getBoundingClientRect();

    // position relative to the current viewport
    return linePosition.top - getEditorScroll();
  };
});

<commit_msg>tests: remove the scroll tests (#3897)<commit_after><|endoftext|>


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

    var assert = require('assert'),
        Validator = require('../src/validator.js') ;

    describe('validator in the wild', function () {
        this.timeout(10000);

        it('loads all referenced remote schemas', function (done) {

            Validator.simple(
                'https://www.swisshotels.com/availabilities-filtered/schema',

                function (error) {
                    assert.ifError(error);
                    done();
                }
            );
        });

        it('does actual validation', function (done) {
            Validator.simple('http://json-schema.org/geo', function (error, v) {
                assert.ifError(error);

                assert(v.validate(
                    {latitude: 53.0, longitude: 43.0},
                    'http://json-schema.org/geo'
                ).valid);

                done();
            });
        });
    });
}());
<commit_msg>Raise the time-out a bit after a Travis CI failure<commit_after>(function () {
    'use strict';

    var assert = require('assert'),
        Validator = require('../src/validator.js') ;

    describe('validator in the wild', function () {
        this.timeout(16000);

        it('loads all referenced remote schemas', function (done) {

            Validator.simple(
                'https://www.swisshotels.com/availabilities-filtered/schema',

                function (error) {
                    assert.ifError(error);
                    done();
                }
            );
        });

        it('does actual validation', function (done) {
            Validator.simple('http://json-schema.org/geo', function (error, v) {
                assert.ifError(error);

                assert(v.validate(
                    {latitude: 53.0, longitude: 43.0},
                    'http://json-schema.org/geo'
                ).valid);

                done();
            });
        });
    });
}());
<|endoftext|>


<commit_before>/**
 * Created by apple on 14-4-28.
 */

exports.error_code = {

    0:"执行成功",
    1:"请先设置环境变量 {color_green}EGRET_PATH{color_normal}。您可以访问 {color_underline}https://github.com/egret-team/egret/wiki/Setting-environment-variables{color_normal} 获取更多细节",
    2:"TypeScript编译器尚未安装，请执行 {color_green}npm install -g typescript{color_normal} 进行安装",
    1001:"请输入项目名称。例: {color_green}egret create [project_name]{color_normal}",
    1002:"该项目已存在",
    1101:"请输入项目名称。例:{color_green}egret build [project_name]{color_normal}",
    1102:"指定項目中不存在 bin-debug 文件夾，请执行 {color_green}egret build [project_name] -e {color_normal} 初始化引擎",
    1103:"{0}: error 类文件之间存在循环依赖，请检查类的继承关系或静态变量的初始化引用。",
    1301:"在编译路径 {0} 下找不到 egret_file_list.js 或 game_file_list.js，请检查编译路径是否正确",
    1302:"请输入编译路径。例:{color_green}egret compile --source [your_typescript_source_dir] --output [your_output_dir]{color_normal}",
    1303:"编译失败",
    1304:"解析manifest.json文件失败，请检查文件是否为正确的JSON格式:\n{0}",
    1305:"读取launcher/{0}.html失败，请检查编译路径是否正确",
    1306:"在launcher/{0}内找不到文档类'document_class'的变量定义，请检查文件内容是否正确",
    1307:"模块 {0} 中不存在任何 .ts 或 .d.ts 文件，无法编译，请在模块的 file_list 字段中填写 .ts 或 .d.ts ",
    1401:"找不到java或java版本过低（最低需求为 java 7 ),请安装java并执行 egret publish -testJava 命令进行测试",
    1501:"无法启动服务器，请检查权限或端口是否被占用",
    1601:"请输入项目名称, h5游戏目录以及手机平台支持库。例: {color_green}egret create_app [app_name] -f [h5_game_path] -t [template_path] {color_normal} \n如没有安装最新手机平台支持库，请从以下地址下载：\nAndroid: http://www.egret-labs.org/download/egret-android-packager-download.html, \niOS:http://www.egret-labs.org/download/egret-ios-packager-download.html",
    1602:"缺少egretProperties.json或格式不正确。 \n请从http://www.egret-labs.org/download/egret-download.html升级egret-core到最新版",
    1603:"缺少create_app.json。\n请从以下地址下载最新手机平台支持库\nAndroid: http://www.egret-labs.org/download/egret-android-packager-download.html, \n\tiOS: http://www.egret-labs.org/download/egret-ios-packager-download.html",
    1604:"执行egret build命令失败",
    1605:"移动平台项目目录不能与html5项目目录为同一目录，请修改移动平台项目目录。",
    1701:"项目版本低于 egret 版本，请执行 egret upgrade {your_project} 命令升级您的项目，\n命令中请不要加上大括号{}",
    1702:"项目升级后，请执行一次 egret build {your_project} {color_green}-e{color_normal} 编译引擎，\n命令中请不要加上大括号{}",
    1703:"\n升级第一步完成，{color_red}请按 {color_underline}https://github.com/egret-labs/egret-core/wiki/Egret_Upgrade/upgrade/index.html{color_red} 完成剩余升级步骤{color_normal}\n",
    9999:"未知错误:{0}",
    8001:"请输入命令行选项{color_green} {0} {color_normal}的参数,并确认是以下值之一: {color_green}[{1}]{color_normal}",
    8002:"{color_red}请选对正确的egret项目目录！{color_normal}\n\tEgret_Project\t\t{color_gray}//项目目录{color_normal}\n\t\t--launcher\t{color_gray}//启动目录{color_normal}\n\t\t--src\t\t{color_gray}//源代码目录{color_normal}",
    8003:"配置文件{0}不存在",
    8004:"{color_red}请先创建Native项目再执行 --runtime native{color_normal}",
    2001:"{0}: error 找不到EXML文件",
    2002:"{0}: error 不是有效的XML文件",
    2003:"{0}: error 无法找到节点所对应的类定义\n{1}",
    2004:"{0}: error 节点不能含有同名的id属性\n{1}",
    2005:"{0}: error 节点上不存在名为'{1}'的属性:\n{2}",
    2006:"{0}: error 未定义的视图状态名称:'{1}'\n{2}",
    2007:"{0}: error 只有处于容器内的egret.IVisualElement对象可以使用includeIn和excludeFrom属性\n{1}",
    2008:"{0}: error 无法将'{1}'类型的值赋给属性:'{2}'\n{3}",
    2009:"{0}: error 在节点属性值的‘{}’标签内只能引用一个ID，不允许使用复杂表达式\n{1}",
    2010:"{0}: error 属性:'{1}'所引用的ID: '{2}'不存在\n{3}",
    2011:"{0}: error 无法将多个子节点赋值给同一个属性:'{1}'\n{2}",
    2012:"{0}: error 节点上不存在默认属性，必须显式声明子节点要赋值到的属性名\n{1}",
    2013:"{0}: error 类型为Array的属性节点上不允许使用视图状态语法\n{1}",
    2014:"{0}: error 不允许将皮肤类自身赋值给节点属性\n{1}",
    2015:"{0}: error 节点引用的类定义:{1}不存在\n{2}",
    2016:"{0}: error 节点上'scale9Grid'属性值的格式错误:{1}",
    2017:"{0}: error 节点上缺少命名空间前缀:{1}",
    2018:"{0}: error 节点上'skinName'属性值的格式错误:{1}",
    2101:"{0}: warning 在w:Declarations内的子节点，不允许使用includeIn和excludeFrom属性\n{1}",
    2102:"{0}: warning 在属性节点上找不到任何子节点\n{1}",
    2103:"{0}: warning 节点上的同一个属性'{1}'被多次赋值\n{2}"
};<commit_msg>修改exmlc报错提示内容<commit_after>/**
 * Created by apple on 14-4-28.
 */

exports.error_code = {

    0:"执行成功",
    1:"请先设置环境变量 {color_green}EGRET_PATH{color_normal}。您可以访问 {color_underline}https://github.com/egret-team/egret/wiki/Setting-environment-variables{color_normal} 获取更多细节",
    2:"TypeScript编译器尚未安装，请执行 {color_green}npm install -g typescript{color_normal} 进行安装",
    1001:"请输入项目名称。例: {color_green}egret create [project_name]{color_normal}",
    1002:"该项目已存在",
    1101:"请输入项目名称。例:{color_green}egret build [project_name]{color_normal}",
    1102:"指定項目中不存在 bin-debug 文件夾，请执行 {color_green}egret build [project_name] -e {color_normal} 初始化引擎",
    1103:"{0}: error 类文件之间存在循环依赖，请检查类的继承关系或静态变量的初始化引用。",
    1301:"在编译路径 {0} 下找不到 egret_file_list.js 或 game_file_list.js，请检查编译路径是否正确",
    1302:"请输入编译路径。例:{color_green}egret compile --source [your_typescript_source_dir] --output [your_output_dir]{color_normal}",
    1303:"编译失败",
    1304:"解析manifest.json文件失败，请检查文件是否为正确的JSON格式:\n{0}",
    1305:"读取launcher/{0}.html失败，请检查编译路径是否正确",
    1306:"在launcher/{0}内找不到文档类'document_class'的变量定义，请检查文件内容是否正确",
    1307:"模块 {0} 中不存在任何 .ts 或 .d.ts 文件，无法编译，请在模块的 file_list 字段中填写 .ts 或 .d.ts ",
    1401:"找不到java或java版本过低（最低需求为 java 7 ),请安装java并执行 egret publish -testJava 命令进行测试",
    1501:"无法启动服务器，请检查权限或端口是否被占用",
    1601:"请输入项目名称, h5游戏目录以及手机平台支持库。例: {color_green}egret create_app [app_name] -f [h5_game_path] -t [template_path] {color_normal} \n如没有安装最新手机平台支持库，请从以下地址下载：\nAndroid: http://www.egret-labs.org/download/egret-android-packager-download.html, \niOS:http://www.egret-labs.org/download/egret-ios-packager-download.html",
    1602:"缺少egretProperties.json或格式不正确。 \n请从http://www.egret-labs.org/download/egret-download.html升级egret-core到最新版",
    1603:"缺少create_app.json。\n请从以下地址下载最新手机平台支持库\nAndroid: http://www.egret-labs.org/download/egret-android-packager-download.html, \n\tiOS: http://www.egret-labs.org/download/egret-ios-packager-download.html",
    1604:"执行egret build命令失败",
    1605:"移动平台项目目录不能与html5项目目录为同一目录，请修改移动平台项目目录。",
    1701:"项目版本低于 egret 版本，请执行 egret upgrade {your_project} 命令升级您的项目，\n命令中请不要加上大括号{}",
    1702:"项目升级后，请执行一次 egret build {your_project} {color_green}-e{color_normal} 编译引擎，\n命令中请不要加上大括号{}",
    1703:"\n升级第一步完成，{color_red}请按 {color_underline}https://github.com/egret-labs/egret-core/wiki/Egret_Upgrade/upgrade/index.html{color_red} 完成剩余升级步骤{color_normal}\n",
    9999:"未知错误:{0}",
    8001:"请输入命令行选项{color_green} {0} {color_normal}的参数,并确认是以下值之一: {color_green}[{1}]{color_normal}",
    8002:"{color_red}请选对正确的egret项目目录！{color_normal}\n\tEgret_Project\t\t{color_gray}//项目目录{color_normal}\n\t\t--launcher\t{color_gray}//启动目录{color_normal}\n\t\t--src\t\t{color_gray}//源代码目录{color_normal}",
    8003:"配置文件{0}不存在",
    8004:"{color_red}请先创建Native项目再执行 --runtime native{color_normal}",
    2001:"{0}: error 找不到EXML文件",
    2002:"{0}: error 不是有效的XML文件",
    2003:"{0}: error 无法找到节点所对应的类定义\n{1}",
    2004:"{0}: error 节点不能含有同名的id属性\n{1}",
    2005:"{0}: error 节点上不存在名为'{1}'的属性或样式名:\n{2}",
    2006:"{0}: error 未定义的视图状态名称:'{1}'\n{2}",
    2007:"{0}: error 只有处于容器内的egret.IVisualElement对象可以使用includeIn和excludeFrom属性\n{1}",
    2008:"{0}: error 无法将'{1}'类型的值赋给属性:'{2}'\n{3}",
    2009:"{0}: error 在节点属性值的‘{}’标签内只能引用一个ID，不允许使用复杂表达式\n{1}",
    2010:"{0}: error 属性:'{1}'所引用的ID: '{2}'不存在\n{3}",
    2011:"{0}: error 无法将多个子节点赋值给同一个属性:'{1}'\n{2}",
    2012:"{0}: error 节点上不存在默认属性，必须显式声明子节点要赋值到的属性名\n{1}",
    2013:"{0}: error 类型为Array的属性节点上不允许使用视图状态语法\n{1}",
    2014:"{0}: error 不允许将皮肤类自身赋值给节点属性\n{1}",
    2015:"{0}: error 节点引用的类定义:{1}不存在\n{2}",
    2016:"{0}: error 节点上'scale9Grid'属性值的格式错误:{1}",
    2017:"{0}: error 节点上缺少命名空间前缀:{1}",
    2018:"{0}: error 节点上'skinName'属性值的格式错误:{1}",
    2101:"{0}: warning 在w:Declarations内的子节点，不允许使用includeIn和excludeFrom属性\n{1}",
    2102:"{0}: warning 在属性节点上找不到任何子节点\n{1}",
    2103:"{0}: warning 节点上的同一个属性'{1}'被多次赋值\n{2}"
};<|endoftext|>


<commit_before>// Automatic preview through XHR

(function($) {
  // Enable automatic previewing to <textarea> elements.
  //
  // Arguments:
  //  - `href`: URL to be called for fetching the preview data.
  //  - `args`: arguments to be passed with the XHR.
  //  - `update`: the function that is called with the preview results. It
  //              is called with the textarea, the text that was rendered and
  //              the rendered text.
  $.fn.autoPreview = function(href, args, update) {
    if (!auto_preview_timeout)
      return this;
    var timeout = auto_preview_timeout * 1000;
    return this.each(function() {
      var timer = null;
      var updating = false;
      var textarea = this;
      var data = {};
      for (var key in args)
        data[key] = args[key];
      data["__FORM_TOKEN"] = form_token;
      data["text"] = textarea.value;

      // Request a preview through XHR
      function request() {
        var text = textarea.value;
        if (text != data["text"]) {
          data["text"] = text;
          updating = true;
          $.ajax({
            type: "POST", url: href, data: data, dataType: "html",
            success: function(data) {
              updating = false;
              update(textarea, text, data);
              if (textarea.value != text)
                timer = setTimeout(request, timeout);
            },
            error: function(req, err, exc) {
              updating = false;
            }
          });
        }
      }

      // Trigger a request after the given timeout
      function trigger() {
        if (!updating) {
          if (timer)
            clearTimeout(timer);
          timer = setTimeout(request, timeout);
        }
        return true;
      }

      $(this).keydown(trigger).keypress(trigger).change(trigger).blur(trigger);
    });
  }
})(jQuery);
<commit_msg>0.12dev: In the automatic preview, update the preview immediately on blur, but keep the delay for key presses.<commit_after>// Automatic preview through XHR

(function($) {
  // Enable automatic previewing to <textarea> elements.
  //
  // Arguments:
  //  - `href`: URL to be called for fetching the preview data.
  //  - `args`: arguments to be passed with the XHR.
  //  - `update`: the function that is called with the preview results. It
  //              is called with the textarea, the text that was rendered and
  //              the rendered text.
  $.fn.autoPreview = function(href, args, update) {
    if (!auto_preview_timeout)
      return this;
    var timeout = auto_preview_timeout * 1000;
    return this.each(function() {
      var timer = null;
      var updating = false;
      var textarea = this;
      var data = {};
      for (var key in args)
        data[key] = args[key];
      data["__FORM_TOKEN"] = form_token;
      data["text"] = textarea.value;

      // Request a preview through XHR
      function request() {
        var text = textarea.value;
        if (!updating && (text != data["text"])) {
          updating = true;
          data["text"] = text;
          $.ajax({
            type: "POST", url: href, data: data, dataType: "html",
            success: function(data) {
              updating = false;
              update(textarea, text, data);
              if (textarea.value != text) {
                if (timer)
                  clearTimeout(timer);
                timer = setTimeout(request, timeout);
              }
            },
            error: function(req, err, exc) {
              updating = false;
            }
          });
        }
      }

      // Trigger a request after the given timeout
      function trigger() {
        if (timer)
          clearTimeout(timer);
        timer = setTimeout(request, timeout);
        return true;
      }

      $(this).keydown(trigger).keypress(trigger).blur(request);
    });
  }
})(jQuery);
<|endoftext|>


<commit_before>var _ = require('underscore');
var SimpleStyleDefaults = require('./simple-style-defaults');

module.exports = _.defaults({

  DEFAULT_FILL_COLOR: '#ECCA8B',
  DEFAULT_STROKE_COLOR: '#9A8F7B',

  _getAggrAttrs: function (geometryType) {
    return {
      aggr_dataset: '',
      aggr_change: 'manual',
      aggr_value: {
        operation: 'COUNT',
        attribute: ''
      }
    };
  }

}, SimpleStyleDefaults);
<commit_msg>default is admin0<commit_after>var _ = require('underscore');
var SimpleStyleDefaults = require('./simple-style-defaults');

module.exports = _.defaults({

  DEFAULT_FILL_COLOR: '#ECCA8B',
  DEFAULT_STROKE_COLOR: '#9A8F7B',

  _getAggrAttrs: function (geometryType) {
    return {
      aggr_dataset: 'admin0',
      aggr_change: 'manual',
      aggr_value: {
        operation: 'COUNT',
        attribute: ''
      }
    };
  }

}, SimpleStyleDefaults);
<|endoftext|>


<commit_before>/**
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
part of the polymer project is also subject to an additional IP rights grant
found at http://polymer.github.io/PATENTS.txt
*/
import "../polymer/polymer-legacy.js";
import './iron-overlay-backdrop.js';
import { IronA11yKeysBehavior } from "../iron-a11y-keys-behavior/iron-a11y-keys-behavior.js";
import { dom } from "../polymer/lib/legacy/polymer.dom.js";
import * as gestures from "../polymer/lib/utils/gestures.js";
/**
 * @struct
 * @constructor
 * @private
 */

export const IronOverlayManagerClass = function () {
  /**
   * Used to keep track of the opened overlays.
   * @private {!Array<!Element>}
   */
  this._overlays = [];
  /**
   * iframes have a default z-index of 100,
   * so this default should be at least that.
   * @private {number}
   */

  this._minimumZ = 101;
  /**
   * Memoized backdrop element.
   * @private {Element|null}
   */

  this._backdropElement = null; // Enable document-wide tap recognizer.
  // NOTE: Use useCapture=true to avoid accidentally prevention of the closing
  // of an overlay via event.stopPropagation(). The only way to prevent
  // closing of an overlay should be through its APIs.
  // NOTE: enable tap on <html> to workaround Polymer/polymer#4459
  // Pass no-op function because MSEdge 15 doesn't handle null as 2nd argument
  // https://github.com/Microsoft/ChakraCore/issues/3863

  gestures.add(document.documentElement, 'tap', function () {});
  const clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
  document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true);
  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
};
IronOverlayManagerClass.prototype = {
  constructor: IronOverlayManagerClass,

  /**
   * The shared backdrop element.
   * @return {!Element} backdropElement
   */
  get backdropElement() {
    if (!this._backdropElement) {
      this._backdropElement = document.createElement('iron-overlay-backdrop');
    }

    return this._backdropElement;
  },

  /**
   * The deepest active element.
   * @return {!Element} activeElement the active element
   */
  get deepActiveElement() {
    var active = document.activeElement; // document.activeElement can be null
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
    // In IE 11, it can also be an object when operating in iframes.
    // In these cases, default it to document.body.

    if (!active || active instanceof Element === false) {
      active = document.body;
    }

    while (active.root && dom(active.root).activeElement) {
      active = dom(active.root).activeElement;
    }

    return active;
  },

  /**
   * Brings the overlay at the specified index to the front.
   * @param {number} i
   * @private
   */
  _bringOverlayAtIndexToFront: function (i) {
    var overlay = this._overlays[i];

    if (!overlay) {
      return;
    }

    var lastI = this._overlays.length - 1;
    var currentOverlay = this._overlays[lastI]; // Ensure always-on-top overlay stays on top.

    while (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
      lastI--;
      currentOverlay = this._overlays[lastI];
    }

    // If already the top element, return.
    if (i >= lastI) {
      return;
    }

    var minimumZ = Math.max(this._getZ(this._overlays[lastI]), this._minimumZ);

    //Get smallest z index to replace z-index for next overlay in the list
    let lastZ = this._getZ(overlay);
    while (i < lastI) {
      //Shift overley to left
      this._overlays[i] = this._overlays[i + 1];
      i++;
      //Replace z-index for shifted overlay by that last smallest z index. But before doing this please save z index for the  next overlay
      let tempZ = this._getZ(this._overlays[i])
      this._setZ(this._overlays[i], lastZ);
      lastZ = tempZ;
    }
    this._overlays[lastI] = overlay;

    if (this._getZ(overlay) <= minimumZ) {
      this._setZ(overlay, minimumZ);
    }
  },

  /**
   * Adds the overlay and updates its z-index if it's opened, or removes it if
   * it's closed. Also updates the backdrop z-index.
   * @param {!Element} overlay
   */
  addOrRemoveOverlay: function (overlay) {
    if (overlay.opened) {
      this.addOverlay(overlay);
    } else {
      this.removeOverlay(overlay);
    }
  },

  /**
   * Tracks overlays for z-index and focus management.
   * Ensures the last added overlay with always-on-top remains on top.
   * @param {!Element} overlay
   */
  addOverlay: function (overlay) {
    var i = this._overlays.indexOf(overlay);

    if (i >= 0) {
      this._bringOverlayAtIndexToFront(i);

      this.trackBackdrop();
      return;
    }

    var insertionIndex = this._overlays.length;
    var currentOverlay = this._overlays[insertionIndex - 1];
    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);

    var newZ = this._getZ(overlay);

    // Ensure always-on-top overlay stays on top.
    while (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
      // This bumps the z-index of +2.
      this._applyOverlayZ(currentOverlay, minimumZ);

      insertionIndex--; // Update minimumZ to match previous overlay's z-index.

      currentOverlay = this._overlays[insertionIndex - 1];
      minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
    } // Update z-index and insert overlay.

    if (newZ <= minimumZ) {
      this._applyOverlayZ(overlay, minimumZ);
    }

    this._overlays.splice(insertionIndex, 0, overlay);

    this.trackBackdrop();
  },

  /**
   * @param {!Element} overlay
   */
  removeOverlay: function (overlay) {
    var i = this._overlays.indexOf(overlay);

    if (i === -1) {
      return;
    }

    this._overlays.splice(i, 1);

    this.trackBackdrop();
  },

  /**
   * Returns the current overlay.
   * @return {!Element|undefined}
   */
  currentOverlay: function () {
    var i = this._overlays.length - 1;
    return this._overlays[i];
  },

  /**
   * Returns the current overlay z-index.
   * @return {number}
   */
  currentOverlayZ: function () {
    return this._getZ(this.currentOverlay());
  },

  /**
   * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
   * This does not effect the z-index of any existing overlays.
   * @param {number} minimumZ
   */
  ensureMinimumZ: function (minimumZ) {
    this._minimumZ = Math.max(this._minimumZ, minimumZ);
  },
  focusOverlay: function () {
    var current =
    /** @type {?} */
    this.currentOverlay();

    if (current) {
      current._applyFocus();
    }
  },

  /**
   * Updates the backdrop z-index.
   */
  trackBackdrop: function () {
    var overlay = this._overlayWithBackdrop(); // Avoid creating the backdrop if there is no overlay with backdrop.

    if (!overlay && !this._backdropElement) {
      return;
    }

    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
    this.backdropElement.opened = !!overlay; // Property observers are not fired until element is attached
    // in Polymer 2.x, so we ensure element is attached if needed.
    // https://github.com/Polymer/polymer/issues/4526

    this.backdropElement.prepare();
  },

  /**
   * @return {!Array<!Element>}
   */
  getBackdrops: function () {
    var backdrops = [];

    for (var i = 0; i < this._overlays.length; i++) {
      if (this._overlays[i].withBackdrop) {
        backdrops.push(this._overlays[i]);
      }
    }

    return backdrops;
  },

  /**
   * Returns the z-index for the backdrop.
   * @return {number}
   */
  backdropZ: function () {
    return this._getZ(this._overlayWithBackdrop()) - 1;
  },

  /**
   * Returns the top opened overlay that has a backdrop.
   * @return {!Element|undefined}
   * @private
   */
  _overlayWithBackdrop: function () {
    for (var i = this._overlays.length - 1; i >= 0; i--) {
      if (this._overlays[i].withBackdrop) {
        return this._overlays[i];
      }
    }
  },

  /**
   * Calculates the minimum z-index for the overlay.
   * @param {Element=} overlay
   * @private
   */
  _getZ: function (overlay) {
    var z = this._minimumZ;

    if (overlay) {
      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex); // Check if is a number
      // Number.isNaN not supported in IE 10+

      if (z1 === z1) {
        z = z1;
      }
    }

    return z;
  },

  /**
   * @param {!Element} element
   * @param {number|string} z
   * @private
   */
  _setZ: function (element, z) {
    element.style.zIndex = z;
  },

  /**
   * @param {!Element} overlay
   * @param {number} aboveZ
   * @private
   */
  _applyOverlayZ: function (overlay, aboveZ) {
    this._setZ(overlay, aboveZ + 2);
  },

  /**
   * Returns the deepest overlay in the path.
   * @param {!Array<!Element>=} path
   * @return {!Element|undefined}
   * @suppress {missingProperties}
   * @private
   */
  _overlayInPath: function (path) {
    path = path || [];

    for (var i = 0; i < path.length; i++) {
      if (path[i]._manager === this) {
        return path[i];
      }
    }
  },

  /**
   * Ensures the click event is delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureClick: function (event) {
    var i = this._overlays.length - 1;
    if (i === -1) return;
    var path =
    /** @type {!Array<!EventTarget>} */
    dom(event).path;
    var overlay; // Check if clicked outside of overlay.

    while ((overlay =
    /** @type {?} */
    this._overlays[i]) && this._overlayInPath(path) !== overlay) {
      overlay._onCaptureClick(event);

      if (overlay.allowClickThrough) {
        i--;
      } else {
        break;
      }
    }
  },

  /**
   * Ensures the focus event is delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureFocus: function (event) {
    var overlay =
    /** @type {?} */
    this.currentOverlay();

    if (overlay) {
      overlay._onCaptureFocus(event);
    }
  },

  /**
   * Ensures TAB and ESC keyboard events are delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureKeyDown: function (event) {
    var overlay =
    /** @type {?} */
    this.currentOverlay();

    if (overlay) {
      if (IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
        overlay._onCaptureEsc(event);
      } else if (IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
        overlay._onCaptureTab(event);
      }
    }
  },

  /**
   * Returns if the overlay1 should be behind overlay2.
   * @param {!Element} overlay1
   * @param {!Element} overlay2
   * @return {boolean}
   * @suppress {missingProperties}
   * @private
   */
  _shouldBeBehindOverlay: function (overlay1, overlay2) {
    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
  }
};
export const IronOverlayManager = new IronOverlayManagerClass();<commit_msg>#1854 Minor code and doc improvements.<commit_after>/**
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
part of the polymer project is also subject to an additional IP rights grant
found at http://polymer.github.io/PATENTS.txt
*/
import "../polymer/polymer-legacy.js";
import './iron-overlay-backdrop.js';
import { IronA11yKeysBehavior } from "../iron-a11y-keys-behavior/iron-a11y-keys-behavior.js";
import { dom } from "../polymer/lib/legacy/polymer.dom.js";
import * as gestures from "../polymer/lib/utils/gestures.js";
/**
 * @struct
 * @constructor
 * @private
 */

export const IronOverlayManagerClass = function () {
  /**
   * Used to keep track of the opened overlays.
   * @private {!Array<!Element>}
   */
  this._overlays = [];
  /**
   * iframes have a default z-index of 100,
   * so this default should be at least that.
   * @private {number}
   */

  this._minimumZ = 101;
  /**
   * Memoized backdrop element.
   * @private {Element|null}
   */

  this._backdropElement = null; // Enable document-wide tap recognizer.
  // NOTE: Use useCapture=true to avoid accidentally prevention of the closing
  // of an overlay via event.stopPropagation(). The only way to prevent
  // closing of an overlay should be through its APIs.
  // NOTE: enable tap on <html> to workaround Polymer/polymer#4459
  // Pass no-op function because MSEdge 15 doesn't handle null as 2nd argument
  // https://github.com/Microsoft/ChakraCore/issues/3863

  gestures.add(document.documentElement, 'tap', function () {});
  const clickEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown';
  document.addEventListener(clickEvent, this._onCaptureClick.bind(this), true);
  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
};
IronOverlayManagerClass.prototype = {
  constructor: IronOverlayManagerClass,

  /**
   * The shared backdrop element.
   * @return {!Element} backdropElement
   */
  get backdropElement() {
    if (!this._backdropElement) {
      this._backdropElement = document.createElement('iron-overlay-backdrop');
    }

    return this._backdropElement;
  },

  /**
   * The deepest active element.
   * @return {!Element} activeElement the active element
   */
  get deepActiveElement() {
    var active = document.activeElement; // document.activeElement can be null
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
    // In IE 11, it can also be an object when operating in iframes.
    // In these cases, default it to document.body.

    if (!active || active instanceof Element === false) {
      active = document.body;
    }

    while (active.root && dom(active.root).activeElement) {
      active = dom(active.root).activeElement;
    }

    return active;
  },

  /**
   * Brings the overlay at the specified index to the front.
   * @param {number} i
   * @private
   */
  _bringOverlayAtIndexToFront: function (i) {
    const overlay = this._overlays[i];

    if (!overlay) {
      return;
    }

    var lastI = this._overlays.length - 1;
    var currentOverlay = this._overlays[lastI]; // Ensure always-on-top overlay stays on top.

    while (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
      lastI--;
      currentOverlay = this._overlays[lastI];
    }

    // If already the top element, return.
    if (i >= lastI) {
      return;
    }

    const minimumZ = Math.max(this._getZ(this._overlays[lastI]), this._minimumZ);

    // Get the smallest z-index to replace z-index for the next overlay in the list
    let lastZ = this._getZ(overlay);
    while (i < lastI) {
      // Shift overlay to left
      this._overlays[i] = this._overlays[i + 1];
      i++;
      // Replace z-index a for shifted overlay by that last smallest z-index. But before doing this capture z-index for the next overlay.
      let tempZ = this._getZ(this._overlays[i])
      this._setZ(this._overlays[i], lastZ);
      lastZ = tempZ;
    }
    this._overlays[lastI] = overlay;

    if (this._getZ(overlay) <= minimumZ) {
      this._setZ(overlay, minimumZ);
    }
  },

  /**
   * Adds the overlay and updates its z-index if it's opened, or removes it if
   * it's closed. Also updates the backdrop z-index.
   * @param {!Element} overlay
   */
  addOrRemoveOverlay: function (overlay) {
    if (overlay.opened) {
      this.addOverlay(overlay);
    } else {
      this.removeOverlay(overlay);
    }
  },

  /**
   * Tracks overlays for z-index and focus management.
   * Ensures the last added overlay with always-on-top remains on top.
   * @param {!Element} overlay
   */
  addOverlay: function (overlay) {
    var i = this._overlays.indexOf(overlay);

    if (i >= 0) {
      this._bringOverlayAtIndexToFront(i);

      this.trackBackdrop();
      return;
    }

    var insertionIndex = this._overlays.length;
    var currentOverlay = this._overlays[insertionIndex - 1];
    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);

    var newZ = this._getZ(overlay);

    // Ensure always-on-top overlay stays on top.
    while (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
      // This bumps the z-index of +2.
      this._applyOverlayZ(currentOverlay, minimumZ);

      insertionIndex--; // Update minimumZ to match previous overlay's z-index.

      currentOverlay = this._overlays[insertionIndex - 1];
      minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
    } // Update z-index and insert overlay.

    if (newZ <= minimumZ) {
      this._applyOverlayZ(overlay, minimumZ);
    }

    this._overlays.splice(insertionIndex, 0, overlay);

    this.trackBackdrop();
  },

  /**
   * @param {!Element} overlay
   */
  removeOverlay: function (overlay) {
    var i = this._overlays.indexOf(overlay);

    if (i === -1) {
      return;
    }

    this._overlays.splice(i, 1);

    this.trackBackdrop();
  },

  /**
   * Returns the current overlay.
   * @return {!Element|undefined}
   */
  currentOverlay: function () {
    var i = this._overlays.length - 1;
    return this._overlays[i];
  },

  /**
   * Returns the current overlay z-index.
   * @return {number}
   */
  currentOverlayZ: function () {
    return this._getZ(this.currentOverlay());
  },

  /**
   * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
   * This does not effect the z-index of any existing overlays.
   * @param {number} minimumZ
   */
  ensureMinimumZ: function (minimumZ) {
    this._minimumZ = Math.max(this._minimumZ, minimumZ);
  },
  focusOverlay: function () {
    var current =
    /** @type {?} */
    this.currentOverlay();

    if (current) {
      current._applyFocus();
    }
  },

  /**
   * Updates the backdrop z-index.
   */
  trackBackdrop: function () {
    var overlay = this._overlayWithBackdrop(); // Avoid creating the backdrop if there is no overlay with backdrop.

    if (!overlay && !this._backdropElement) {
      return;
    }

    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
    this.backdropElement.opened = !!overlay; // Property observers are not fired until element is attached
    // in Polymer 2.x, so we ensure element is attached if needed.
    // https://github.com/Polymer/polymer/issues/4526

    this.backdropElement.prepare();
  },

  /**
   * @return {!Array<!Element>}
   */
  getBackdrops: function () {
    var backdrops = [];

    for (var i = 0; i < this._overlays.length; i++) {
      if (this._overlays[i].withBackdrop) {
        backdrops.push(this._overlays[i]);
      }
    }

    return backdrops;
  },

  /**
   * Returns the z-index for the backdrop.
   * @return {number}
   */
  backdropZ: function () {
    return this._getZ(this._overlayWithBackdrop()) - 1;
  },

  /**
   * Returns the top opened overlay that has a backdrop.
   * @return {!Element|undefined}
   * @private
   */
  _overlayWithBackdrop: function () {
    for (var i = this._overlays.length - 1; i >= 0; i--) {
      if (this._overlays[i].withBackdrop) {
        return this._overlays[i];
      }
    }
  },

  /**
   * Calculates the minimum z-index for the overlay.
   * @param {Element=} overlay
   * @private
   */
  _getZ: function (overlay) {
    var z = this._minimumZ;

    if (overlay) {
      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex); // Check if is a number
      // Number.isNaN not supported in IE 10+

      if (z1 === z1) {
        z = z1;
      }
    }

    return z;
  },

  /**
   * @param {!Element} element
   * @param {number|string} z
   * @private
   */
  _setZ: function (element, z) {
    element.style.zIndex = z;
  },

  /**
   * @param {!Element} overlay
   * @param {number} aboveZ
   * @private
   */
  _applyOverlayZ: function (overlay, aboveZ) {
    this._setZ(overlay, aboveZ + 2);
  },

  /**
   * Returns the deepest overlay in the path.
   * @param {!Array<!Element>=} path
   * @return {!Element|undefined}
   * @suppress {missingProperties}
   * @private
   */
  _overlayInPath: function (path) {
    path = path || [];

    for (var i = 0; i < path.length; i++) {
      if (path[i]._manager === this) {
        return path[i];
      }
    }
  },

  /**
   * Ensures the click event is delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureClick: function (event) {
    var i = this._overlays.length - 1;
    if (i === -1) return;
    var path =
    /** @type {!Array<!EventTarget>} */
    dom(event).path;
    var overlay; // Check if clicked outside of overlay.

    while ((overlay =
    /** @type {?} */
    this._overlays[i]) && this._overlayInPath(path) !== overlay) {
      overlay._onCaptureClick(event);

      if (overlay.allowClickThrough) {
        i--;
      } else {
        break;
      }
    }
  },

  /**
   * Ensures the focus event is delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureFocus: function (event) {
    var overlay =
    /** @type {?} */
    this.currentOverlay();

    if (overlay) {
      overlay._onCaptureFocus(event);
    }
  },

  /**
   * Ensures TAB and ESC keyboard events are delegated to the right overlay.
   * @param {!Event} event
   * @private
   */
  _onCaptureKeyDown: function (event) {
    var overlay =
    /** @type {?} */
    this.currentOverlay();

    if (overlay) {
      if (IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
        overlay._onCaptureEsc(event);
      } else if (IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
        overlay._onCaptureTab(event);
      }
    }
  },

  /**
   * Returns if the overlay1 should be behind overlay2.
   * @param {!Element} overlay1
   * @param {!Element} overlay2
   * @return {boolean}
   * @suppress {missingProperties}
   * @private
   */
  _shouldBeBehindOverlay: function (overlay1, overlay2) {
    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
  }
};
export const IronOverlayManager = new IronOverlayManagerClass();<|endoftext|>


<commit_before>var $ = function(id){ return document.getElementById(id); }
var show = function(elem) { elem.style.display = "block" }

var themes = {
  "dark": {
    background: {
      normal: '#333',
      halftone: '#444'
    },
    foreground: {
      normal: '#ccc',
      halftone: '#bbb'
    },
    link: {
      fresh: '#6b8',
      visited: '#496',
      hover: '#7c9'
    }
  },
  "solarized-light": {
    background: {
      normal: '#fdf6e3',
      halftone: '#eee8d5'
    },
    foreground: {
      normal: '#657b83',
      halftone: '#839496'
    },
    link: {
      fresh: '#b58900',
      visited: '#cb4b16',
      hover: '#dc322f'
    }
  },
  "solarized-dark": {
    background: {
      normal: '#073642',
      halftone: '#002b36'
    },
    foreground: {
      normal: '#93a1a1',
      halftone: '#eee8d5'
    },
    link: {
      fresh: '#cb4b16',
      visited: '#b58900',
      hover: '#dc322f'
    }
  },
  "default": {
    background: {
      normal: '#fff',
      halftone: '#efefef'
    },
    foreground: {
      normal: '#333',
      halftone: '#888'
    },
    link: {
      fresh: '#097',
      visited: '#054',
      hover: '#0a8'
    }
  }
};

var ui = { theme: "default" };
if (location.search.length > 0) {
  location.search.slice(1).split("&").reduce(function(acc, e){
    var p = e.split("=");
    acc[p[0]] = p[1];
    return acc
  }, ui);
}

var vars = {
  '@background': themes[ui.theme].background.normal,
  '@background_halftone': themes[ui.theme].background.halftone,
  '@foreground': themes[ui.theme].foreground.normal,
  '@foreground_halftone': themes[ui.theme].foreground.halftone,
  '@link_fresh': themes[ui.theme].link.fresh,
  '@link_visited': themes[ui.theme].link.visited,
  '@link_hover': themes[ui.theme].link.hover
};

var fontURL = "https://fonts.googleapis.com/" +
    "css?family=PT+Serif:700|Noticia+Text:700%s" +
    "&subset=latin,cyrillic",
    injection = "";

if(ui["header-font"] || ui["text-font"]) {
  injection = ["header-font", "text-font"].reduce(function(acc, font){
    if(ui[font]) {
      vars['@' + font.replace(/-/, "_")] = ui[font].replace(/\+/g," ");
      return acc + "|" + ui[font];
    } else return acc;
  }, "");
}

if(ui["text-size"]) vars["@text_size_factor"] = ui["text-size"];
if(ui["header-size"]) vars["@header_size_factor"] = ui["header-size"];

fontURL = fontURL.replace(/%s/, injection);
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", fontURL)
document.getElementsByTagName("head")[0].appendChild(fileref)

function showFooter(){
  less.modifyVars(vars);
  var elem = $("footer");
  if(!elem) return;
  if(window.innerHeight * 0.85 >= document.body.clientHeight) {
      elem.style.position = "fixed";
      elem.style.bottom = 0;
  }
  show(elem);
}

// for the case if main.js is not loaded
var onLoad = showFooter;
<commit_msg>styling delay fixed<commit_after>var $ = function(id){ return document.getElementById(id); }
var show = function(elem) { elem.style.display = "block" }

var themes = {
  "dark": {
    background: {
      normal: '#333',
      halftone: '#444'
    },
    foreground: {
      normal: '#ccc',
      halftone: '#bbb'
    },
    link: {
      fresh: '#6b8',
      visited: '#496',
      hover: '#7c9'
    }
  },
  "solarized-light": {
    background: {
      normal: '#fdf6e3',
      halftone: '#eee8d5'
    },
    foreground: {
      normal: '#657b83',
      halftone: '#839496'
    },
    link: {
      fresh: '#b58900',
      visited: '#cb4b16',
      hover: '#dc322f'
    }
  },
  "solarized-dark": {
    background: {
      normal: '#073642',
      halftone: '#002b36'
    },
    foreground: {
      normal: '#93a1a1',
      halftone: '#eee8d5'
    },
    link: {
      fresh: '#cb4b16',
      visited: '#b58900',
      hover: '#dc322f'
    }
  },
  "default": {
    background: {
      normal: '#fff',
      halftone: '#efefef'
    },
    foreground: {
      normal: '#333',
      halftone: '#888'
    },
    link: {
      fresh: '#097',
      visited: '#054',
      hover: '#0a8'
    }
  }
};

var ui = { theme: "default" };
if (location.search.length > 0) {
  location.search.slice(1).split("&").reduce(function(acc, e){
    var p = e.split("=");
    acc[p[0]] = p[1];
    return acc
  }, ui);
}

var vars = {
  '@background': themes[ui.theme].background.normal,
  '@background_halftone': themes[ui.theme].background.halftone,
  '@foreground': themes[ui.theme].foreground.normal,
  '@foreground_halftone': themes[ui.theme].foreground.halftone,
  '@link_fresh': themes[ui.theme].link.fresh,
  '@link_visited': themes[ui.theme].link.visited,
  '@link_hover': themes[ui.theme].link.hover
};

var fontURL = "https://fonts.googleapis.com/" +
    "css?family=PT+Serif:700|Noticia+Text:700%s" +
    "&subset=latin,cyrillic",
    injection = "";

if(ui["header-font"] || ui["text-font"]) {
  injection = ["header-font", "text-font"].reduce(function(acc, font){
    if(ui[font]) {
      vars['@' + font.replace(/-/, "_")] = ui[font].replace(/\+/g," ");
      return acc + "|" + ui[font];
    } else return acc;
  }, "");
}

if(ui["text-size"]) vars["@text_size_factor"] = ui["text-size"];
if(ui["header-size"]) vars["@header_size_factor"] = ui["header-size"];

fontURL = fontURL.replace(/%s/, injection);
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", fontURL)
document.getElementsByTagName("head")[0].appendChild(fileref)

less.modifyVars(vars);

function showFooter(){
  var elem = $("footer");
  if(!elem) return;
  if(window.innerHeight * 0.85 >= document.body.clientHeight) {
      elem.style.position = "fixed";
      elem.style.bottom = 0;
  }
  show(elem);
}

// for the case if main.js is not loaded
var onLoad = showFooter;
<|endoftext|>


<commit_before>'use strict';

function <%= controllerName %>Controller($log) {
  'ngInject';

  $log.debug('Hello from <%= controllerName %>Controller!');

}

export default <%= controllerName %>Controller;
<commit_msg>add scopre depend. in page CTRL<commit_after>'use strict';

function <%= controllerName %>Controller($scope, $log) {
  'ngInject';

  $log.debug('Hello from <%= controllerName %>Controller!');

}

export default <%= controllerName %>Controller;
<|endoftext|>