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

    angular
        .module('atlas')
        .factory('dataSelectionReducers', dataSelectionReducersFactory);

    dataSelectionReducersFactory.$inject = [
        'ACTIONS',
        'stateUrlConverter'
    ];

    function dataSelectionReducersFactory (ACTIONS, stateUrlConverter) {
        const reducers = {};

        reducers[ACTIONS.FETCH_DATA_SELECTION.id] = fetchDataSelectionReducer;
        reducers[ACTIONS.SHOW_DATA_SELECTION.id] = showDataSelectionReducer;
        reducers[ACTIONS.NAVIGATE_DATA_SELECTION.id] = navigateDataSelectionReducer;
        reducers[ACTIONS.SET_DATA_SELECTION_VIEW.id] = setDataSelectionViewReducer;

        return reducers;

        /**
         * @param {Object} oldState
         * @param {Object} payload A tring with the search query or
         *                         An object with the following keys:
         *                          - query (String): The search query
         *                          - filters (Object): Active filters
         *
         * @returns {Object} newState
         */
        function fetchDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);
            let mergeInto;

            newState.map.isFullscreen = false;

            newState.layerSelection.isEnabled = null;
            newState.search = null;
            newState.page.name = null;
            newState.detail = null;
            newState.straatbeeld = null;

            if (angular.isString(payload)) {
                mergeInto = {
                    query: payload,
                    filters: {}
                };
            }  else {
                mergeInto = payload;
                mergeInto.filters = mergeInto.filters || {};
            }

            newState.dataSelection = Object.keys(mergeInto).reduce((result, key) => {
                result[key] = mergeInto[key];
                return result;
            }, newState.dataSelection || {});

            if (!newState.dataSelection.view) {
                // Default view is table view
                newState.dataSelection.view = 'TABLE';
            }

            // LIST loading might include markers => set map loading accordingly
            newState.map.isLoading = newState.dataSelection.view === 'LIST';

            newState.dataSelection.geometryFilter = newState.dataSelection.geometryFilter ||
                {
                    markers: [],
                    description: ''
                };

            newState.dataSelection.markers = [];
            newState.dataSelection.isLoading = true;
            newState.dataSelection.isFullscreen = newState.dataSelection.view !== 'LIST';

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {Array} payload - Markers for the leaflet.markercluster plugin
         *
         * @returns {Object} newState
         */
        function showDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            if (newState.dataSelection) {
                newState.dataSelection.markers = payload;
                newState.dataSelection.isLoading = false;

                newState.dataSelection.isFullscreen = newState.dataSelection.view !== 'LIST';
            }

            newState.map.isLoading = false;

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {Number} payload - The destination page
         *
         * @returns {Object} newState
         */
        function navigateDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            newState.dataSelection.page = payload;

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {String} payload
         *
         * @returns {Object} newState
         */
        function setDataSelectionViewReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            ['LIST', 'TABLE', 'CARDS'].forEach(legalValue => {
                if (payload === legalValue) {
                    newState.dataSelection.view = payload;
                    newState.dataSelection.isLoading = true;
                }
            });

            return newState;
        }
    }
})();
<commit_msg>tg-3078 expanded function param description<commit_after>(function () {
    'use strict';

    angular
        .module('atlas')
        .factory('dataSelectionReducers', dataSelectionReducersFactory);

    dataSelectionReducersFactory.$inject = [
        'ACTIONS',
        'stateUrlConverter'
    ];

    function dataSelectionReducersFactory (ACTIONS, stateUrlConverter) {
        const reducers = {};

        reducers[ACTIONS.FETCH_DATA_SELECTION.id] = fetchDataSelectionReducer;
        reducers[ACTIONS.SHOW_DATA_SELECTION.id] = showDataSelectionReducer;
        reducers[ACTIONS.NAVIGATE_DATA_SELECTION.id] = navigateDataSelectionReducer;
        reducers[ACTIONS.SET_DATA_SELECTION_VIEW.id] = setDataSelectionViewReducer;

        return reducers;

        /**
         * @param {Object} oldState
         * @param {Object} payload A tring with the search query or
         *                         An object with the following keys:
         *                          - query (String): The search query
         *                          - filters (Object): Active filters
         *                          Except these two keys other keys will
         *                          be copied if the are in the object
         *                          but no defualt value will be provided.
         *
         * @returns {Object} newState
         */
        function fetchDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);
            let mergeInto;

            newState.map.isFullscreen = false;

            newState.layerSelection.isEnabled = null;
            newState.search = null;
            newState.page.name = null;
            newState.detail = null;
            newState.straatbeeld = null;

            if (angular.isString(payload)) {
                mergeInto = {
                    query: payload,
                    filters: {}
                };
            }  else {
                mergeInto = payload;
                mergeInto.filters = mergeInto.filters || {};
            }

            newState.dataSelection = Object.keys(mergeInto).reduce((result, key) => {
                result[key] = mergeInto[key];
                return result;
            }, newState.dataSelection || {});

            if (!newState.dataSelection.view) {
                // Default view is table view
                newState.dataSelection.view = 'TABLE';
            }

            // LIST loading might include markers => set map loading accordingly
            newState.map.isLoading = newState.dataSelection.view === 'LIST';

            newState.dataSelection.geometryFilter = newState.dataSelection.geometryFilter ||
                {
                    markers: [],
                    description: ''
                };

            newState.dataSelection.markers = [];
            newState.dataSelection.isLoading = true;
            newState.dataSelection.isFullscreen = newState.dataSelection.view !== 'LIST';

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {Array} payload - Markers for the leaflet.markercluster plugin
         *
         * @returns {Object} newState
         */
        function showDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            if (newState.dataSelection) {
                newState.dataSelection.markers = payload;
                newState.dataSelection.isLoading = false;

                newState.dataSelection.isFullscreen = newState.dataSelection.view !== 'LIST';
            }

            newState.map.isLoading = false;

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {Number} payload - The destination page
         *
         * @returns {Object} newState
         */
        function navigateDataSelectionReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            newState.dataSelection.page = payload;

            return newState;
        }

        /**
         * @param {Object} oldState
         * @param {String} payload
         *
         * @returns {Object} newState
         */
        function setDataSelectionViewReducer (oldState, payload) {
            const newState = angular.copy(oldState);

            ['LIST', 'TABLE', 'CARDS'].forEach(legalValue => {
                if (payload === legalValue) {
                    newState.dataSelection.view = payload;
                    newState.dataSelection.isLoading = true;
                }
            });

            return newState;
        }
    }
})();
<|endoftext|>


<commit_before>/********************************************************************
 * candytalking.js
 *
 * Just Another Minimal Charts script
 *
 * Copyright (C) 2014 Jean Zundel <jzu@free.fr>
 * MIT License: https://github.com/jzu/candytalking/blob/master/LICENSE
 *
 * Draws blocks, lines, Bezier curves, and later dots and stacked blocks
 * from a json structure whose name matches a canvas id. Type of graph is
 * given by the class name: "blocks", "lines" or "bezier". All sizes, fonts,
 * etc. are based on the dimensions of the canvas. Executed automatically
 * by default when the page is loaded.
 *
 * Example:

<!DOCTYPE html>
<html>
<head>
 <title>Some Candy Talking</title>
 <script src="candytalking.js"></script>
</head>
<body>
 <script>
   var canvas1 = {
         "title": "Blocks",
         "colors": [ "black", "cyan", "orange" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
   var canvas2 = {
         "title": "Lines",
         "colors": [ "black", "blue", "red" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
   var canvas3 = {
         "title": "Bezier",
         "colors": [ "black", "green", "magenta" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
 </script>
 <canvas id="canvas1" class="blocks" width="800" height="600">
  Canvas require a real browser
 </canvas>
 <canvas id="canvas2" class="lines" width="800" height="600">
  Canvas require a real browser
 </canvas>
 <canvas id="canvas3" class="bezier" width="800" height="600">
  Canvas require a real browser
 </canvas>
</body>
</html>

*/

/***************************************************************************
 * verticalLine()
 *
 * Draws a vertical line in light grey
 ***************************************************************************

function verticalLine () {
      ctx.strokeStyle = "#DDDDDD";
      ctx.beginPath ();
      ctx.moveTo (marginX + spaceXAxis + blockW * (i - 1),
                  marginY + marginTitle + blockH);
      ctx.lineTo (marginX + spaceXAxis + blockW * (i - 1),
                  marginY + marginTitle);
      ctx.stroke ();
}
 */
/****************************************************************************
 * drawY()
 *
 * Draws a Y value in the left margin and the corresponding horizontal line
 ***************************************************************************/

function drawY (canvas_h, ctx, i, marginX, scaleY, spaceXAxis) {

  ctx.fillText (i,
                marginX * 1.5 - ctx.measureText (i).width,
                scaleY);
  ctx.beginPath ();
  ctx.moveTo (marginX * 2, scaleY);
  ctx.lineTo (marginX + canvas_h.width - spaceXAxis, scaleY);
  ctx.stroke ();
}

/****************************************************************************
 * onload() handler
 *
 * Draws charts in all canvases of class "blocks", "lines and "bezier"
 * All dimensions in pixels except yMin, yMax
 *
 * You may want to use this function on demand, for instance if you already
 * have an onload() handler. In this case, just rename it, and call it
 * explicitely from elsewhere.
 ***************************************************************************/

window.onload = function () {

  var canvas = document.getElementsByTagName ("canvas");

  for (var h = 0; h < canvas.length; h++) {

    if ((canvas [h].className != "blocks") &&
        (canvas [h].className != "lines") &&
        (canvas [h].className != "bezier"))
      continue;

    var ctx = canvas [h].getContext ("2d");
    var histName = canvas [h].getAttribute ('id');
    var hist = eval (histName);
    var nbSets = hist.data.length - 1;
    var nbBlocks = hist.data [0].length - 1;

    // Title and text font sizes

    var titleFontSize = (canvas [h].width < canvas [h].height * 4 / 3)
                        ? canvas [h].width / 25
                        : canvas [h].height / 18;
    var textFontSize = (canvas [h].width < canvas [h].height * 4 / 3)
                       ? canvas [h].width / 40
                       : canvas [h].height / 30;

    // Margins

    var marginX = textFontSize * 2;
    var marginY = textFontSize * 2;
    var spaceXAxis = textFontSize * 4;
    var spaceYAxis = textFontSize * 2;
    var marginTitle = textFontSize * 4;

    // A block contains several values if there are several datasets

    var blockW = (canvas [h].width - marginX * 2 - spaceXAxis) / nbBlocks;
    var blockH = canvas [h].height - marginY * 2 - spaceYAxis - marginTitle;

    // Y-axis adjustment

    var yMax = 0;
    for (i = 1; i <= nbSets; i++)
      for (j = 1; j <= nbBlocks; j++)
        yMax = (hist.data [i][j] > yMax)
               ? hist.data [i][j]
               : yMax;
    yMax = (yMax > 0)
           ? yMax
           : 0;
    var yMin = 0;
    for (i = 1; i <= nbSets; i++)
      for (j = 1; j <= nbBlocks; j++)
        yMin = (hist.data [i][j] < yMin)
               ? hist.data [i][j]
               : yMin;
    yMin = (yMin < 0)
           ? yMin
           : 0;

    // Origin on the Y-axis

    var ord0 = marginY + marginTitle + blockH + yMin * blockH / (yMax - yMin);

    // Title

    ctx.font = (titleFontSize + "px Helvetica");
    ctx.fillText (hist.title, marginX * 2, marginY * 1.5);
    ctx.font = (textFontSize + "px Helvetica");

    // X-axis labels

    ctx.fillStyle = hist.colors [0];
    ctx.fillText (hist.data [0][0],
                  marginX ,
                  marginY + marginTitle + blockH + spaceYAxis);
    for (i = 1; i <= nbBlocks; i++) {
      ctx.fillText (hist.data [0][i],
                    marginX + spaceYAxis + blockW * (i - 1)
                    + (blockW - blockW/nbSets + ctx.measureText (hist.data [0][i]).width) / 2,
                    marginY + marginTitle + blockH + spaceYAxis);
    }

    // Draw lines (y=0 is bold) and numbers on the Y-axis
    // Right-align numbers, avoid overlapping
    // First min and max values, then step by step

    ctx.lineWidth = 0;
    ctx.strokeStyle = "#DDD";
    var greyLine = ctx.strokeStyle;

    drawY (canvas [h],
           ctx,
           yMin,
           marginX,
           marginY + marginTitle + blockH,
           spaceXAxis);
    drawY (canvas [h],
           ctx,
           yMax,
           marginX,
           marginY + marginTitle,
           spaceXAxis);

    // Then horizontal lines and Y-axis labels

    var zeroes = 0;
    var range = yMax - yMin;
    var step = range;

    // Intervals on the Y-axis
    // Find +/- the exponent of the range (at 25 => step *= 10)

    if (range >= 1) {
      for (zeroes = 0; step > 25; zeroes++)
        step /= 10;
      step = 1;
      for (i = 0; i < zeroes; i++)
        step *= 10;
    }
    else {
      for (zeroes = 0; step < 2.5; zeroes--)
        step *= 10;
      step = 1;
      for (i = 0; i > zeroes; i--)
        step /= 10;
    }

    var yMinTrunc = -Math.floor (-yMin / step) * step;   // Never > 0

    for (i = yMinTrunc; i <= yMax; i+=step) {
      if ((i - yMin > range / 25) &&
          (yMax - i > range / 25)) {   // Don't you step on my blue suede shoes
        drawY (canvas [h],
               ctx,
               (range < 2.5)
               ? i.toFixed (-zeroes)   // Bug^H^H^H Implementation detail in JS
               : i,
               marginX,
               marginY + marginTitle + blockH + (yMin-i) * blockH / range,
               spaceXAxis);
        if (i == 0) {
          ctx.strokeStyle = "#CCC";
          ctx.stroke ();
          ctx.strokeStyle = greyLine;
        }
      }
    }

    // Coloured dots and dataset names

    var sMaxWidth = 0;
    for (i = 1; i <= nbSets; i++)
      if (ctx.measureText (hist.data [i][0]).width > sMaxWidth)
        sMaxWidth = ctx.measureText (hist.data [i][0]).width;

    for (i = 1; i <= nbSets; i++) {

      ctx.fillStyle = hist.colors [i];
      ctx.strokeStyle = "#BBBBBB";      // Grey ring around the dot

      ctx.beginPath ();
      ctx.arc (canvas [h].width - marginX - sMaxWidth - textFontSize * 1.5,
               marginY + (i - 1) * textFontSize * 1.1 - textFontSize / 2,
               textFontSize * 3 / 7,
               0,
               Math.PI * 2);
      ctx.fill ();
      ctx.stroke ();
      ctx.closePath ();

      ctx.fillStyle = "black";
      ctx.fillText (hist.data [i][0],
                    canvas [h].width - marginX - sMaxWidth,
                    marginY + (i - 1) * textFontSize * 1.1 - 2);
    }

    ctx.shadowColor = '#666';
    ctx.shadowBlur = 20;
    ctx.shadowOffsetX = 5;
    ctx.shadowOffsetY = 5;

    switch (canvas [h].className) {

    case "blocks":

      for (i = 1; i <= nbSets; i++) {
        ctx.fillStyle = hist.colors [i];
        ctx.strokeStyle = hist.colors [i];
        for (j = 1; j <= nbBlocks; j++)
          ctx.fillRect (marginX + spaceXAxis + blockW * (j - 1)
                        + (i - 1) * blockW / (nbSets+1),
                        ord0,
                        blockW / (nbSets+1),
                        -hist.data [i][j] * blockH / (yMax - yMin));
      }
      break;                   // blocks

    case "lines":

      for (i = 1; i <= nbSets; i++) {
        ctx.strokeStyle = hist.colors [i];
        ctx.beginPath ();
        ctx.moveTo (marginX + spaceXAxis,
                    ord0 - hist.data [i][1] * blockH / (yMax - yMin));
        for (j = 2; j <= nbBlocks; j++) {
          ctx.lineTo (marginX + spaceXAxis + blockW * (j - 1),
                      ord0 - hist.data [i][j] * blockH / range);
        }
        ctx.stroke ();
      }
      break;                  // lines

    case "bezier":

      if (nbBlocks >= 3) {
        for (i = 1; i <= nbSets; i++) {

          var pt = [];              // Curve points [number] {X|Y}
          var cp = [];              // Control points [number] [1st|2nd] {X|Y}
          pt [1] = new Object ();
          pt [1]['X'] = marginX + spaceXAxis;
          pt [1]['Y'] = ord0 - hist.data [i][1] * blockH / (yMax - yMin);

          for (j = 2; j <= nbBlocks; j++) {

            pt [j] = new Object ();
            pt [j]['X'] = marginX + spaceXAxis + blockW * (j - 1);
            pt [j]['Y'] = ord0 - hist.data [i][j] * blockH / range;
          }

          ctx.strokeStyle = hist.colors [i];
          ctx.beginPath ();
          ctx.moveTo (pt [1]['X'], pt [1]['Y']);

          cp [1] = [];
          cp [1][1] = new Object ();

          for (j = 2; j < nbBlocks; j++) {

            cp [j-1][2] = new Object ();
            cp [j-1][2]['X'] = (pt [j-1]['X'] + 3 * pt [j]['X']) / 4;
            cp [j-1][2]['Y'] = pt [j]['Y'] + (pt [j-1]['Y'] - pt [j+1]['Y'])/8;
            cp [j] = [];
            cp [j][1] = new Object ();
            cp [j][1]['X'] = (pt [j+1]['X'] + 3 * pt [j]['X']) / 4;
            cp [j][1]['Y'] = pt [j]['Y'] - (pt [j-1]['Y'] - pt [j+1]['Y']) / 8;
          }
          cp [1][1]['X'] = pt [1]['X'];
          cp [1][1]['Y'] = pt [1]['Y'];
          cp [nbBlocks-1][2] = new Object ();
          cp [nbBlocks-1][2]['X'] = (pt [nbBlocks-1]['X']
                                     + 3 * pt [nbBlocks]['X']) / 4;
          cp [nbBlocks-1][2]['Y'] = (pt [nbBlocks]['Y']
                                     + 3 * pt [nbBlocks-1]['Y']) / 4;
        for (j = 2; j <= nbBlocks; j++) {

            ctx.bezierCurveTo (cp [j-1][1]['X'], cp [j-1][1]['Y'],
                                   cp [j-1][2]['X'], cp [j-1][2]['Y'],
                                   pt [j]['X'], pt [j]['Y']);
          }
          ctx.stroke ();
        }
      }
      break;                   // "bezier"
    }
  }
}

<commit_msg>Last Bezier control point adjusted<commit_after>/********************************************************************
 * candytalking.js
 *
 * Just Another Minimal Charts script
 *
 * Copyright (C) 2014 Jean Zundel <jzu@free.fr>
 * MIT License: https://github.com/jzu/candytalking/blob/master/LICENSE
 *
 * Draws blocks, lines, Bezier curves, and later dots and stacked blocks
 * from a json structure whose name matches a canvas id. Type of graph is
 * given by the class name: "blocks", "lines" or "bezier". All sizes, fonts,
 * etc. are based on the dimensions of the canvas. Executed automatically
 * by default when the page is loaded.
 *
 * Example:

<!DOCTYPE html>
<html>
<head>
 <title>Some Candy Talking</title>
 <script src="candytalking.js"></script>
</head>
<body>
 <script>
   var canvas1 = {
         "title": "Blocks",
         "colors": [ "black", "cyan", "orange" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
   var canvas2 = {
         "title": "Lines",
         "colors": [ "black", "blue", "red" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
   var canvas3 = {
         "title": "Bezier",
         "colors": [ "black", "green", "magenta" ],
         "data": [
                   [ "Day", "01/08", "02/08", "03/08", "04/08" ],
                   [ "Var 1", 1, 2, 3, 4 ],
                   [ "Var 2", -10, 5, 1, 5 ]
                 ]
       };
 </script>
 <canvas id="canvas1" class="blocks" width="800" height="600">
  Canvas require a real browser
 </canvas>
 <canvas id="canvas2" class="lines" width="800" height="600">
  Canvas require a real browser
 </canvas>
 <canvas id="canvas3" class="bezier" width="800" height="600">
  Canvas require a real browser
 </canvas>
</body>
</html>

*/

/***************************************************************************
 * verticalLine()
 *
 * Draws a vertical line in light grey
 ***************************************************************************

function verticalLine () {
      ctx.strokeStyle = "#DDDDDD";
      ctx.beginPath ();
      ctx.moveTo (marginX + spaceXAxis + blockW * (i - 1),
                  marginY + marginTitle + blockH);
      ctx.lineTo (marginX + spaceXAxis + blockW * (i - 1),
                  marginY + marginTitle);
      ctx.stroke ();
}
 */
/****************************************************************************
 * drawY()
 *
 * Draws a Y value in the left margin and the corresponding horizontal line
 ***************************************************************************/

function drawY (canvas_h, ctx, i, marginX, scaleY, spaceXAxis) {

  ctx.fillText (i,
                marginX * 1.5 - ctx.measureText (i).width,
                scaleY);
  ctx.beginPath ();
  ctx.moveTo (marginX * 2, scaleY);
  ctx.lineTo (marginX + canvas_h.width - spaceXAxis, scaleY);
  ctx.stroke ();
}

/****************************************************************************
 * onload() handler
 *
 * Draws charts in all canvases of class "blocks", "lines and "bezier"
 * All dimensions in pixels except yMin, yMax
 *
 * You may want to use this function on demand, for instance if you already
 * have an onload() handler. In this case, just rename it, and call it
 * explicitely from elsewhere.
 ***************************************************************************/

window.onload = function () {

  var canvas = document.getElementsByTagName ("canvas");

  for (var h = 0; h < canvas.length; h++) {

    if ((canvas [h].className != "blocks") &&
        (canvas [h].className != "lines") &&
        (canvas [h].className != "bezier"))
      continue;

    var ctx = canvas [h].getContext ("2d");
    var histName = canvas [h].getAttribute ('id');
    var hist = eval (histName);
    var nbSets = hist.data.length - 1;
    var nbBlocks = hist.data [0].length - 1;

    // Title and text font sizes

    var titleFontSize = (canvas [h].width < canvas [h].height * 4 / 3)
                        ? canvas [h].width / 25
                        : canvas [h].height / 18;
    var textFontSize = (canvas [h].width < canvas [h].height * 4 / 3)
                       ? canvas [h].width / 40
                       : canvas [h].height / 30;

    // Margins

    var marginX = textFontSize * 2;
    var marginY = textFontSize * 2;
    var spaceXAxis = textFontSize * 4;
    var spaceYAxis = textFontSize * 2;
    var marginTitle = textFontSize * 4;

    // A block contains several values if there are several datasets

    var blockW = (canvas [h].width - marginX * 2 - spaceXAxis) / nbBlocks;
    var blockH = canvas [h].height - marginY * 2 - spaceYAxis - marginTitle;

    // Y-axis adjustment

    var yMax = 0;
    for (i = 1; i <= nbSets; i++)
      for (j = 1; j <= nbBlocks; j++)
        yMax = (hist.data [i][j] > yMax)
               ? hist.data [i][j]
               : yMax;
    yMax = (yMax > 0)
           ? yMax
           : 0;
    var yMin = 0;
    for (i = 1; i <= nbSets; i++)
      for (j = 1; j <= nbBlocks; j++)
        yMin = (hist.data [i][j] < yMin)
               ? hist.data [i][j]
               : yMin;
    yMin = (yMin < 0)
           ? yMin
           : 0;

    // Origin on the Y-axis

    var ord0 = marginY + marginTitle + blockH + yMin * blockH / (yMax - yMin);

    // Title

    ctx.font = (titleFontSize + "px Helvetica");
    ctx.fillText (hist.title, marginX * 2, marginY * 1.5);
    ctx.font = (textFontSize + "px Helvetica");

    // X-axis labels

    ctx.fillStyle = hist.colors [0];
    ctx.fillText (hist.data [0][0],
                  marginX ,
                  marginY + marginTitle + blockH + spaceYAxis);
    for (i = 1; i <= nbBlocks; i++) {
      ctx.fillText (hist.data [0][i],
                    marginX + spaceYAxis + blockW * (i - 1)
                    + (blockW - blockW/nbSets + ctx.measureText (hist.data [0][i]).width) / 2,
                    marginY + marginTitle + blockH + spaceYAxis);
    }

    // Draw lines (y=0 is bold) and numbers on the Y-axis
    // Right-align numbers, avoid overlapping
    // First min and max values, then step by step

    ctx.lineWidth = 0;
    ctx.strokeStyle = "#DDD";
    var greyLine = ctx.strokeStyle;

    drawY (canvas [h],
           ctx,
           yMin,
           marginX,
           marginY + marginTitle + blockH,
           spaceXAxis);
    drawY (canvas [h],
           ctx,
           yMax,
           marginX,
           marginY + marginTitle,
           spaceXAxis);

    // Then horizontal lines and Y-axis labels

    var zeroes = 0;
    var range = yMax - yMin;
    var step = range;

    // Intervals on the Y-axis
    // Find +/- the exponent of the range (at 25 => step *= 10)

    if (range >= 1) {
      for (zeroes = 0; step > 25; zeroes++)
        step /= 10;
      step = 1;
      for (i = 0; i < zeroes; i++)
        step *= 10;
    }
    else {
      for (zeroes = 0; step < 2.5; zeroes--)
        step *= 10;
      step = 1;
      for (i = 0; i > zeroes; i--)
        step /= 10;
    }

    var yMinTrunc = -Math.floor (-yMin / step) * step;   // Never > 0

    for (i = yMinTrunc; i <= yMax; i+=step) {
      if ((i - yMin > range / 25) &&
          (yMax - i > range / 25)) {   // Don't you step on my blue suede shoes
        drawY (canvas [h],
               ctx,
               (range < 2.5)
               ? i.toFixed (-zeroes)   // Bug^H^H^H Implementation detail in JS
               : i,
               marginX,
               marginY + marginTitle + blockH + (yMin-i) * blockH / range,
               spaceXAxis);
        if (i == 0) {
          ctx.strokeStyle = "#CCC";
          ctx.stroke ();
          ctx.strokeStyle = greyLine;
        }
      }
    }

    // Coloured dots and dataset names

    var sMaxWidth = 0;
    for (i = 1; i <= nbSets; i++)
      if (ctx.measureText (hist.data [i][0]).width > sMaxWidth)
        sMaxWidth = ctx.measureText (hist.data [i][0]).width;

    for (i = 1; i <= nbSets; i++) {

      ctx.fillStyle = hist.colors [i];
      ctx.strokeStyle = "#BBBBBB";      // Grey ring around the dot

      ctx.beginPath ();
      ctx.arc (canvas [h].width - marginX - sMaxWidth - textFontSize * 1.5,
               marginY + (i - 1) * textFontSize * 1.1 - textFontSize / 2,
               textFontSize * 3 / 7,
               0,
               Math.PI * 2);
      ctx.fill ();
      ctx.stroke ();
      ctx.closePath ();

      ctx.fillStyle = "black";
      ctx.fillText (hist.data [i][0],
                    canvas [h].width - marginX - sMaxWidth,
                    marginY + (i - 1) * textFontSize * 1.1 - 2);
    }

    ctx.shadowColor = '#666';
    ctx.shadowBlur = 20;
    ctx.shadowOffsetX = 5;
    ctx.shadowOffsetY = 5;

    switch (canvas [h].className) {

    case "blocks":

      for (i = 1; i <= nbSets; i++) {
        ctx.fillStyle = hist.colors [i];
        ctx.strokeStyle = hist.colors [i];
        for (j = 1; j <= nbBlocks; j++)
          ctx.fillRect (marginX + spaceXAxis + blockW * (j - 1)
                        + (i - 1) * blockW / (nbSets+1),
                        ord0,
                        blockW / (nbSets+1),
                        -hist.data [i][j] * blockH / (yMax - yMin));
      }
      break;                   // blocks

    case "lines":

      for (i = 1; i <= nbSets; i++) {
        ctx.strokeStyle = hist.colors [i];
        ctx.beginPath ();
        ctx.moveTo (marginX + spaceXAxis,
                    ord0 - hist.data [i][1] * blockH / (yMax - yMin));
        for (j = 2; j <= nbBlocks; j++) {
          ctx.lineTo (marginX + spaceXAxis + blockW * (j - 1),
                      ord0 - hist.data [i][j] * blockH / range);
        }
        ctx.stroke ();
      }
      break;                  // lines

    case "bezier":

      if (nbBlocks >= 3) {
        for (i = 1; i <= nbSets; i++) {

          var pt = [];              // Curve points [number] {X|Y}
          var cp = [];              // Control points [number] [1st|2nd] {X|Y}
          pt [1] = new Object ();
          pt [1]['X'] = marginX + spaceXAxis;
          pt [1]['Y'] = ord0 - hist.data [i][1] * blockH / (yMax - yMin);

          for (j = 2; j <= nbBlocks; j++) {

            pt [j] = new Object ();
            pt [j]['X'] = marginX + spaceXAxis + blockW * (j - 1);
            pt [j]['Y'] = ord0 - hist.data [i][j] * blockH / range;
          }

          ctx.strokeStyle = hist.colors [i];
          ctx.beginPath ();
          ctx.moveTo (pt [1]['X'], pt [1]['Y']);

          cp [1] = [];
          cp [1][1] = new Object ();

          for (j = 2; j < nbBlocks; j++) {

            cp [j-1][2] = new Object ();
            cp [j-1][2]['X'] = (pt [j-1]['X'] + 3 * pt [j]['X']) / 4;
            cp [j-1][2]['Y'] = pt [j]['Y'] + (pt [j-1]['Y'] - pt [j+1]['Y'])/8;
            cp [j] = [];
            cp [j][1] = new Object ();
            cp [j][1]['X'] = (pt [j+1]['X'] + 3 * pt [j]['X']) / 4;
            cp [j][1]['Y'] = pt [j]['Y'] - (pt [j-1]['Y'] - pt [j+1]['Y']) / 8;
          }
          cp [1][1]['X'] = pt [1]['X'];
          cp [1][1]['Y'] = pt [1]['Y'];
          cp [nbBlocks-1][2] = new Object ();
          cp [nbBlocks-1][2]['X'] = (pt [nbBlocks-1]['X']
                                     + 3 * cp [nbBlocks-1][1]['X']) / 4;
          cp [nbBlocks-1][2]['Y'] = (pt [nbBlocks]['Y']
                                     + 3 * cp [nbBlocks-1][1]['Y']) / 4;
        for (j = 2; j <= nbBlocks; j++) {

            ctx.bezierCurveTo (cp [j-1][1]['X'], cp [j-1][1]['Y'],
                                   cp [j-1][2]['X'], cp [j-1][2]['Y'],
                                   pt [j]['X'], pt [j]['Y']);
          }
          ctx.stroke ();
        }
      }
      break;                   // "bezier"
    }
  }
}

<|endoftext|>


<commit_before>define(["./Cedar"],function(Cedar){return Cedar});
<commit_msg>Update module.js<commit_after>/*
 * Copyright (C) 2015 con terra GmbH (info@conterra.de)
 *
 * 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.
 */
define(["./Cedar"],function(Cedar){return Cedar});
<|endoftext|>


<commit_before>doesItSuck.factory('presentationFactory', [ function() {
  var COLORCHOICE = {'SUCKS': 'red', 'DOESN\'T SUCK': 'green', 'MEH': 'yellow'};
  var RESULT_TERMS = {'positive': 'DOESN\'T SUCK', 'negative': 'SUCKS', 'neutral': 'MEH'};

  var methods = {
    evaluateSearch:evaluateSearch,
    getFullColorScheme: getFullColorScheme,
    getColorScheme: getColorScheme,
    insertHTML: insertHTML
  };

  return methods;

  function evaluateSearch(search) {
    if( search.positive > 1.5 * search.negative) {
      return RESULT_TERMS.positive;
    } else if( search.negative > 1.5 * search.positive) {
      return RESULT_TERMS.negative;
    } else {
      return RESULT_TERMS.neutral;
    }
  }

  function getFullColorScheme(search) {
    var evaluated = evaluateSearch(search);
    return COLORCHOICE[evaluated];
  }

  function getColorScheme(search){
    return (search.winner) ? COLORCHOICE['DOESN\'T SUCK'] : COLORCHOICE['SUCKS'];
  }

  function insertHTML(messages){
    messages.forEach(function(msg){
      insertSentimentClass(msg);
      insertKeyWordClass(msg);
    });
  }

  function insertPositiveWordClass(msg){
    var re;
    msg.posWords.forEach(function(pos){
      re = new RegExp(pos, "gi");
      msg.content = msg.content.replace(re,""+pos+"");
    });
  }

  function insertKeyWordClass(msg){
    var re;

  function insertNegativeWordClass(msg){
    var re;
    msg.negWords.forEach(function(neg){
      re = new RegExp(neg, "gi");
      msg.content = msg.content.replace(re,""+neg+"");
    });
  }

  function insertSentimentClass(msg){
    var sentiment = msg.sentiment;
    msg.content = "" + msg.content +"";
  }

}]);
<commit_msg>datacontroller refactored<commit_after>doesItSuck.factory('presentationFactory', [ function() {
  var COLORCHOICE = {'SUCKS': 'red', 'DOESN\'T SUCK': 'green', 'MEH': 'yellow'};
  var RESULT_TERMS = {'positive': 'DOESN\'T SUCK', 'negative': 'SUCKS', 'neutral': 'MEH'};

  var methods = {
    evaluateSearch:evaluateSearch,
    getFullColorScheme: getFullColorScheme,
    getColorScheme: getColorScheme,
    insertHTML: insertHTML
  };

  return methods;

  function evaluateSearch(search) {
    if( search.positive > 1.5 * search.negative) {
      return RESULT_TERMS.positive;
    } else if( search.negative > 1.5 * search.positive) {
      return RESULT_TERMS.negative;
    } else {
      return RESULT_TERMS.neutral;
    }
  }

  function getFullColorScheme(search) {
    var evaluated = evaluateSearch(search);
    return COLORCHOICE[evaluated];
  }

  function getColorScheme(search){
    return (search.winner) ? COLORCHOICE['DOESN\'T SUCK'] : COLORCHOICE['SUCKS'];
  }

  function insertHTML(messages){
    messages.forEach(function(msg){
      insertSentimentClass(msg);
      insertKeyWordClass(msg, 'posWords', 'positive');
      insertKeyWordClass(msg, 'negWords', 'negative');
    });
  }

  function insertKeyWordClass(msg, keyWords, sentiment){
    var re;
    msg[keyWords].forEach(function(word){
      re = new RegExp(word, "gi");
      msg.content = msg.content.replace(re,"" + word + "");
    });
  }

  function insertSentimentClass(msg){
    var sentiment = msg.sentiment;
    msg.content = "" + msg.content +"";
  }

}]);
<|endoftext|>


<commit_before>(function JaptemConfigControllerModule() {
	"use strict";

	angular.module('translate.app')
		.controller('japtemConfigController', JaptemConfigController);

	JaptemConfigController.$inject = ['ttsService', 'configService', 'fileSystemService'];

	function JaptemConfigController(ttsService, configService, fileSystemService) {
		var vm = this;

		vm.languages = [];
		vm.update = update;
		vm.openProfile = openProfile;
		vm.profile = null;
		vm.addMapRow = addMapRow;
		vm.removeRow = removeRow;

		ttsService.getVoices()
			.then(processVoices);

		configService.get('lang')
			.then(function (result) {
				vm.selectedLang = result || 'ja-JP';
			});

		configService.get('rate')
			.then(function (result) {
				vm.ttsRate = result || 0.8;
			});

		configService.get('profile')
			.then(function (result) {
				vm.profile = result;
			});

		function processVoices(voices) {
			vm.languages = voices.filter(filter);

			function filter(current) {
				return current.hasOwnProperty('lang') && current.hasOwnProperty('voiceName') && current.hasOwnProperty('gender') && current.gender === 'female';
			}
		}

		function update() {
			configService.set({
				lang: vm.selectedLang,
				rate: parseFloat(vm.ttsRate),
				profile: vm.profile
			});
		}

		function openProfile() {
			fileSystemService.readTextFile()
				.then(function (file) {
					var parsed = CSV.parse(file.data);
					var translations = [];
					for (var i = 0; i < parsed.length; i++) {
						var obj = parsed[i];
						if (!Array.isArray(obj) || obj.length < 2) {
							continue;
						}

						translations.push({
							key: obj[0],
							value: obj[1]
						});
					}

					vm.profile = {
						name: file.entry.name,
						translations: translations
					};

					vm.update();
				});
		}

		function addMapRow() {
			console.log(vm.mapRowAddKey);
			console.log(vm.mapRowAddValue);
			if (!vm.mapRowAddKey || !vm.mapRowAddValue) {
				return;
			}
			vm.profile.translations.push({
				key: vm.mapRowAddKey,
				value: vm.mapRowAddValue
			});
			vm.update();
			console.log(vm.profile);
			vm.mapRowAddKey = '';
			vm.mapRowAddValue = '';
			console.log(vm.mapRowAddKey);
			console.log(vm.mapRowAddValue);
		}

		function removeRow(index) {
			vm.profile.translations.splice(index, 1);
			vm.update();
		}
	}
})();<commit_msg>Removing logs, adding scroll to bottom<commit_after>(function JaptemConfigControllerModule() {
	"use strict";

	angular.module('translate.app')
		.controller('japtemConfigController', JaptemConfigController);

	JaptemConfigController.$inject = ['ttsService', 'configService', 'fileSystemService', '$timeout'];

	function JaptemConfigController(ttsService, configService, fileSystemService, $timeout) {
		var vm = this;

		vm.languages = [];
		vm.update = update;
		vm.openProfile = openProfile;
		vm.profile = null;
		vm.addMapRow = addMapRow;
		vm.removeRow = removeRow;

		ttsService.getVoices()
			.then(processVoices);

		configService.get('lang')
			.then(function (result) {
				vm.selectedLang = result || 'ja-JP';
			});

		configService.get('rate')
			.then(function (result) {
				vm.ttsRate = result || 0.8;
			});

		configService.get('profile')
			.then(function (result) {
				vm.profile = result;
			});

		var element = document.querySelector('.profile-edit-container');
		$timeout(function() {
			element.scrollTop = element.scrollHeight;
		});

		function processVoices(voices) {
			vm.languages = voices.filter(filter);

			function filter(current) {
				return current.hasOwnProperty('lang') && current.hasOwnProperty('voiceName') && current.hasOwnProperty('gender') && current.gender === 'female';
			}
		}

		function update() {
			configService.set({
				lang: vm.selectedLang,
				rate: parseFloat(vm.ttsRate),
				profile: vm.profile
			});
		}

		function openProfile() {
			fileSystemService.readTextFile()
				.then(function (file) {
					var parsed = CSV.parse(file.data);
					var translations = [];
					for (var i = 0; i < parsed.length; i++) {
						var obj = parsed[i];
						if (!Array.isArray(obj) || obj.length < 2) {
							continue;
						}

						translations.push({
							key: obj[0],
							value: obj[1]
						});
					}

					vm.profile = {
						name: file.entry.name,
						translations: translations
					};

					vm.update();
				});
		}

		function addMapRow() {
			if (!vm.mapRowAddKey || !vm.mapRowAddValue) {
				return;
			}
			vm.profile.translations.push({
				key: vm.mapRowAddKey,
				value: vm.mapRowAddValue
			});
			vm.update();
			vm.mapRowAddKey = '';
			vm.mapRowAddValue = '';
		}

		function removeRow(index) {
			vm.profile.translations.splice(index, 1);
			vm.update();
		}
	}
})();<|endoftext|>


<commit_before>{% load i18n %}
{% load inventree_extras %}

/* globals
    renderErrorMessage,
    showAlertDialog,
*/

/* exported
    inventreeGet,
    inventreeDelete,
    inventreeFormDataUpload,
    showApiError,
*/

$.urlParam = function(name) {
    // eslint-disable-next-line no-useless-escape
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);

    if (results == null) {
        return null;
    }

    return decodeURI(results[1]) || 0;
};

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function inventreeGet(url, filters={}, options={}) {

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: 'GET',
        data: filters,
        dataType: 'json',
        contentType: 'application/json',
        success: function(response) {
            if (options.success) {
                options.success(response);
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            console.error('Error on GET at ' + url);
            console.error(thrownError);
            if (options.error) {
                options.error({
                    error: thrownError
                });
            }
        }
    });
}

function inventreeFormDataUpload(url, data, options={}) {
    /* Upload via AJAX using the FormData approach.
     *
     * Note that the following AJAX parameters are required for FormData upload
     *
     * processData: false
     * contentType: false
     */

    // CSRF cookie token
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        method: options.method || 'POST',
        data: data,
        processData: false,
        contentType: false,
        success: function(data, status, xhr) {
            if (options.success) {
                options.success(data, status, xhr);
            }
        },
        error: function(xhr, status, error) {
            console.log('Form data upload failure: ' + status);

            if (options.error) {
                options.error(xhr, status, error);
            }
        }
    });
}

function inventreePut(url, data={}, options={}) {

    var method = options.method || 'PUT';

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: method,
        data: JSON.stringify(data),
        dataType: 'json',
        contentType: 'application/json',
        success: function(response, status) {
            if (options.success) {
                options.success(response, status);
            }
            if (options.reloadOnSuccess) {
                location.reload();
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            if (options.error) {
                options.error(xhr, ajaxOptions, thrownError);
            } else {
                console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`);
                console.error(thrownError);
            }
        },
        complete: function(xhr, status) {
            if (options.complete) {
                options.complete(xhr, status);
            }
        }
    });
}

function inventreeDelete(url, options={}) {
    /*
     * Delete a record
     */

    options = options || {};

    options.method = 'DELETE';

    return inventreePut(url, {}, options);
}

function showApiError(xhr, url) {

    var title = null;
    var message = null;

    switch (xhr.status) {
    // No response
    case 0:
        title = '{% trans "No Response" %}';
        message = '{% trans "No response from the InvenTree server" %}';
        break;
    // Bad request
    case 400:
        // Note: Normally error code 400 is handled separately,
        //       and should now be shown here!
        title = '{% trans "Error 400: Bad request" %}';
        message = '{% trans "API request returned error code 400" %}';
        break;
    // Not authenticated
    case 401:
        title = '{% trans "Error 401: Not Authenticated" %}';
        message = '{% trans "Authentication credentials not supplied" %}';
        break;
    // Permission denied
    case 403:
        title = '{% trans "Error 403: Permission Denied" %}';
        message = '{% trans "You do not have the required permissions to access this function" %}';
        break;
    // Resource not found
    case 404:
        title = '{% trans "Error 404: Resource Not Found" %}';
        message = '{% trans "The requested resource could not be located on the server" %}';
        break;
    // Timeout
    case 408:
        title = '{% trans "Error 408: Timeout" %}';
        message = '{% trans "Connection timeout while requesting data from server" %}';
        break;
    default:
        title = '{% trans "Unhandled Error Code" %}';
        message = `{% trans "Error code" %}: ${xhr.status}`;
        break;
    }

    message += '
';
    message += `URL: ${url}`;

    showMessage(title, {
        style: 'danger',
        icon: 'fas fa-server icon-red',
        details: message,
    });
}
<commit_msg>Display more errors<commit_after>{% load i18n %}
{% load inventree_extras %}

/* globals
    renderErrorMessage,
    showAlertDialog,
*/

/* exported
    inventreeGet,
    inventreeDelete,
    inventreeFormDataUpload,
    showApiError,
*/

$.urlParam = function(name) {
    // eslint-disable-next-line no-useless-escape
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);

    if (results == null) {
        return null;
    }

    return decodeURI(results[1]) || 0;
};

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function inventreeGet(url, filters={}, options={}) {

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: 'GET',
        data: filters,
        dataType: 'json',
        contentType: 'application/json',
        success: function(response) {
            if (options.success) {
                options.success(response);
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            console.error('Error on GET at ' + url);
            console.error(thrownError);
            if (options.error) {
                options.error({
                    error: thrownError
                });
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreeFormDataUpload(url, data, options={}) {
    /* Upload via AJAX using the FormData approach.
     *
     * Note that the following AJAX parameters are required for FormData upload
     *
     * processData: false
     * contentType: false
     */

    // CSRF cookie token
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        method: options.method || 'POST',
        data: data,
        processData: false,
        contentType: false,
        success: function(data, status, xhr) {
            if (options.success) {
                options.success(data, status, xhr);
            }
        },
        error: function(xhr, status, error) {
            console.log('Form data upload failure: ' + status);

            if (options.error) {
                options.error(xhr, status, error);
            } else {
                showApiError(xhr, url);
            }
        }
    });
}

function inventreePut(url, data={}, options={}) {

    var method = options.method || 'PUT';

    // Middleware token required for data update
    var csrftoken = getCookie('csrftoken');

    return $.ajax({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('X-CSRFToken', csrftoken);
        },
        url: url,
        type: method,
        data: JSON.stringify(data),
        dataType: 'json',
        contentType: 'application/json',
        success: function(response, status) {
            if (options.success) {
                options.success(response, status);
            }
            if (options.reloadOnSuccess) {
                location.reload();
            }
        },
        error: function(xhr, ajaxOptions, thrownError) {
            if (options.error) {
                options.error(xhr, ajaxOptions, thrownError);
            } else {
                console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`);
                console.error(thrownError);

                showApiError(xhr, url);
            }
        },
        complete: function(xhr, status) {
            if (options.complete) {
                options.complete(xhr, status);
            }
        }
    });
}

function inventreeDelete(url, options={}) {
    /*
     * Delete a record
     */

    options = options || {};

    options.method = 'DELETE';

    return inventreePut(url, {}, options);
}

/*
 * Display a notification with error information
 */
function showApiError(xhr, url) {

    var title = null;
    var message = null;

    switch (xhr.status) {
    // No response
    case 0:
        title = '{% trans "No Response" %}';
        message = '{% trans "No response from the InvenTree server" %}';
        break;
    // Bad request
    case 400:
        // Note: Normally error code 400 is handled separately,
        //       and should now be shown here!
        title = '{% trans "Error 400: Bad request" %}';
        message = '{% trans "API request returned error code 400" %}';
        break;
    // Not authenticated
    case 401:
        title = '{% trans "Error 401: Not Authenticated" %}';
        message = '{% trans "Authentication credentials not supplied" %}';
        break;
    // Permission denied
    case 403:
        title = '{% trans "Error 403: Permission Denied" %}';
        message = '{% trans "You do not have the required permissions to access this function" %}';
        break;
    // Resource not found
    case 404:
        title = '{% trans "Error 404: Resource Not Found" %}';
        message = '{% trans "The requested resource could not be located on the server" %}';
        break;
    // Timeout
    case 408:
        title = '{% trans "Error 408: Timeout" %}';
        message = '{% trans "Connection timeout while requesting data from server" %}';
        break;
    default:
        title = '{% trans "Unhandled Error Code" %}';
        message = `{% trans "Error code" %}: ${xhr.status}`;
        break;
    }

    message += '
';
    message += `URL: ${url}`;

    showMessage(title, {
        style: 'danger',
        icon: 'fas fa-server icon-red',
        details: message,
    });
}
<|endoftext|>


<commit_before>/**
 *    Copyright (C) 2015 Deciso B.V.
 *
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 *    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 *    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *    POSSIBILITY OF SUCH DAMAGE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *    User interface shared components, requires opnsense.js for supporting functions.
 */

 /**
  * format bytes
  * @param bytes number of bytes to format
  * @param decimals decimal places
  * @return string
  */
 function byteFormat(bytes, decimals)
 {
     if (decimals == undefined) {
        decimals = 0;
     }
     var kb = 1024;
     var ndx = Math.floor( Math.log(bytes) / Math.log(kb) );
     var fileSizeTypes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
     return (bytes / Math.pow(kb, ndx)).toFixed(decimals) + ' ' + fileSizeTypes[ndx];
 }

/**
 * save form to server
 * @param url endpoint url
 * @param formid parent id to grep input data from
 * @param disable_dialog don't show input validation message box on failure
 */
function saveFormToEndpoint(url,formid,callback_ok, disable_dialog) {
    disable_dialog = disable_dialog || false;
    var data = getFormData(formid);
    ajaxCall(url=url,sendData=data,callback=function(data,status){
        if ( status == "success") {
            // update field validation
            handleFormValidation(formid,data['validations']);

            // if there are validation issues, update our screen and show a dialog.
            if (data['validations'] != undefined) {
                if (!disable_dialog) {
                    var detailsid = "errorfrm"+Math.floor((Math.random() * 10000000) + 1);
                    var errorMessage = $('

');
                    errorMessage.append('Please correct validation errors in form
');
                    errorMessage.append('');
                    errorMessage.append('

');

                    // validation message box is optional, form is already updated using handleFormValidation
                    BootstrapDialog.show({
                        type:BootstrapDialog.TYPE_WARNING,
                        title: 'Input validation',
                        message: errorMessage,
                        buttons: [{
                            label: 'Dismiss',
                            action: function(dialogRef){
                                dialogRef.close();
                            }
                        }],
                        onshown: function(){
                            // set debug information
                            $("#"+detailsid + " > pre").html(JSON.stringify(data, null, 2));
                        }
                    });

                }
            } else if ( callback_ok != undefined ) {
                // execute callback function
                callback_ok();
            }
        }
    });
}

/**
 * standard data mapper to map json request data to forms on this page
 * @param data_get_map named array containing form names and source url's to get data from {'frm_example':"/api/example/settings/get"};
 * @return promise object, resolves when all are loaded
 */
function mapDataToFormUI(data_get_map) {
    var dfObj = new $.Deferred();

    // calculate number of items for deferred object to resolve
    var data_map_seq = 1;
    var data_map_count = 0;
    $.each(data_get_map, function(){
        data_map_count += 1;
    });

    var collected_data = {};
    $.each(data_get_map, function(data_index, data_url) {
        ajaxGet(url=data_url,sendData={}, callback=function(data, status) {
            if (status == "success") {
                $("form").each(function( index ) {
                    if ( $(this).attr('id') && $(this).attr('id').split('-')[0] == data_index) {
                        // related form found, load data
                        setFormData($(this).attr('id'), data);
                        collected_data[$(this).attr('id')] = data;
                    }
                });
            }
            if (data_map_seq == data_map_count) {
                dfObj.resolve(collected_data);
            }
            data_map_seq += 1;
        });
    });

    return dfObj;
}

/**
 * update service status buttons in user interface
 */
function updateServiceStatusUI(status) {

    var status_html = '';

    $('#service_status_container').html(status_html);
}

/**
 * reformat all tokenizers on this document
 */
function formatTokenizersUI(){
    // remove old tokenizers (if any)
    $('div[class="tokenize Tokenize"]').each(function(){
        $(this).remove();
    });
    $('select[class="tokenize"]').each(function(){
        if ($(this).prop("size")==0) {
            maxDropdownHeight=String(36*5)+"px"; // default number of items

        } else {
            number_of_items = $(this).prop("size");
            maxDropdownHeight=String(36*number_of_items)+"px";
        }
        hint=$(this).data("hint");
        width=$(this).data("width");
        allownew=$(this).data("allownew");
        nbDropdownElements=$(this).data("nbdropdownelements");
        maxTokenContainerHeight=$(this).data("maxheight");

        $(this).tokenize({
            displayDropdownOnFocus: true,
            newElements: allownew,
            nbDropdownElements: nbDropdownElements,
            placeholder:hint
        });
        $(this).parent().find('ul[class="TokensContainer"]').parent().css("width",width);
        $(this).parent().find('ul[class="Dropdown"]').css("max-height", maxDropdownHeight);
        if ( maxDropdownHeight != undefined ) {
            $(this).parent().find('ul[class="TokensContainer"]').css("max-height", maxTokenContainerHeight);
        }
    });
}

/**
 * clear multiselect boxes on click event, works on standard and tokenized versions
 */
function addMultiSelectClearUI() {
    $('[id*="clear-options"]').each(function() {
        $(this).click(function() {
            var id = $(this).attr("id").replace(/_*clear-options_*/, '');
            BootstrapDialog.confirm({
                title: 'Deselect or remove all items ?',
                message: 'Deselect or remove all items ?',
                type: BootstrapDialog.TYPE_DANGER,
                closable: true,
                draggable: true,
                btnCancelLabel: 'Cancel',
                btnOKLabel: 'Yes',
                btnOKClass: 'btn-primary',
                callback: function(result) {
                    if(result) {
                        if ($('select[id="' + id + '"]').hasClass("tokenize")) {
                            // trigger close on all Tokens
                            $('select[id="' + id + '"]').parent().find('ul[class="TokensContainer"]').find('li[class="Token"]').find('a').trigger("click");
                        } else {
                            // remove options from selection
                            $('select[id="' + id + '"]').find('option').prop('selected',false);
                        }
                    }
                    // In case this modal was triggered from another modal, fix focus issues
                    $('.modal').on("hidden.bs.modal", function (e) {
                        if($('.modal:visible').length)
                        {
                            $('body').addClass('modal-open');
                        }
                    });
                }
            });
        });
    });
}

/**
 * setup form help buttons
 */
function initFormHelpUI() {
    // handle help messages show/hide
    $("a[class='showhelp']").click(function (event) {
        $("*[for='" + $(this).attr('id') + "']").toggleClass("hidden show");
        event.preventDefault();
    });

    // handle all help messages show/hide
    $('[id*="show_all_help"]').click(function(event) {
        $('[id*="show_all_help"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_all_help"]').toggleClass("text-success text-danger");
        if ($('[id*="show_all_help"]').hasClass("fa-toggle-on")) {
            if (window.sessionStorage) {
                sessionStorage.setItem('all_help_preset', 1);
            }
            $('[for*="help_for"]').addClass("show");
            $('[for*="help_for"]').removeClass("hidden");
        } else {
            $('[for*="help_for"]').addClass("hidden");
            $('[for*="help_for"]').removeClass("show");
            if (window.sessionStorage) {
                sessionStorage.setItem('all_help_preset', 0);
            }
        }
        event.preventDefault();
    });
    if (window.sessionStorage && sessionStorage.getItem('all_help_preset') == 1) {
        // show all help messages when preset was stored
        $('[id*="show_all_help"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_all_help"]').toggleClass("text-success text-danger");
        $('[for*="help_for"]').addClass("show");
        $('[for*="help_for"]').removeClass("hidden");
    }
}

/**
 * handle advanced show/hide
 */
function initFormAdvancedUI() {
    if (window.sessionStorage && sessionStorage.getItem('show_advanced_preset') == 1) {
        // show advanced options when preset was stored
        $('[id*="show_advanced"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_advanced"]').toggleClass("text-success text-danger");
    } else {
        $('[data-advanced*="true"]').hide(function(){
            $('[data-advanced*="true"]').after("

"); // the table row is added to keep correct table striping
        });
    }

    $('[id*="show_advanced"]').click(function() {
        $('[id*="show_advanced"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_advanced"]').toggleClass("text-success text-danger");
        if ($('[id*="show_advanced"]').hasClass("fa-toggle-on")) {
            $('[data-advanced*="true"]').show();
            $('[data-advanced*="hidden_row"]').remove(); // the table row is deleted to keep correct table striping
            if (window.sessionStorage) {
                sessionStorage.setItem('show_advanced_preset', 1);
            }
        } else {
            $('[data-advanced*="true"]').after("

").hide(); // the table row is added to keep correct table striping
            if (window.sessionStorage) {
                sessionStorage.setItem('show_advanced_preset', 0);
            }
        }
    });
}

/**
 * standard dialog when information is required, wrapper around BootstrapDialog
 */
function stdDialogInform(title, message, close, callback, type) {
     var types = {
         "danger": BootstrapDialog.TYPE_DANGER,
         "default": BootstrapDialog.TYPE_DEFAULT,
         "info": BootstrapDialog.TYPE_INFO,
         "primary": BootstrapDialog.TYPE_PRIMARY,
         "success": BootstrapDialog.TYPE_SUCCESS,
         "warning": BootstrapDialog.TYPE_WARNING
    };
    if (!(type in types)) {
        type = 'info';
    }
    BootstrapDialog.show({
        title: title,
        message: message,
        type: types[type],
        buttons: [{
            label: close,
            action: function (dialogRef) {
                if (typeof callback !== 'undefined') {
                    callback();
                }
                dialogRef.close();
            }
        }]
    });
}

/**
 * standard dialog when confirmation is required, wrapper around BootstrapDialog
 */
function stdDialogConfirm(title, message, accept, decline, callback, type) {
     var types = {
         "danger": BootstrapDialog.TYPE_DANGER,
         "default": BootstrapDialog.TYPE_DEFAULT,
         "info": BootstrapDialog.TYPE_INFO,
         "primary": BootstrapDialog.TYPE_PRIMARY,
         "success": BootstrapDialog.TYPE_SUCCESS,
         "warning": BootstrapDialog.TYPE_WARNING
    };
    if (!(type in types)) {
        type = 'warning';
    }
    BootstrapDialog.confirm({
        title: title,
        message: message,
        type: types[type],
        btnCancelLabel: decline,
        btnOKLabel: accept,
        btnOKClass: 'btn-' + type,
        callback: function(result) {
            if (result) {
                callback();
            }
        }
    });
}

/**
 * wrapper for backwards compatibility (do not use)
 */
function stdDialogRemoveItem(message, callback) {
    stdDialogConfirm('Remove', message, 'Yes', 'Cancel', callback);
}
<commit_msg>ui: remap manually instead of flushing for #1689<commit_after>/**
 *    Copyright (C) 2015 Deciso B.V.
 *
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 *    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 *    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *    POSSIBILITY OF SUCH DAMAGE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 *    User interface shared components, requires opnsense.js for supporting functions.
 */

 /**
  * format bytes
  * @param bytes number of bytes to format
  * @param decimals decimal places
  * @return string
  */
 function byteFormat(bytes, decimals)
 {
     if (decimals == undefined) {
        decimals = 0;
     }
     var kb = 1024;
     var ndx = Math.floor( Math.log(bytes) / Math.log(kb) );
     var fileSizeTypes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
     return (bytes / Math.pow(kb, ndx)).toFixed(decimals) + ' ' + fileSizeTypes[ndx];
 }

/**
 * save form to server
 * @param url endpoint url
 * @param formid parent id to grep input data from
 * @param disable_dialog don't show input validation message box on failure
 */
function saveFormToEndpoint(url,formid,callback_ok, disable_dialog) {
    disable_dialog = disable_dialog || false;
    var data = getFormData(formid);
    ajaxCall(url=url,sendData=data,callback=function(data,status){
        if ( status == "success") {
            // update field validation
            handleFormValidation(formid,data['validations']);

            // if there are validation issues, update our screen and show a dialog.
            if (data['validations'] != undefined) {
                if (!disable_dialog) {
                    var detailsid = "errorfrm"+Math.floor((Math.random() * 10000000) + 1);
                    var errorMessage = $('

');
                    errorMessage.append('Please correct validation errors in form
');
                    errorMessage.append('');
                    errorMessage.append('

');

                    // validation message box is optional, form is already updated using handleFormValidation
                    BootstrapDialog.show({
                        type:BootstrapDialog.TYPE_WARNING,
                        title: 'Input validation',
                        message: errorMessage,
                        buttons: [{
                            label: 'Dismiss',
                            action: function(dialogRef){
                                dialogRef.close();
                            }
                        }],
                        onshown: function(){
                            // set debug information
                            $("#"+detailsid + " > pre").html(JSON.stringify(data, null, 2));
                        }
                    });

                }
            } else if ( callback_ok != undefined ) {
                // execute callback function
                callback_ok();
            }
        }
    });
}

/**
 * standard data mapper to map json request data to forms on this page
 * @param data_get_map named array containing form names and source url's to get data from {'frm_example':"/api/example/settings/get"};
 * @return promise object, resolves when all are loaded
 */
function mapDataToFormUI(data_get_map) {
    var dfObj = new $.Deferred();

    // calculate number of items for deferred object to resolve
    var data_map_seq = 1;
    var data_map_count = 0;
    $.each(data_get_map, function(){
        data_map_count += 1;
    });

    var collected_data = {};
    $.each(data_get_map, function(data_index, data_url) {
        ajaxGet(url=data_url,sendData={}, callback=function(data, status) {
            if (status == "success") {
                $("form").each(function( index ) {
                    if ( $(this).attr('id') && $(this).attr('id').split('-')[0] == data_index) {
                        // related form found, load data
                        setFormData($(this).attr('id'), data);
                        collected_data[$(this).attr('id')] = data;
                    }
                });
            }
            if (data_map_seq == data_map_count) {
                dfObj.resolve(collected_data);
            }
            data_map_seq += 1;
        });
    });

    return dfObj;
}

/**
 * update service status buttons in user interface
 */
function updateServiceStatusUI(status) {

    var status_html = '';

    $('#service_status_container').html(status_html);
}

/**
 * reformat all tokenizers on this document
 */
function formatTokenizersUI() {
    $('select[class="tokenize"]').each(function () {
        if ($(this).prop("size")==0) {
            maxDropdownHeight=String(36*5)+"px"; // default number of items
        } else {
            number_of_items = $(this).prop("size");
            maxDropdownHeight=String(36*number_of_items)+"px";
        }
        width=$(this).data("width");
        maxTokenContainerHeight=$(this).data("maxheight");

        $tokenizer = $(this).tokenize();
        $tokenizer.resizeSearchInput();
        $tokenizer.remap(true);
        $tokenizer.updatePlaceholder();

        $(this).parent().find('ul[class="TokensContainer"]').parent().css("width",width);
        $(this).parent().find('ul[class="Dropdown"]').css("max-height", maxDropdownHeight);
        if ( maxDropdownHeight != undefined ) {
            $(this).parent().find('ul[class="TokensContainer"]').css("max-height", maxTokenContainerHeight);
        }
    });
}

/**
 * clear multiselect boxes on click event, works on standard and tokenized versions
 */
function addMultiSelectClearUI() {
    $('[id*="clear-options"]').each(function() {
        $(this).click(function() {
            var id = $(this).attr("id").replace(/_*clear-options_*/, '');
            BootstrapDialog.confirm({
                title: 'Deselect or remove all items ?',
                message: 'Deselect or remove all items ?',
                type: BootstrapDialog.TYPE_DANGER,
                closable: true,
                draggable: true,
                btnCancelLabel: 'Cancel',
                btnOKLabel: 'Yes',
                btnOKClass: 'btn-primary',
                callback: function(result) {
                    if(result) {
                        if ($('select[id="' + id + '"]').hasClass("tokenize")) {
                            // trigger close on all Tokens
                            $('select[id="' + id + '"]').parent().find('ul[class="TokensContainer"]').find('li[class="Token"]').find('a').trigger("click");
                        } else {
                            // remove options from selection
                            $('select[id="' + id + '"]').find('option').prop('selected',false);
                        }
                    }
                    // In case this modal was triggered from another modal, fix focus issues
                    $('.modal').on("hidden.bs.modal", function (e) {
                        if($('.modal:visible').length)
                        {
                            $('body').addClass('modal-open');
                        }
                    });
                }
            });
        });
    });
}

/**
 * setup form help buttons
 */
function initFormHelpUI() {
    // handle help messages show/hide
    $("a[class='showhelp']").click(function (event) {
        $("*[for='" + $(this).attr('id') + "']").toggleClass("hidden show");
        event.preventDefault();
    });

    // handle all help messages show/hide
    $('[id*="show_all_help"]').click(function(event) {
        $('[id*="show_all_help"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_all_help"]').toggleClass("text-success text-danger");
        if ($('[id*="show_all_help"]').hasClass("fa-toggle-on")) {
            if (window.sessionStorage) {
                sessionStorage.setItem('all_help_preset', 1);
            }
            $('[for*="help_for"]').addClass("show");
            $('[for*="help_for"]').removeClass("hidden");
        } else {
            $('[for*="help_for"]').addClass("hidden");
            $('[for*="help_for"]').removeClass("show");
            if (window.sessionStorage) {
                sessionStorage.setItem('all_help_preset', 0);
            }
        }
        event.preventDefault();
    });
    if (window.sessionStorage && sessionStorage.getItem('all_help_preset') == 1) {
        // show all help messages when preset was stored
        $('[id*="show_all_help"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_all_help"]').toggleClass("text-success text-danger");
        $('[for*="help_for"]').addClass("show");
        $('[for*="help_for"]').removeClass("hidden");
    }
}

/**
 * handle advanced show/hide
 */
function initFormAdvancedUI() {
    if (window.sessionStorage && sessionStorage.getItem('show_advanced_preset') == 1) {
        // show advanced options when preset was stored
        $('[id*="show_advanced"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_advanced"]').toggleClass("text-success text-danger");
    } else {
        $('[data-advanced*="true"]').hide(function(){
            $('[data-advanced*="true"]').after("

"); // the table row is added to keep correct table striping
        });
    }

    $('[id*="show_advanced"]').click(function() {
        $('[id*="show_advanced"]').toggleClass("fa-toggle-on fa-toggle-off");
        $('[id*="show_advanced"]').toggleClass("text-success text-danger");
        if ($('[id*="show_advanced"]').hasClass("fa-toggle-on")) {
            $('[data-advanced*="true"]').show();
            $('[data-advanced*="hidden_row"]').remove(); // the table row is deleted to keep correct table striping
            if (window.sessionStorage) {
                sessionStorage.setItem('show_advanced_preset', 1);
            }
        } else {
            $('[data-advanced*="true"]').after("

").hide(); // the table row is added to keep correct table striping
            if (window.sessionStorage) {
                sessionStorage.setItem('show_advanced_preset', 0);
            }
        }
    });
}

/**
 * standard dialog when information is required, wrapper around BootstrapDialog
 */
function stdDialogInform(title, message, close, callback, type) {
     var types = {
         "danger": BootstrapDialog.TYPE_DANGER,
         "default": BootstrapDialog.TYPE_DEFAULT,
         "info": BootstrapDialog.TYPE_INFO,
         "primary": BootstrapDialog.TYPE_PRIMARY,
         "success": BootstrapDialog.TYPE_SUCCESS,
         "warning": BootstrapDialog.TYPE_WARNING
    };
    if (!(type in types)) {
        type = 'info';
    }
    BootstrapDialog.show({
        title: title,
        message: message,
        type: types[type],
        buttons: [{
            label: close,
            action: function (dialogRef) {
                if (typeof callback !== 'undefined') {
                    callback();
                }
                dialogRef.close();
            }
        }]
    });
}

/**
 * standard dialog when confirmation is required, wrapper around BootstrapDialog
 */
function stdDialogConfirm(title, message, accept, decline, callback, type) {
     var types = {
         "danger": BootstrapDialog.TYPE_DANGER,
         "default": BootstrapDialog.TYPE_DEFAULT,
         "info": BootstrapDialog.TYPE_INFO,
         "primary": BootstrapDialog.TYPE_PRIMARY,
         "success": BootstrapDialog.TYPE_SUCCESS,
         "warning": BootstrapDialog.TYPE_WARNING
    };
    if (!(type in types)) {
        type = 'warning';
    }
    BootstrapDialog.confirm({
        title: title,
        message: message,
        type: types[type],
        btnCancelLabel: decline,
        btnOKLabel: accept,
        btnOKClass: 'btn-' + type,
        callback: function(result) {
            if (result) {
                callback();
            }
        }
    });
}

/**
 * wrapper for backwards compatibility (do not use)
 */
function stdDialogRemoveItem(message, callback) {
    stdDialogConfirm('Remove', message, 'Yes', 'Cancel', callback);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C)2012 D. Plaindoux.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*global require */

require([ "jquery", "qunit", "Contrail/Factory", "Core/Socket", "test/jCC" ],
    function (jQuery, QUnit, Factory, socket, jCC) {
        "use strict";

        jCC.scenario("Waiting packet from a server using Socket", function () {
            var dataFlow, client, i;

            jCC.
                Given(function () {
                    dataFlow = Factory.flow.accumulated();
                }).
                And(function () {
                    client = socket("ws://localhost:1337", dataFlow);
                }).
                WhenNothing.
                Then(function () {
                    QUnit.equal(dataFlow.getAccumulation().length, 1);
                }).
                And(function () {
                    QUnit.equal(dataFlow.getAccumulation()[0], "Pong");
                });
        });
    });

/* NODE JS server side - npm install websocket required first
 ------------------------------------------------------------

 var http = require('http');

 var server = http.createServer(function(request, response) {
    // process HTTP request.
 });

 server.listen(1337, function(){});

 // create the server
 var WebSocketServer = require('websocket').server;
 var wsServer = new WebSocketServer({ httpServer: server });

 // WebSocket server
 wsServer.on('request', function(request) {

    var connection = request.accept(null, request.origin);
    console.log((new Date()) + ' Start ' + connection + '.');

    // Handle messages from users here.
    connection.on('message', function(message) {
        console.log("RECV : " + message + "/n");
        connection.send("Pong");
    });

    // Close user connection
    connection.on('close', function(connection) {
        console.log((new Date()) + ' Finish ' + connection + '.');
    });

    console.log((new Date()) + ' Sending initial message ...');
    connection.send("OK for Ping/Pong");
 });

 */<commit_msg>removed tests<commit_after><|endoftext|>


<commit_before>$(document).ready(function(){
    var socket = io();
    var mouseIsDown = false;
    var running = false;
    var runButton = $('#run-button');
    var stopButton = $('#stop-button');
    var clearButton = $('#clear-button');
    var runningText = $('#running-text');
    $(this).mousedown(function() {
        mouseIsDown = true;
    }).mouseup(function() {
        mouseIsDown = false;
    });
    $('td').on('mousedown', function(e){
        e.preventDefault();
        if(running){
            return;
        }
        var cell = $(this);
        if(cell.hasClass('live')){
            socket.emit('cell-deselected', cell.attr('id'));
        }
        else{
            socket.emit('cell-selected', cell.attr('id'));
        }
    });
    $('td').on('mouseout', function(){
        if(running){
            return;
        }
        var cell = $(this);
        if(mouseIsDown &&!cell.hasClass('live')){
            socket.emit('cell-selected', cell.attr('id'));
        }
    });

    clearButton.on('click', function(){
        console.log('clear button clicked');
        if(!running){
            socket.emit('clear');
        }
    });

    runButton.on('click', function(){
        console.log('run button clicked')
        socket.emit('running');
        $(this).attr('disabled', 'disabled');
        stopButton.removeAttr('disabled');
        clearButton.attr('disabled', 'disabled');
        runningText.show();
    });

    stopButton.on('click', function(){
        console.log('stop button clicked')
        socket.emit('stopping');
        $(this).attr('disabled', 'disabled');
        runButton.removeAttr('disabled');
        clearButton.removeAttr('disabled');
        runningText.hide();
    });

    socket.on('join', function(liveCells, isRunning, generationNumber){
        running = isRunning;
        $('#generation-number').text(generationNumber);
        if(running){
            runButton.attr('disabled', 'disabled');
            stopButton.removeAttr('disabled');
            clearButton.attr('disabled', 'disabled');
            runningText.show();
        }
        else{
            runButton.removeAttr('disabled');
            stopButton.attr('disabled', 'disabled');
            clearButton.removeAttr('disabled');
            runningText.hide();
        }
        for(cellKey in liveCells){
            var cell = $('#' + liveCells[id]);
            if(!cell.hasClass('live')){
                cell.addClass('live');
            }
        }
    });

    socket.on('running', function(){
        running = true;
        runButton.attr('disabled', 'disabled');
        stopButton.removeAttr('disabled');
        clearButton.attr('disabled', 'disabled');
        runningText.show();
    });

    socket.on('nextGen', function(generationNumber, cellsBorn, cellsDied){
        $('#generation-number').text(generationNumber);
        var uiCell;
        for(cell in cellsBorn){
            uiCell = $('#' + cell.id);
            if(!uiCell.hasClass('live')){
                uiCell.addClass('live');
            }
        }
        for(cell in cellsDied){
            uiCell = $('#' + cell.id);
            if(uiCell.hasClass('live')){
                uiCell.removeClass('live');
            }
        }
    });

    socket.on('stopping', function(){
        running = false;
        stopButton.attr('disabled', 'disabled');
        runButton.removeAttr('disabled');
        clearButton.removeAttr('disabled');
        runningText.hide();
    });

    socket.on('clear', function(liveCells){
        for(cellKey in liveCells){
            var cell = $('#' + liveCells[cellKey]);
            if(cell.hasClass('live')){
                cell.removeClass('live');
            }
        }
    });

    socket.on('life', function(id){
        console.log('life at ' + id);
        var cell = $('#' + id);
        if(!cell.hasClass('live')){
            cell.addClass('live');
        }
    });

    socket.on('death', function(id){
        console.log('death at ' + id);
        var cell = $('#' + id);
        if(cell.hasClass('live')){
            cell.removeClass('live');
        }
    });
});    <commit_msg>fixed clearing<commit_after>$(document).ready(function(){
    var socket = io();
    var mouseIsDown = false;
    var running = false;
    var runButton = $('#run-button');
    var stopButton = $('#stop-button');
    var clearButton = $('#clear-button');
    var runningText = $('#running-text');
    $(this).mousedown(function() {
        mouseIsDown = true;
    }).mouseup(function() {
        mouseIsDown = false;
    });
    $('td').on('mousedown', function(e){
        e.preventDefault();
        if(running){
            return;
        }
        var cell = $(this);
        if(cell.hasClass('live')){
            socket.emit('cell-deselected', cell.attr('id'));
        }
        else{
            socket.emit('cell-selected', cell.attr('id'));
        }
    });
    $('td').on('mouseout', function(){
        if(running){
            return;
        }
        var cell = $(this);
        if(mouseIsDown &&!cell.hasClass('live')){
            socket.emit('cell-selected', cell.attr('id'));
        }
    });

    clearButton.on('click', function(){
        console.log('clear button clicked');
        if(!running){
            socket.emit('clear');
        }
    });

    runButton.on('click', function(){
        console.log('run button clicked')
        socket.emit('running');
        $(this).attr('disabled', 'disabled');
        stopButton.removeAttr('disabled');
        clearButton.attr('disabled', 'disabled');
        runningText.show();
    });

    stopButton.on('click', function(){
        console.log('stop button clicked')
        socket.emit('stopping');
        $(this).attr('disabled', 'disabled');
        runButton.removeAttr('disabled');
        clearButton.removeAttr('disabled');
        runningText.hide();
    });

    socket.on('join', function(liveCells, isRunning, generationNumber){
        running = isRunning;
        $('#generation-number').text(generationNumber);
        if(running){
            runButton.attr('disabled', 'disabled');
            stopButton.removeAttr('disabled');
            clearButton.attr('disabled', 'disabled');
            runningText.show();
        }
        else{
            runButton.removeAttr('disabled');
            stopButton.attr('disabled', 'disabled');
            clearButton.removeAttr('disabled');
            runningText.hide();
        }
        for(cellKey in liveCells){
            var cell = $('#' + liveCells[id]);
            if(!cell.hasClass('live')){
                cell.addClass('live');
            }
        }
    });

    socket.on('running', function(){
        running = true;
        runButton.attr('disabled', 'disabled');
        stopButton.removeAttr('disabled');
        clearButton.attr('disabled', 'disabled');
        runningText.show();
    });

    socket.on('nextGen', function(generationNumber, cellsBorn, cellsDied){
        $('#generation-number').text(generationNumber);
        var uiCell;
        for(cell in cellsBorn){
            uiCell = $('#' + cell.id);
            if(!uiCell.hasClass('live')){
                uiCell.addClass('live');
            }
        }
        for(cell in cellsDied){
            uiCell = $('#' + cell.id);
            if(uiCell.hasClass('live')){
                uiCell.removeClass('live');
            }
        }
    });

    socket.on('stopping', function(){
        running = false;
        stopButton.attr('disabled', 'disabled');
        runButton.removeAttr('disabled');
        clearButton.removeAttr('disabled');
        runningText.hide();
    });

    socket.on('clear', function(liveCells){
        //surely we could just query for every with the live class and remove that?
        for(cellKey in liveCells){
            var cell = $('#' + liveCells[cellKey].id);
            if(cell.hasClass('live')){
                cell.removeClass('live');
            }
        }
    });

    socket.on('life', function(id){
        console.log('life at ' + id);
        var cell = $('#' + id);
        if(!cell.hasClass('live')){
            cell.addClass('live');
        }
    });

    socket.on('death', function(id){
        console.log('death at ' + id);
        var cell = $('#' + id);
        if(cell.hasClass('live')){
            cell.removeClass('live');
        }
    });
});    <|endoftext|>