<commit_before>/*
  ss.js - This file is part of Slither Sessions Mods

  The MIT License (MIT)
  Copyright (c) 2016 Slither Sessions.  All rights reserved.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights to
  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  of the Software, and to permit persons to whom the Software is furnished to do
  so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

var ss = window.ss = (function() {
  return {
    clanTags: [ 'SS', 'JG', 'YT' ],
    mods: [],
    options: {
      leaderBoardTitle: 'Slither Sessions',
      rotateSkins: false,
      useLastHost: false
    },

    version: function() { return '2.2.5'; },

    isInt: function (n) {
      return !isNaN(n) && Number(n) === n && n % 1 === 0;
    },

    connect: function() {
      if (ss.options.useLastHost) {
        var host = ss.loadOption ('lastHost');
        if (host && host.length > 0) {
          var addy = host.split(':')[0].trim(),
              port = host.split(':')[1].trim();
          forceServer (addy, port);
        }
      }

      window.connect();
    },

    connectToHost: function() {
      defaultIp = ss.loadOption ('lastHost', '');
      eipaddr = prompt ('Enter the IP address:', defaultIp);
      if (eipaddr && eipaddr.indexOf(":") != -1 && eipaddr.indexOf(".") != -1) {
        ss.saveOption ('lastHost', eipaddr);
        var addy = eipaddr.split(':')[0].trim(),
            port = eipaddr.split(':')[1].trim();
        forceServer (addy, port);
        connect();
        ss.waitForSnake (function (s) {
          setSkin (s, ss.skins.skin);
        });
      }
    },

    /** Returns the current IP as provided by Slither */
    currentIp: function() {
      return (typeof bso != 'undefined') ? bso.ip + ":" + bso.po : false;
    },

    forceLastHost: function() {
      var host = ss.loadOption ('lastHost');
      if (host && host.length > 0) {
        var addy = host.split(':')[0].trim(),
            port = host.split(':')[1].trim();
        forceServer (addy, port);
      }
    },

    register: function (mod) {
      ss.mods.push (mod);
      ss[mod.slug] = mod;
      return ss;
    },

    quit: function() {
      return window.userInterface.quit();
    },

    saveOption: function (key, val) {
      return window.userInterface.savePreference (key, val);
    },

    /** Sets background to the given image URL.
        Defaults to slither.io's internal background. */
    setBackground: function (url) {
        url = typeof url !== 'undefined' ? url : '/s/bg45.jpg';
        window.ii.src = url;
    },

    loadOption: function (key, d) {
      return window.userInterface.loadPreference (key, d);
    },

    log: function() {
      if (window.logDebugging)
          console.log.apply (console, arguments);
    },

    onFrameUpdate: function() {
      if (! window.playing || window.snake === null) {
        if (! $(userInterface.connect).is(':visible'))
          $(userInterface.connect).fadeIn();
        return;
      }

      // Botstatus overlay
      if (window.playing && window.snake !== null) {
          let oContent = [];

          oContent.push('fps: ' + userInterface.framesPerSecond.fps);

          // Display the X and Y of the snake
          oContent.push('x: ' +
              (Math.round(window.snake.xx) || 0) + ' y: ' +
              (Math.round(window.snake.yy) || 0));

          if (window.goalCoordinates) {
              oContent.push('target');
              oContent.push('x: ' + window.goalCoordinates.x + ' y: ' +
                  window.goalCoordinates.y);
              if (window.goalCoordinates.sz) {
                  oContent.push('sz: ' + window.goalCoordinates.sz);
              }
          }

          userInterface.overlays.botOverlay.innerHTML = oContent.join('
');

          if (userInterface.gfxOverlay) {
              let gContent = [];

              gContent.push('' + window.snake.nk + '');
              gContent.push(bot.snakeLength);
              gContent.push('[' + window.rank + '/' + window.snake_count + ']');

              userInterface.gfxOverlay.innerHTML = gContent.join('
');
          }
      }

      if (window.playing && window.visualDebugging) {
          // Only draw the goal when a bot has a goal.
          if (window.goalCoordinates && bot.isBotEnabled) {
              var headCoord = { x: window.snake.xx, y: window.snake.yy };
              canvas.drawLine(
                  headCoord,
                  window.goalCoordinates,
                  'green');
              canvas.drawCircle(window.goalCoordinates, 'red', true);
          }
      }

      if ($(userInterface.connect).is(':visible'))
        $(userInterface.connect).fadeOut();

      // customize leaderboard title
      if (typeof window.lbh != 'undefined' && window.lbh.textContent != ss.options.leaderBoardTitle) {
        window.log ("[SS] Updated leaderboard title: " + ss.options.leaderBoardTitle);
        window.lbh.textContent = ss.options.leaderBoardTitle;
      }

      // save last host when it changes
      if (window.bso !== undefined && userInterface.overlays.serverOverlay.innerHTML !==
          window.bso.ip + ':' + window.bso.po) {
          userInterface.overlays.serverOverlay.innerHTML = window.bso.ip + ':' + window.bso.po;
          ss.saveOption ('lastHost', window.bso.ip + ':' + window.bso.po);

          if (typeof ss.onHostChanged != 'undefined')
            ss.onHostChanged();
      }
    },

    /** Override this to react when the server address changes */
    onHostChanged: function() { },

    /** Wait for the player's snake to become available */
    waitForSnake: function (callback, retries) {
      if (! ss.isInt (retries))
        retries = 4;

      var r = 0;

      function _waitForSnake() {
        if (r > retries)
          return;

        if (! window.snake) {
          ss.log('[SS] waiting for snake r=' + r + '...');
          ++r;
          setTimeout (_waitForSnake, 300);
          return;
        }

        callback (window.snake);
      }

      return _waitForSnake();
    },

    quit: function() {
      userInterface.quit();
    }
  };
})();
<commit_msg>experimenting with updating IP display and callback from overridden connect() function<commit_after>/*
  ss.js - This file is part of Slither Sessions Mods

  The MIT License (MIT)
  Copyright (c) 2016 Slither Sessions.  All rights reserved.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights to
  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  of the Software, and to permit persons to whom the Software is furnished to do
  so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

var ss = window.ss = (function() {
  var superConnect = window.connect;

  window.connect = function() {
    var nextHost = ss.currentIp();
    if (nextHost != ss.loadOption ('lastHost')) {
      userInterface.overlays.serverOverlay.innerHTML = nextHost;
      ss.saveOption ('lastHost', nextHost);
      if (typeof ss.onHostChanged != 'undefined')
        ss.onHostChanged();
    }

    return superConnect();
  };

  return {
    clanTags: [ 'SS', 'JG', 'YT' ],
    mods: [],
    options: {
      leaderBoardTitle: 'Slither Sessions',
      rotateSkins: false,
      useLastHost: false
    },

    version: function() { return '2.2.5'; },

    isInt: function (n) {
      return !isNaN(n) && Number(n) === n && n % 1 === 0;
    },

    connect: function() {
      if (ss.options.useLastHost) {
        var host = ss.loadOption ('lastHost');
        if (host && host.length > 0) {
          var addy = host.split(':')[0].trim(),
              port = host.split(':')[1].trim();
          forceServer (addy, port);
        }
      }

      window.connect();
    },

    connectToHost: function() {
      defaultIp = ss.loadOption ('lastHost', '');
      eipaddr = prompt ('Enter the IP address:', defaultIp);
      if (eipaddr && eipaddr.indexOf(":") != -1 && eipaddr.indexOf(".") != -1) {
        ss.saveOption ('lastHost', eipaddr);
        var addy = eipaddr.split(':')[0].trim(),
            port = eipaddr.split(':')[1].trim();
        forceServer (addy, port);
        connect();
        ss.waitForSnake (function (s) {
          setSkin (s, ss.skins.skin);
        });
      }
    },

    /** Returns the current IP as provided by Slither */
    currentIp: function() {
      return (typeof bso != 'undefined') ? bso.ip + ":" + bso.po : false;
    },

    forceLastHost: function() {
      var host = ss.loadOption ('lastHost');
      if (host && host.length > 0) {
        var addy = host.split(':')[0].trim(),
            port = host.split(':')[1].trim();
        forceServer (addy, port);
      }
    },

    register: function (mod) {
      ss.mods.push (mod);
      ss[mod.slug] = mod;
      return ss;
    },

    quit: function() {
      return window.userInterface.quit();
    },

    saveOption: function (key, val) {
      return window.userInterface.savePreference (key, val);
    },

    /** Sets background to the given image URL.
        Defaults to slither.io's internal background. */
    setBackground: function (url) {
        url = typeof url !== 'undefined' ? url : '/s/bg45.jpg';
        window.ii.src = url;
    },

    loadOption: function (key, d) {
      return window.userInterface.loadPreference (key, d);
    },

    log: function() {
      if (window.logDebugging)
          console.log.apply (console, arguments);
    },

    onFrameUpdate: function() {
      if (! window.playing || window.snake === null) {
        if (! $(userInterface.connect).is(':visible'))
          $(userInterface.connect).fadeIn();
        return;
      }

      // Botstatus overlay
      if (window.playing && window.snake !== null) {
          let oContent = [];

          oContent.push('fps: ' + userInterface.framesPerSecond.fps);

          // Display the X and Y of the snake
          oContent.push('x: ' +
              (Math.round(window.snake.xx) || 0) + ' y: ' +
              (Math.round(window.snake.yy) || 0));

          if (window.goalCoordinates) {
              oContent.push('target');
              oContent.push('x: ' + window.goalCoordinates.x + ' y: ' +
                  window.goalCoordinates.y);
              if (window.goalCoordinates.sz) {
                  oContent.push('sz: ' + window.goalCoordinates.sz);
              }
          }

          userInterface.overlays.botOverlay.innerHTML = oContent.join('
');

          if (userInterface.gfxOverlay) {
              let gContent = [];

              gContent.push('' + window.snake.nk + '');
              gContent.push(bot.snakeLength);
              gContent.push('[' + window.rank + '/' + window.snake_count + ']');

              userInterface.gfxOverlay.innerHTML = gContent.join('
');
          }
      }

      if (window.playing && window.visualDebugging) {
          // Only draw the goal when a bot has a goal.
          if (window.goalCoordinates && bot.isBotEnabled) {
              var headCoord = { x: window.snake.xx, y: window.snake.yy };
              canvas.drawLine(
                  headCoord,
                  window.goalCoordinates,
                  'green');
              canvas.drawCircle(window.goalCoordinates, 'red', true);
          }
      }

      if ($(userInterface.connect).is(':visible'))
        $(userInterface.connect).fadeOut();

      // customize leaderboard title
      if (typeof window.lbh != 'undefined' && window.lbh.textContent != ss.options.leaderBoardTitle) {
        window.log ("[SS] Updated leaderboard title: " + ss.options.leaderBoardTitle);
        window.lbh.textContent = ss.options.leaderBoardTitle;
      }

      // // save last host when it changes
      // if (window.bso !== undefined && userInterface.overlays.serverOverlay.innerHTML !==
      //     window.bso.ip + ':' + window.bso.po) {
      //     userInterface.overlays.serverOverlay.innerHTML = window.bso.ip + ':' + window.bso.po;
      //     ss.saveOption ('lastHost', window.bso.ip + ':' + window.bso.po);
      //
      //     if (typeof ss.onHostChanged != 'undefined')
      //       ss.onHostChanged();
      // }
    },

    /** Override this to react when the server address changes */
    onHostChanged: function() { },

    /** Wait for the player's snake to become available */
    waitForSnake: function (callback, retries) {
      if (! ss.isInt (retries))
        retries = 4;

      var r = 0;

      function _waitForSnake() {
        if (r > retries)
          return;

        if (! window.snake) {
          ss.log('[SS] waiting for snake r=' + r + '...');
          ++r;
          setTimeout (_waitForSnake, 300);
          return;
        }

        callback (window.snake);
      }

      return _waitForSnake();
    },

    quit: function() {
      userInterface.quit();
    }
  };
})();
<|endoftext|>


<commit_before><commit_msg>add dep<commit_after><|endoftext|>


<commit_before>/**
 * Created by Juan on 4/6/14.
 */

define('table', ['datatablesLibraries'], function() {
    var self = {};

    self.dataseriesTable = {};
    self.shouldInitialize = true;

    var tableOffsetY = 125;

    self.initializeTable = function() {
        var ui = require('ui');
        var data = require('data');
        var visualization = require('visualization');

        self.dataseriesTable = $('#datasetsTable').dataTable({
            data: data.dataseries,
            dom: 'TftiS',
            stateSave: true,
            deferRender: true,
            scrollCollapse: true,
            scrollY: ($('div#datasetsContent').height() - tableOffsetY),
            scrollX: '100%',
            tableTools: {
                aButtons: [],
                sRowSelect: 'multi',
                sSelectedClass: 'selected',
                fnPreRowSelect: function (event, nodes) {
                    return !event;
                }
            },
            order: [[ 2, "asc" ]],
            columns: [
                {
                    title: 'Plot', orderable: false, type: 'html',
                    render: renderCheckbox, data: 'seriesid', name: 'plot'
                },
                {
                    title: 'Source Network Id',  data: 'sourcedataserviceid',
                    name: 'sourcedataserviceid', visible: false, orderable: false
                },
                {
                    title: 'Quality Control Level Code', data: 'qualitycontrollevelcode',
                    name: 'qualitycontrollevelcode', visible: false, orderable: false
                },
                { title: 'Series',  data: 'seriesid', name: 'seriesid', type: 'numeric' },
                { title: 'Network',  data: 'network',  name: 'network' },
                { title: 'Site Code', data: 'sitecode', name: 'sitecode' },
                { title: 'Site Name', data: 'sitename', name: 'sitename', visible: false },
                { title: 'Latitude', data: 'latitude', name: 'latitude', visible: false },
                { title: 'Longitude', data: 'longitude', name: 'longitude', visible: false },
                { title: 'State', data: 'state', name: 'state', visible: false },
                { title: 'County', data: 'county', name: 'county', visible: false },
                { title: 'Site Type', data: 'sitetype', name: 'sitetype', visible: false },
                { title: 'Variable Code', data: 'variablecode', name: 'variablecode' },
                { title: 'Variable Name', data: 'variablename', name: 'variablename' },
                { title: 'Method', data: 'methoddescription', name: 'methoddescription', visible: false },
                { title: 'Units', data: 'variableunitsname', name: 'variableunitsname', visible: false },
                { title: 'Units Type', data: 'variableunitstype', name: 'variableunitstype', visible: false },
                { title: 'Units Abbreviation', data: 'variableunitsabbreviation', name: 'variableunitsabbreviation', visible: false },
                { title: 'Sample Medium', data: 'samplemedium', name: 'samplemedium', visible: false },
                { title: 'Value Type', data: 'valuetype', name: 'valuetype', visible: false },
                { title: 'Data Type', data: 'datatype', name: 'datatype', visible: false },
                { title: 'Category', data: 'generalcategory', name: 'generalcategory', visible: false },
                { title: 'Time Support', data: 'timesupport', name: 'timesupport', visible: false },
                { title: 'Time Support Units Name', data: 'timesupportunitsname', name: 'timesupportunitsname', visible: false },
                { title: 'Time Support Units Type', data: 'timesupportunitstype', name: 'timesupportunitstype', visible: false },
                { title: 'Time Support Units Abbreviation', data: 'timesupportunitsabbreviation', name: 'timesupportunitsabbreviation', visible: false },
                { title: 'Quality Control Level', data: 'qualitycontrolleveldefinition', name: 'qualitycontrolleveldefinition', visible: false },
                { title: 'Source Organization', data: 'sourceorganization', name: 'sourceorganization', visible: false },
                { title: 'Source Description', data: 'sourcedescription', name: 'sourcedescription', visible: false },
                { title: 'Begin DateTime', data: 'begindatetime', name: 'begindatetime', visible: false },
                { title: 'End DateTime', data: 'enddatetime', name: 'enddatetime', visible: false },
                { title: 'UTC Offset', data: 'utcoffset', name: 'utcoffset', visible: false },
                { title: 'Number Observations', data: 'numberobservations', name: 'numberobservations' },
                { title: 'Date Last Updated', data: 'datelastupdated', name: 'datelastupdated' },
                { title: 'Active', data: 'isactive', name: 'isactive', visible: false }
            ],
            createdRow: function(row, rowData, dataIndex) {
                var tableRow = $(row);

                var plotSeries = _(visualization.plottedSeries).union(visualization.unplottedSeries);
                var selected = (_(plotSeries).findWhere({seriesid: rowData.seriesid}))? 'selected': '';
                tableRow.addClass(selected);

                tableRow.find('td:not(:first)').click(function(){
                    var series = rowData;
                    ui.showDataseriesDialog(series);
                });

                tableRow.find('input[type="checkbox"]').on('change', function() {
                    var tableTools = TableTools.fnGetInstance("datasetsTable");
                    var series = rowData;

                    if (this.checked) {
                        if (!visualization.canPlot()) {
                            this.checked = false;
                            return;
                        }

                        visualization.doPlot = false;
                        visualization.prepareSeries(series);
                        tableTools.fnSelect(this.parentElement.parentElement);
                    } else {
                        visualization.unplotSeries(series.seriesid);
                        tableTools.fnDeselect(this.parentElement.parentElement);
                    }
                });
            }
        });

        var colvis = new $.fn.dataTable.ColVis(self.dataseriesTable);
        colvis.s.aiExclude = [0, 1, 2, 3];
        $.fn.dataTable.ColVis.fnRebuild();
        $(colvis.button()).appendTo('#tableButtons');

        $(window).on('resize', function() {
            _.debounce(self.reDrawTable, 500);
            if ($('.ColVis_collection').is(':visible')) {
                $('.ColVis_catcher').click();
            }
        });

        ui.customizeTableStyle();
        self.shouldInitialize = false;
        self.updateDataseries();
    };

    self.reDrawTable = function() {
        var oSettings = self.dataseriesTable.fnSettings();
        oSettings.oScroll.sY = ($('div#datasetsContent').height() - tableOffsetY);
        self.dataseriesTable.api().draw();
    };

    self.updateDataseries = function() {
        var data = require('data');
        if (self.shouldInitialize) {
            return;
        }
        var api = self.dataseriesTable.api();
        data.facets.forEach(function(facet) {
            var column = api.column(facet.keyfield + ':name');
            var filterRegex = '';

            facet.filters.forEach(function(filter) {
                if (filter.applied) {
                    filterRegex += (filterRegex === '')? '': '|';
                    filterRegex += '(^' + filter[facet.keyfield] + '$)';
                }
            });
            column.search(filterRegex, true, false);
        });
        api.draw();
    };

    self.uncheckSeries = function(id) {
        var tableTools = TableTools.fnGetInstance("datasetsTable");
        var selectedRows = tableTools.fnGetSelected();
        var api = self.dataseriesTable.api();

        selectedRows.forEach(function(row) {
            var rowData = api.row(row).data();
            if (rowData.seriesid === id) {
                tableTools.fnDeselect(row);
                $(row).find('input[type="checkbox"]').prop('checked', false);
            }
        });
    };

    function renderCheckbox(data, type) {
        var visualization = require('visualization');
        var series = _(visualization.plottedSeries).union(visualization.unplottedSeries);
        var checked = (_(series).findWhere({seriesid: data}))? 'checked': '';
        return ('<input data-seriesid="' + data + '" type="checkbox" ' + checked + '>');
    }

    return self;
});<commit_msg>Fixed dataseries table resizing.<commit_after>/**
 * Created by Juan on 4/6/14.
 */

define('table', ['datatablesLibraries'], function() {
    var self = {};

    self.dataseriesTable = {};
    self.shouldInitialize = true;

    var tableOffsetY = 125;

    self.initializeTable = function() {
        var ui = require('ui');
        var data = require('data');
        var visualization = require('visualization');

        self.dataseriesTable = $('#datasetsTable').dataTable({
            data: data.dataseries,
            dom: 'TftiS',
            stateSave: true,
            deferRender: true,
            scrollCollapse: true,
            scrollY: ($('div#datasetsContent').height() - tableOffsetY),
            scrollX: '100%',
            tableTools: {
                aButtons: [],
                sRowSelect: 'multi',
                sSelectedClass: 'selected',
                fnPreRowSelect: function (event, nodes) {
                    return !event;
                }
            },
            order: [[ 2, "asc" ]],
            columns: [
                {
                    title: 'Plot', orderable: false, type: 'html',
                    render: renderCheckbox, data: 'seriesid', name: 'plot'
                },
                {
                    title: 'Source Network Id',  data: 'sourcedataserviceid',
                    name: 'sourcedataserviceid', visible: false, orderable: false
                },
                {
                    title: 'Quality Control Level Code', data: 'qualitycontrollevelcode',
                    name: 'qualitycontrollevelcode', visible: false, orderable: false
                },
                { title: 'Series',  data: 'seriesid', name: 'seriesid', type: 'numeric' },
                { title: 'Network',  data: 'network',  name: 'network' },
                { title: 'Site Code', data: 'sitecode', name: 'sitecode' },
                { title: 'Site Name', data: 'sitename', name: 'sitename', visible: false },
                { title: 'Latitude', data: 'latitude', name: 'latitude', visible: false },
                { title: 'Longitude', data: 'longitude', name: 'longitude', visible: false },
                { title: 'State', data: 'state', name: 'state', visible: false },
                { title: 'County', data: 'county', name: 'county', visible: false },
                { title: 'Site Type', data: 'sitetype', name: 'sitetype', visible: false },
                { title: 'Variable Code', data: 'variablecode', name: 'variablecode' },
                { title: 'Variable Name', data: 'variablename', name: 'variablename' },
                { title: 'Method', data: 'methoddescription', name: 'methoddescription', visible: false },
                { title: 'Units', data: 'variableunitsname', name: 'variableunitsname', visible: false },
                { title: 'Units Type', data: 'variableunitstype', name: 'variableunitstype', visible: false },
                { title: 'Units Abbreviation', data: 'variableunitsabbreviation', name: 'variableunitsabbreviation', visible: false },
                { title: 'Sample Medium', data: 'samplemedium', name: 'samplemedium', visible: false },
                { title: 'Value Type', data: 'valuetype', name: 'valuetype', visible: false },
                { title: 'Data Type', data: 'datatype', name: 'datatype', visible: false },
                { title: 'Category', data: 'generalcategory', name: 'generalcategory', visible: false },
                { title: 'Time Support', data: 'timesupport', name: 'timesupport', visible: false },
                { title: 'Time Support Units Name', data: 'timesupportunitsname', name: 'timesupportunitsname', visible: false },
                { title: 'Time Support Units Type', data: 'timesupportunitstype', name: 'timesupportunitstype', visible: false },
                { title: 'Time Support Units Abbreviation', data: 'timesupportunitsabbreviation', name: 'timesupportunitsabbreviation', visible: false },
                { title: 'Quality Control Level', data: 'qualitycontrolleveldefinition', name: 'qualitycontrolleveldefinition', visible: false },
                { title: 'Source Organization', data: 'sourceorganization', name: 'sourceorganization', visible: false },
                { title: 'Source Description', data: 'sourcedescription', name: 'sourcedescription', visible: false },
                { title: 'Begin DateTime', data: 'begindatetime', name: 'begindatetime', visible: false },
                { title: 'End DateTime', data: 'enddatetime', name: 'enddatetime', visible: false },
                { title: 'UTC Offset', data: 'utcoffset', name: 'utcoffset', visible: false },
                { title: 'Number Observations', data: 'numberobservations', name: 'numberobservations' },
                { title: 'Date Last Updated', data: 'datelastupdated', name: 'datelastupdated' },
                { title: 'Active', data: 'isactive', name: 'isactive', visible: false }
            ],
            createdRow: function(row, rowData, dataIndex) {
                var tableRow = $(row);

                var plotSeries = _(visualization.plottedSeries).union(visualization.unplottedSeries);
                var selected = (_(plotSeries).findWhere({seriesid: rowData.seriesid}))? 'selected': '';
                tableRow.addClass(selected);

                tableRow.find('td:not(:first)').click(function(){
                    var series = rowData;
                    ui.showDataseriesDialog(series);
                });

                tableRow.find('input[type="checkbox"]').on('change', function() {
                    var tableTools = TableTools.fnGetInstance("datasetsTable");
                    var series = rowData;

                    if (this.checked) {
                        if (!visualization.canPlot()) {
                            this.checked = false;
                            return;
                        }

                        visualization.doPlot = false;
                        visualization.prepareSeries(series);
                        tableTools.fnSelect(this.parentElement.parentElement);
                    } else {
                        visualization.unplotSeries(series.seriesid);
                        tableTools.fnDeselect(this.parentElement.parentElement);
                    }
                });
            }
        });

        var colvis = new $.fn.dataTable.ColVis(self.dataseriesTable);
        colvis.s.aiExclude = [0, 1, 2, 3];
        $.fn.dataTable.ColVis.fnRebuild();
        $(colvis.button()).appendTo('#tableButtons');

        var reDraw = _.debounce(self.reDrawTable, 500);

        $(window).on('resize', function() {
            reDraw();
            if ($('.ColVis_collection').is(':visible')) {
                $('.ColVis_catcher').click();
            }
        });

        ui.customizeTableStyle();
        self.shouldInitialize = false;
        self.updateDataseries();
    };

    self.reDrawTable = function() {
        var oSettings = self.dataseriesTable.fnSettings();
        oSettings.oScroll.sY = ($('div#datasetsContent').height() - tableOffsetY);
        self.dataseriesTable.api().draw();
    };

    self.updateDataseries = function() {
        var data = require('data');
        if (self.shouldInitialize) {
            return;
        }
        var api = self.dataseriesTable.api();
        data.facets.forEach(function(facet) {
            var column = api.column(facet.keyfield + ':name');
            var filterRegex = '';

            facet.filters.forEach(function(filter) {
                if (filter.applied) {
                    filterRegex += (filterRegex === '')? '': '|';
                    filterRegex += '(^' + filter[facet.keyfield] + '$)';
                }
            });
            column.search(filterRegex, true, false);
        });
        api.draw();
    };

    self.uncheckSeries = function(id) {
        var tableTools = TableTools.fnGetInstance("datasetsTable");
        var selectedRows = tableTools.fnGetSelected();
        var api = self.dataseriesTable.api();

        selectedRows.forEach(function(row) {
            var rowData = api.row(row).data();
            if (rowData.seriesid === id) {
                tableTools.fnDeselect(row);
                $(row).find('input[type="checkbox"]').prop('checked', false);
            }
        });
    };

    function renderCheckbox(data, type) {
        var visualization = require('visualization');
        var series = _(visualization.plottedSeries).union(visualization.unplottedSeries);
        var checked = (_(series).findWhere({seriesid: data}))? 'checked': '';
        return ('<input data-seriesid="' + data + '" type="checkbox" ' + checked + '>');
    }

    return self;
});<|endoftext|>


<commit_before>import { Object3D } from '../core/Object3D.js';

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Group() {

	Object3D.call( this );

	this.type = 'Group';

}

Group.prototype = Object.assign( Object.create( Object3D.prototype ), {

	constructor: Group

} );

export { Group };
<commit_msg>Add missing isGroup property to Group<commit_after>import { Object3D } from '../core/Object3D.js';

/**
 * @author mrdoob / http://mrdoob.com/
 */

function Group() {

	Object3D.call( this );

	this.type = 'Group';

}

Group.prototype = Object.assign( Object.create( Object3D.prototype ), {

	constructor: Group,

	isGroup: true

} );

export { Group };
<|endoftext|>


<commit_before>const { denodeify } = require('./util')
const bindLate = require('bind-late')
const chalk = require('chalk')
const read = denodeify(require('read'))
const Table = require('cli-table');

export default bindLate({
  color: false,

  chalk: _ => _.color != null
    ? new chalk.constructor({ enabled: _.color })
    : chalk,

  chevron: '>>',

  greyParens: _ => text =>
    _.chalk.enabled
      ? text
          .replace('(', chalk.styles.grey.open + '(')
          .replace(')', ')' + chalk.styles.grey.close)
      : text,

  ask: _ => question =>
    `${_.chalk.green(_.chevron)} ${_.greyParens(question)}`
      + (_.chalk.enabled ? chalk.styles.cyan.open : ''),

  prompt: _ => opts =>
    read(Object.assign({}, opts, { prompt: _.ask(opts.prompt) })),

  error: _ => (...args) =>
    console.error(_.chalk.red(_.chevron), ...args),

  info: _ => (...args) =>
    console.log(_.chalk.blue(_.chevron), ...args),

  date: date =>
    date.toISOString()
      .substr(0, 10),

  time: date =>
    date.toISOString()
      .substr(11, 9),

  dateTime: date =>
    date.toISOString()
      .replace('T', ' ')
      .substr(0, 19),

  title: _ => title =>
    title + '\n'
      + _.chalk.gray(String.repeat('─', _.chalk.stripColor(title).length)),

  post: _ => post =>
    _.chalk.enabled
      ? post.replace(/:[\w\d]+:/g, _.chalk.yellow('$&'))
      : post,

  table: (opts, rows) => {
    const table = new Table(opts)
    table.push(...rows)
    return table.toString()
  },
})
<commit_msg>Remove semicolon<commit_after>const { denodeify } = require('./util')
const bindLate = require('bind-late')
const chalk = require('chalk')
const read = denodeify(require('read'))
const Table = require('cli-table')

export default bindLate({
  color: false,

  chalk: _ => _.color != null
    ? new chalk.constructor({ enabled: _.color })
    : chalk,

  chevron: '>>',

  greyParens: _ => text =>
    _.chalk.enabled
      ? text
          .replace('(', chalk.styles.grey.open + '(')
          .replace(')', ')' + chalk.styles.grey.close)
      : text,

  ask: _ => question =>
    `${_.chalk.green(_.chevron)} ${_.greyParens(question)}`
      + (_.chalk.enabled ? chalk.styles.cyan.open : ''),

  prompt: _ => opts =>
    read(Object.assign({}, opts, { prompt: _.ask(opts.prompt) })),

  error: _ => (...args) =>
    console.error(_.chalk.red(_.chevron), ...args),

  info: _ => (...args) =>
    console.log(_.chalk.blue(_.chevron), ...args),

  date: date =>
    date.toISOString()
      .substr(0, 10),

  time: date =>
    date.toISOString()
      .substr(11, 9),

  dateTime: date =>
    date.toISOString()
      .replace('T', ' ')
      .substr(0, 19),

  title: _ => title =>
    title + '\n'
      + _.chalk.gray(String.repeat('─', _.chalk.stripColor(title).length)),

  post: _ => post =>
    _.chalk.enabled
      ? post.replace(/:[\w\d]+:/g, _.chalk.yellow('$&'))
      : post,

  table: (opts, rows) => {
    const table = new Table(opts)
    table.push(...rows)
    return table.toString()
  },
})
<|endoftext|>


<commit_before>/*
 *  Project: SKT HTML5 Framework
 *  CodeName : CornerStone
 *  FileName : featured-listview.js
 *  Description: 리스트뷰는 코너스톤 UI에 맞게 기본적으로 설정하며, DATA-API를 사용해서 스크립트 사용없이 마크업
 *  속성만으로 작동되도록 구현함.
 *  Author: 김우섭
 *  License :
 */

(function (root, doc, factory) {
	if (typeof define === "function" && define.amd) {

		define([ "backbone", "underscore", "jquery"], function (Backbone, _, $) {
			factory($, root, doc);
			return Backbone.View.extend({
				tagName: "ul",
				initialize: function () {
					this.listenTo(collection, "change", this.render);
					this.listenTo(collection, "reset", this.render);
				},

				addItem: function () {
					var html = document.createElement(this.tagName);
					this.collection.each(function (model) {
						$(html).append(new this.options.itemView({model: model}).render().el);
					});
					this.$el.featuredListView("addItem", html);
				},

				removeItem: function ($target, aNumbers) {
					return this.$el.featuredListView("removeItem", $target, aNumbers);
				},

				render: function () {
					this.$el.featuredListView(this.options);

					this.addItem();

					return this;
				}
			});
		});
	} else {
		// Browser globals
		factory(root.jQuery, root, doc);
	}
}(this, document, function ($, window, document) {
	var pluginName = "featuredListView",
		ListView,
		ListItem,
		defaultOptions;

	var Plugin = function (element, options) {
		var self = this;
		defaultOptions = {
			$scroller: $(window),
			optimization: true,
			SCROLL_THROTTLE: 0,
			scrollEndAction: function () {

			}
		};
		this.$el = $(element);
		this.options = options = $.extend(true, defaultOptions, options);

		infinity.config.SCROLL_THROTTLE = this.options.SCROLL_THROTTLE;
		ListView = infinity.ListView;
		ListItem = infinity.ListItem;

		this.$el.each(function () {
			if (options.optimization) {
				var html = self.$el.html();
				self.$el.html("");

				// 리스트뷰 최적화를 위해 Infinity 적용
				var listView = new ListView($(this));
				$(this).data('listView', listView);
				self.$el.data('listView').append(html);

				// HTML 초기화
				html = "";
			}
		});

		this.scrollHeight = navigator.userAgent.match(":*iPhone:*") && !window.navigator.standalone ? 60 : 0;
		var scrollTop = 0;
		options.$scroller.on("scroll", function (e) {
			if(e.target.tagName) {
				if ($(this)[0].scrollHeight - $(this).scrollTop() == $(this).outerHeight()) {
					options.scrollEndAction();
					console.log("nested", self.$el);
					self.$el.trigger("scrollEnd.cs.liveView");
				}
			} else {
				scrollTop = navigator.userAgent.match("Android") ? $(window).scrollTop() + 100 : $(window).scrollTop();
				if (scrollTop >= ($(document).height() - $(window).height() - self.scrollHeight)) {
					options.scrollEndAction();
					console.log("window", self.$el);
					self.$el.trigger("scrollEnd.cs.liveView");
				}
			}
		});
	};

	Plugin.prototype.addItem = function (options, html) {
		if (options.optimization) {
			this.$el.data('listView').append($(html));
		} else {
			this.$el.append(html);
		}

		// 리스트 아이템 추가를 완료할 때 이벤트를 발생시킨다.
		this.$el.trigger("listView.addItem.done");
	};

	Plugin.prototype.removeItem = function (options, page, items) {
		var i, j;
		var height = 0;
		var length;
		var listItems;
		var target;
		if (options.optimization) {
			if (typeof items === "undefined") {
				listItems = this.$el.data('listView').find(page);
				for (i = 0, length = listItems.length; i < length; i++) {
					listItems[i].remove();
				}
			} else {
				listItems = this.$el.data('listView').find(page);
				for (i = 0, length = listItems.length; i < length; i++) {
					for (j in items) {
						target = listItems[i].$el.find("[data-list-itemid='" + items[j] + "']");
						height += target.height();
						target.remove();
					}
					listItems[i].parent.height = listItems[i].parent.height - height;
				}
			}

			window.scrollTo(window.scrollX, window.scrollY - ($(options.spinner).height()));
		} else {
			if (typeof items === "undefined") {
				page.remove();
			} else {
				for (i in items) {
					page.find("[data-list-itemid='" + items[i] + "']").remove();
				}
			}

			window.scrollTo(window.scrollX, window.scrollY - ($(options.spinner).height()));
		}

		this.refresh();
		// 리스트 아이템 삭제를 완료할때 이벤트를 발생시킨다.
		this.$el.trigger("listView.removeItem.done");
	};

	Plugin.prototype.refresh = function () {
		var listView = this.$el.data('listView');
		var height = 0;

		$(listView.pages).each(function () {
			height += this.height;
		});
		listView.height = height;
		this.$el.children("div").css({"height": listView.height});

		window.scrollTo(window.scrollX, window.scrollY - $(options.spinner).height());
	};

	Plugin.prototype.scrollHandler = function () {
		this.$el.data('listView').scrollHandler();
	};

	// 프로토타입 클래스로 정의된 객체를 플러그인과 연결시킨다.
	$.fn[pluginName] = function (options, page, items) {
		return this.each(function () {
			var $this = $(this);
			var data = $this.data(pluginName);

			// 초기 실행된 경우 플러그인을 해당 엘리먼트에 data 등록
			if (!data) {
				$this.data(pluginName, (data = new Plugin(this, options)))
			}

			// 옵션이 문자로 넘어온 경우 함수를 실행시키도록 한다.
			if (typeof options == 'string') {
				data[options](data.options, page, items);
			}
		});
	};

	$.fn[pluginName].Constructor = Plugin;

	$(function () {
		/**
		 * DATA API (HTML5 Data Attribute)
		 */
		$("[data-featured=listView]").each(function () {
			$(this)[pluginName]();
		});
	});

	return Plugin;
}));<commit_msg>collection undefined 문제 수정<commit_after>/*
 *  Project: SKT HTML5 Framework
 *  CodeName : CornerStone
 *  FileName : featured-listview.js
 *  Description: 리스트뷰는 코너스톤 UI에 맞게 기본적으로 설정하며, DATA-API를 사용해서 스크립트 사용없이 마크업
 *  속성만으로 작동되도록 구현함.
 *  Author: 김우섭
 *  License :
 */

(function (root, doc, factory) {
	if (typeof define === "function" && define.amd) {

		define([ "backbone", "underscore", "jquery"], function (Backbone, _, $) {
			factory($, root, doc);
			return Backbone.View.extend({
				tagName: "ul",
				initialize: function () {
					this.listenTo(this.collection, "change", this.render);
					this.listenTo(this.collection, "reset", this.render);
				},

				addItem: function () {
					var html = document.createElement(this.tagName);
					this.collection.each(function (model) {
						$(html).append(new this.options.itemView({model: model}).render().el);
					});
					this.$el.featuredListView("addItem", html);
				},

				removeItem: function ($target, aNumbers) {
					return this.$el.featuredListView("removeItem", $target, aNumbers);
				},

				render: function () {
					this.$el.featuredListView(this.options);

					this.addItem();

					return this;
				}
			});
		});
	} else {
		// Browser globals
		factory(root.jQuery, root, doc);
	}
}(this, document, function ($, window, document) {
	var pluginName = "featuredListView",
		ListView,
		ListItem,
		defaultOptions;

	var Plugin = function (element, options) {
		var self = this;
		defaultOptions = {
			$scroller: $(window),
			optimization: true,
			SCROLL_THROTTLE: 0,
			scrollEndAction: function () {

			}
		};
		this.$el = $(element);
		this.options = options = $.extend(true, defaultOptions, options);

		infinity.config.SCROLL_THROTTLE = this.options.SCROLL_THROTTLE;
		ListView = infinity.ListView;
		ListItem = infinity.ListItem;

		this.$el.each(function () {
			if (options.optimization) {
				var html = self.$el.html();
				self.$el.html("");

				// 리스트뷰 최적화를 위해 Infinity 적용
				var listView = new ListView($(this));
				$(this).data('listView', listView);
				self.$el.data('listView').append(html);

				// HTML 초기화
				html = "";
			}
		});

		this.scrollHeight = navigator.userAgent.match(":*iPhone:*") && !window.navigator.standalone ? 60 : 0;
		var scrollTop = 0;
		options.$scroller.on("scroll", function (e) {
			if(e.target.tagName) {
				if ($(this)[0].scrollHeight - $(this).scrollTop() == $(this).outerHeight()) {
					options.scrollEndAction();
					console.log("nested", self.$el);
					self.$el.trigger("scrollEnd.cs.liveView");
				}
			} else {
				scrollTop = navigator.userAgent.match("Android") ? $(window).scrollTop() + 100 : $(window).scrollTop();
				if (scrollTop >= ($(document).height() - $(window).height() - self.scrollHeight)) {
					options.scrollEndAction();
					console.log("window", self.$el);
					self.$el.trigger("scrollEnd.cs.liveView");
				}
			}
		});
	};

	Plugin.prototype.addItem = function (options, html) {
		if (options.optimization) {
			this.$el.data('listView').append($(html));
		} else {
			this.$el.append(html);
		}

		// 리스트 아이템 추가를 완료할 때 이벤트를 발생시킨다.
		this.$el.trigger("listView.addItem.done");
	};

	Plugin.prototype.removeItem = function (options, page, items) {
		var i, j;
		var height = 0;
		var length;
		var listItems;
		var target;
		if (options.optimization) {
			if (typeof items === "undefined") {
				listItems = this.$el.data('listView').find(page);
				for (i = 0, length = listItems.length; i < length; i++) {
					listItems[i].remove();
				}
			} else {
				listItems = this.$el.data('listView').find(page);
				for (i = 0, length = listItems.length; i < length; i++) {
					for (j in items) {
						target = listItems[i].$el.find("[data-list-itemid='" + items[j] + "']");
						height += target.height();
						target.remove();
					}
					listItems[i].parent.height = listItems[i].parent.height - height;
				}
			}

			window.scrollTo(window.scrollX, window.scrollY - ($(options.spinner).height()));
		} else {
			if (typeof items === "undefined") {
				page.remove();
			} else {
				for (i in items) {
					page.find("[data-list-itemid='" + items[i] + "']").remove();
				}
			}

			window.scrollTo(window.scrollX, window.scrollY - ($(options.spinner).height()));
		}

		this.refresh();
		// 리스트 아이템 삭제를 완료할때 이벤트를 발생시킨다.
		this.$el.trigger("listView.removeItem.done");
	};

	Plugin.prototype.refresh = function () {
		var listView = this.$el.data('listView');
		var height = 0;

		$(listView.pages).each(function () {
			height += this.height;
		});
		listView.height = height;
		this.$el.children("div").css({"height": listView.height});

		window.scrollTo(window.scrollX, window.scrollY - $(options.spinner).height());
	};

	Plugin.prototype.scrollHandler = function () {
		this.$el.data('listView').scrollHandler();
	};

	// 프로토타입 클래스로 정의된 객체를 플러그인과 연결시킨다.
	$.fn[pluginName] = function (options, page, items) {
		return this.each(function () {
			var $this = $(this);
			var data = $this.data(pluginName);

			// 초기 실행된 경우 플러그인을 해당 엘리먼트에 data 등록
			if (!data) {
				$this.data(pluginName, (data = new Plugin(this, options)))
			}

			// 옵션이 문자로 넘어온 경우 함수를 실행시키도록 한다.
			if (typeof options == 'string') {
				data[options](data.options, page, items);
			}
		});
	};

	$.fn[pluginName].Constructor = Plugin;

	$(function () {
		/**
		 * DATA API (HTML5 Data Attribute)
		 */
		$("[data-featured=listView]").each(function () {
			$(this)[pluginName]();
		});
	});

	return Plugin;
}));<|endoftext|>


<commit_before>/**
 * @module ol/format/OWS
 */
import {inherits} from '../util.js';
import {readHref} from '../format/XLink.js';
import XML from '../format/XML.js';
import {readString} from '../format/xsd.js';
import {makeObjectPropertyPusher, makeObjectPropertySetter, makeStructureNS, pushParseAndPop} from '../xml.js';

/**
 * @const
 * @type {Array.<null|string>}
 */
const NAMESPACE_URIS = [null, 'http://www.opengis.net/ows/1.1'];

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'ServiceIdentification': makeObjectPropertySetter(readServiceIdentification),
    'ServiceProvider': makeObjectPropertySetter(readServiceProvider),
    'OperationsMetadata': makeObjectPropertySetter(readOperationsMetadata)
  });

/**
 * @extends {module:ol/format/XML}
 */
class OWS {
  constructor() {
    XML.call(this);
  }

  /**
   * @inheritDoc
   */
  readFromDocument(doc) {
    for (let n = doc.firstChild; n; n = n.nextSibling) {
      if (n.nodeType == Node.ELEMENT_NODE) {
        return this.readFromNode(n);
      }
    }
    return null;
  }

  /**
   * @inheritDoc
   */
  readFromNode(node) {
    const owsObject = pushParseAndPop({},
      PARSERS, node, []);
    return owsObject ? owsObject : null;
  }
}

inherits(OWS, XML);

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const ADDRESS_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'DeliveryPoint': makeObjectPropertySetter(readString),
    'City': makeObjectPropertySetter(readString),
    'AdministrativeArea': makeObjectPropertySetter(readString),
    'PostalCode': makeObjectPropertySetter(readString),
    'Country': makeObjectPropertySetter(readString),
    'ElectronicMailAddress': makeObjectPropertySetter(readString)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const ALLOWED_VALUES_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Value': makeObjectPropertyPusher(readValue)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const CONSTRAINT_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'AllowedValues': makeObjectPropertySetter(readAllowedValues)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const CONTACT_INFO_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Phone': makeObjectPropertySetter(readPhone),
    'Address': makeObjectPropertySetter(readAddress)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const DCP_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'HTTP': makeObjectPropertySetter(readHttp)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const HTTP_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Get': makeObjectPropertyPusher(readGet),
    'Post': undefined // TODO
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const OPERATION_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'DCP': makeObjectPropertySetter(readDcp)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const OPERATIONS_METADATA_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Operation': readOperation
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const PHONE_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Voice': makeObjectPropertySetter(readString),
    'Facsimile': makeObjectPropertySetter(readString)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const REQUEST_METHOD_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Constraint': makeObjectPropertyPusher(readConstraint)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_CONTACT_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'IndividualName': makeObjectPropertySetter(readString),
        'PositionName': makeObjectPropertySetter(readString),
        'ContactInfo': makeObjectPropertySetter(readContactInfo)
      });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_IDENTIFICATION_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'Abstract': makeObjectPropertySetter(readString),
        'AccessConstraints': makeObjectPropertySetter(readString),
        'Fees': makeObjectPropertySetter(readString),
        'Title': makeObjectPropertySetter(readString),
        'ServiceTypeVersion': makeObjectPropertySetter(readString),
        'ServiceType': makeObjectPropertySetter(readString)
      });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_PROVIDER_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'ProviderName': makeObjectPropertySetter(readString),
        'ProviderSite': makeObjectPropertySetter(readHref),
        'ServiceContact': makeObjectPropertySetter(readServiceContact)
      });

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The address.
 */
function readAddress(node, objectStack) {
  return pushParseAndPop({},
    ADDRESS_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The values.
 */
function readAllowedValues(node, objectStack) {
  return pushParseAndPop({},
    ALLOWED_VALUES_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The constraint.
 */
function readConstraint(node, objectStack) {
  const name = node.getAttribute('name');
  if (!name) {
    return undefined;
  }
  return pushParseAndPop({'name': name},
    CONSTRAINT_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The contact info.
 */
function readContactInfo(node, objectStack) {
  return pushParseAndPop({},
    CONTACT_INFO_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The DCP.
 */
function readDcp(node, objectStack) {
  return pushParseAndPop({},
    DCP_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The GET object.
 */
function readGet(node, objectStack) {
  const href = readHref(node);
  if (!href) {
    return undefined;
  }
  return pushParseAndPop({'href': href},
    REQUEST_METHOD_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The HTTP object.
 */
function readHttp(node, objectStack) {
  return pushParseAndPop({}, HTTP_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The operation.
 */
function readOperation(node, objectStack) {
  const name = node.getAttribute('name');
  const value = pushParseAndPop({},
    OPERATION_PARSERS, node, objectStack);
  if (!value) {
    return undefined;
  }
  const object = /** @type {Object} */
      (objectStack[objectStack.length - 1]);
  object[name] = value;
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The operations metadata.
 */
function readOperationsMetadata(node, objectStack) {
  return pushParseAndPop({},
    OPERATIONS_METADATA_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The phone.
 */
function readPhone(node, objectStack) {
  return pushParseAndPop({},
    PHONE_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service identification.
 */
function readServiceIdentification(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_IDENTIFICATION_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service contact.
 */
function readServiceContact(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_CONTACT_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service provider.
 */
function readServiceProvider(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_PROVIDER_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {string|undefined} The value.
 */
function readValue(node, objectStack) {
  return readString(node);
}

export default OWS;
<commit_msg>Use extends and super for format/OWS<commit_after>/**
 * @module ol/format/OWS
 */
import {readHref} from '../format/XLink.js';
import XML from '../format/XML.js';
import {readString} from '../format/xsd.js';
import {makeObjectPropertyPusher, makeObjectPropertySetter, makeStructureNS, pushParseAndPop} from '../xml.js';

/**
 * @const
 * @type {Array.<null|string>}
 */
const NAMESPACE_URIS = [null, 'http://www.opengis.net/ows/1.1'];

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'ServiceIdentification': makeObjectPropertySetter(readServiceIdentification),
    'ServiceProvider': makeObjectPropertySetter(readServiceProvider),
    'OperationsMetadata': makeObjectPropertySetter(readOperationsMetadata)
  });

class OWS extends XML {
  constructor() {
    super();
  }

  /**
   * @inheritDoc
   */
  readFromDocument(doc) {
    for (let n = doc.firstChild; n; n = n.nextSibling) {
      if (n.nodeType == Node.ELEMENT_NODE) {
        return this.readFromNode(n);
      }
    }
    return null;
  }

  /**
   * @inheritDoc
   */
  readFromNode(node) {
    const owsObject = pushParseAndPop({},
      PARSERS, node, []);
    return owsObject ? owsObject : null;
  }
}

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const ADDRESS_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'DeliveryPoint': makeObjectPropertySetter(readString),
    'City': makeObjectPropertySetter(readString),
    'AdministrativeArea': makeObjectPropertySetter(readString),
    'PostalCode': makeObjectPropertySetter(readString),
    'Country': makeObjectPropertySetter(readString),
    'ElectronicMailAddress': makeObjectPropertySetter(readString)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const ALLOWED_VALUES_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Value': makeObjectPropertyPusher(readValue)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const CONSTRAINT_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'AllowedValues': makeObjectPropertySetter(readAllowedValues)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const CONTACT_INFO_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Phone': makeObjectPropertySetter(readPhone),
    'Address': makeObjectPropertySetter(readAddress)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const DCP_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'HTTP': makeObjectPropertySetter(readHttp)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const HTTP_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Get': makeObjectPropertyPusher(readGet),
    'Post': undefined // TODO
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const OPERATION_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'DCP': makeObjectPropertySetter(readDcp)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const OPERATIONS_METADATA_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Operation': readOperation
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const PHONE_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Voice': makeObjectPropertySetter(readString),
    'Facsimile': makeObjectPropertySetter(readString)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const REQUEST_METHOD_PARSERS = makeStructureNS(
  NAMESPACE_URIS, {
    'Constraint': makeObjectPropertyPusher(readConstraint)
  });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_CONTACT_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'IndividualName': makeObjectPropertySetter(readString),
        'PositionName': makeObjectPropertySetter(readString),
        'ContactInfo': makeObjectPropertySetter(readContactInfo)
      });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_IDENTIFICATION_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'Abstract': makeObjectPropertySetter(readString),
        'AccessConstraints': makeObjectPropertySetter(readString),
        'Fees': makeObjectPropertySetter(readString),
        'Title': makeObjectPropertySetter(readString),
        'ServiceTypeVersion': makeObjectPropertySetter(readString),
        'ServiceType': makeObjectPropertySetter(readString)
      });

/**
 * @const
 * @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
 */
const SERVICE_PROVIDER_PARSERS =
    makeStructureNS(
      NAMESPACE_URIS, {
        'ProviderName': makeObjectPropertySetter(readString),
        'ProviderSite': makeObjectPropertySetter(readHref),
        'ServiceContact': makeObjectPropertySetter(readServiceContact)
      });

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The address.
 */
function readAddress(node, objectStack) {
  return pushParseAndPop({},
    ADDRESS_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The values.
 */
function readAllowedValues(node, objectStack) {
  return pushParseAndPop({},
    ALLOWED_VALUES_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The constraint.
 */
function readConstraint(node, objectStack) {
  const name = node.getAttribute('name');
  if (!name) {
    return undefined;
  }
  return pushParseAndPop({'name': name},
    CONSTRAINT_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The contact info.
 */
function readContactInfo(node, objectStack) {
  return pushParseAndPop({},
    CONTACT_INFO_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The DCP.
 */
function readDcp(node, objectStack) {
  return pushParseAndPop({},
    DCP_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The GET object.
 */
function readGet(node, objectStack) {
  const href = readHref(node);
  if (!href) {
    return undefined;
  }
  return pushParseAndPop({'href': href},
    REQUEST_METHOD_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The HTTP object.
 */
function readHttp(node, objectStack) {
  return pushParseAndPop({}, HTTP_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The operation.
 */
function readOperation(node, objectStack) {
  const name = node.getAttribute('name');
  const value = pushParseAndPop({},
    OPERATION_PARSERS, node, objectStack);
  if (!value) {
    return undefined;
  }
  const object = /** @type {Object} */
      (objectStack[objectStack.length - 1]);
  object[name] = value;
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The operations metadata.
 */
function readOperationsMetadata(node, objectStack) {
  return pushParseAndPop({},
    OPERATIONS_METADATA_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The phone.
 */
function readPhone(node, objectStack) {
  return pushParseAndPop({},
    PHONE_PARSERS, node, objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service identification.
 */
function readServiceIdentification(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_IDENTIFICATION_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service contact.
 */
function readServiceContact(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_CONTACT_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {Object|undefined} The service provider.
 */
function readServiceProvider(node, objectStack) {
  return pushParseAndPop(
    {}, SERVICE_PROVIDER_PARSERS, node,
    objectStack);
}

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @return {string|undefined} The value.
 */
function readValue(node, objectStack) {
  return readString(node);
}

export default OWS;
<|endoftext|>


<commit_before>var skui = {}
sk.ui = skui;

skui.Component = function(){
	this.element = sk.div();
	this.container = this.element;
	return this;
}

skui.component = function(){
	return new skui.Component();
}

skui.section = function(cArgs){
	var container = {};
	container.container = sk.c('div', cArgs);
	container.element = container.container;
	container.container.classList.add('section');
	container.header = sk.c('div', {
		cls: 'header',
		parent: container.container,
	});
	container.body = sk.c('div', {
		parent: container.container,
		cls: 'body',
	});
	container.footer = sk.c('div', {
		parent: container.container,
		cls: 'footer',
	});
	return container;
}

skui.window = function(){
	var args = sk.args(arguments, 'str title, num? level, args?');
	var wind = {};
	wind.container = sk.div(args);
	wind.container.classList.add('skui-wind');
	wind.element = wind.container;
	wind.container.classList.add('window');
	wind.header = sk.c('div', {
		cls: 'header skui-wind-header',
		parent: wind.container,
	});
	wind.actions = sk.c('div', wind.header, 'skui-wind-actions');
	wind.title = sk.c('h' + (args.level || 2), wind.header, 'skui-wind-title title', {content: args.title || 'Window'});
	wind.toolbar = sk.c('div', wind.element, 'toolbar skui-wind-toolbar');
	wind.body = sk.c('div', wind.element, 'body skui-wind-body');
	wind.footer = sk.c('div', wind.element, 'footer skui-wind-footer');
	return wind;
}

// skui.labeled = function()

// Scene manager
skui.scenes = function(cArgs){
	var self = {};
	self.container = sk.c(cArgs);
	self.nextId = 1;
	self.scenes = {};
	self.activeScenes = [];
	self.add = function(args){
		self.container.appendChild(args.container);
		self.scenes[self.nextId] = args;
		args.container.dataset.sceneId = self.nextId;
		self.nextId += 1;
	}
	self.activate = function(scene){
		if(scene.parentNode === self.container){
			scene.classList.add('active');
			self.activeScenes.push(scene);
			var onactivated = self.scenes[scene.dataset.sceneId].onactivated;
			if(typeof onactivated === 'function'){
				onactivated.call();
			}
		}
	}
	self.deactivate = function(scene){
		scene.classList.remove('active');
	}
	self.deactivateAll = function(){
		for(var i in self.activeScenes){
			self.deactivate(self.activeScenes[i])
		}
		self.activeScenes = [];
	}
	self.reset = function(scene){
		self.deactivateAll();
		self.activate(scene);
	}
	return self;
}

skui.controlContainer = function(args, label){
	var out = {
		container: sk.c('div', args),
	};
	out.container.classList.add('control-container');
	out.container.classList.add('form-group');
	out.header = sk.c('div', {
		parent: out.container,
		cls: 'header',
	})
	out.label = sk.c('label', {
		parent: out.header,
		cls: 'control-label',
		content: label,
	})
	out.body = sk.c('div', {
		parent: out.container,
		cls: 'body',
	})
	return out;
}

skui.textControl = function(args, label, name, value){
	var control = skui.controlContainer(args, label);
	control.input = sk.c('input', {
		parent: control.body,
		content: value,
		id: true,
		attr: {
			name: name,
			type: 'text',
		},
		cls: 'control text-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.textareaControl = function(args, label, name, value){
	var control = skui.controlContainer(args, label);
	control.input = sk.c('textarea', {
		parent: control.body,
		content: value,
		id: true,
		attr: {
			name: name,
		},
		cls: 'control textarea-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.numberControl = function(){
	var args = sk.args(arguments,
		'obj? contArgs, str label, str name, args?',
		{
			label: 'Number',
		});
	var control = skui.controlContainer(args.contArgs, args.label);
	control.input = sk.c('input', {
		parent: control.body,
		id: true,
		attr: {
			name: args.name,
			type: 'number',
		},
		cls: 'control number-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.fileControl = function(){
	var args = sk.args(arguments,
		'obj? contArgs, str label, str name, args?',
		{
			label: 'File',
		});
	var control = skui.controlContainer(args.contArgs, args.label);
	control.input = sk.c('input', {
		parent: control.body,
		id: true,
		attr: {
			name: args.name,
			type: 'file',
		},
		cls: 'control file-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.menu = function(){
	var menu = {};
	menu.element = sk.c('ul',{
		cls: 'menu-list'
	});
	menu.container = menu.element;
	menu.activator = sk.activator({
		activation: function(prev, next){
			next.element.classList.add('active');
		},
		deactivation: function(prev){
			prev.element.classList.remove('active');
		}
	});
	menu.item = function(content, action){
		var item = {
			action: action,
			menu: menu,
		};
		item.element = sk.c('li', menu.element, {
			action: function(){
				item.activate();
			}
		});
		item.element.appendChild(content);
		item.activate = function(){
			if(typeof item.action === 'function'){
				item.action();
			}
		}
	}
	return menu;
}

sk.ui.admin = function(args){
	var admin = {};
	admin.element = sk.div(args);
	admin.element.classList.add('skui-admin');
	admin.header = sk.div({
		parent: admin.element,
		cls: 'skui-admin-header'
	});
	admin.body = sk.div({
		parent: admin.element,
		cls: 'skui-admin-body',
	})
	admin.navigation = sk.div({
		parent: admin.body,
		cls: 'skui-admin-nav',
	});
	admin.main = sk.ui.scenes({
		parent: admin.body,
		cls: 'skui-admin-main',
	});
	admin.footer = sk.div({
		parent: admin.element,
		cls: 'skui-admin-footer'
	});

	admin.menu = sk.ui.scenes({
		parent: admin.navigation,
	});

	admin.brand = sk.span({
		parent: admin.header,
		cls: 'skui-admin-brand',
		text: args.brandName || '',
	});

	return admin;
}
<commit_msg>Add sk.ui.field()<commit_after>var skui = {}
sk.ui = skui;

skui.Component = function(){
	this.element = sk.div();
	this.container = this.element;
	return this;
}

skui.component = function(){
	return new skui.Component();
}

skui.section = function(cArgs){
	var container = {};
	container.container = sk.c('div', cArgs);
	container.element = container.container;
	container.container.classList.add('section');
	container.header = sk.c('div', {
		cls: 'header',
		parent: container.container,
	});
	container.body = sk.c('div', {
		parent: container.container,
		cls: 'body',
	});
	container.footer = sk.c('div', {
		parent: container.container,
		cls: 'footer',
	});
	return container;
}

skui.window = function(){
	var args = sk.args(arguments, 'str title, num? level, args?');
	var wind = {};
	wind.container = sk.div(args);
	wind.container.classList.add('skui-wind');
	wind.element = wind.container;
	wind.container.classList.add('window');
	wind.header = sk.c('div', {
		cls: 'header skui-wind-header',
		parent: wind.container,
	});
	wind.actions = sk.c('div', wind.header, 'skui-wind-actions');
	wind.title = sk.c('h' + (args.level || 2), wind.header, 'skui-wind-title title', {content: args.title || 'Window'});
	wind.toolbar = sk.c('div', wind.element, 'toolbar skui-wind-toolbar');
	wind.body = sk.c('div', wind.element, 'body skui-wind-body');
	wind.footer = sk.c('div', wind.element, 'footer skui-wind-footer');
	return wind;
}

// skui.labeled = function()

// Scene manager
skui.scenes = function(cArgs){
	var self = {};
	self.container = sk.c(cArgs);
	self.nextId = 1;
	self.scenes = {};
	self.activeScenes = [];
	self.add = function(args){
		self.container.appendChild(args.container);
		self.scenes[self.nextId] = args;
		args.container.dataset.sceneId = self.nextId;
		self.nextId += 1;
	}
	self.activate = function(scene){
		if(scene.parentNode === self.container){
			scene.classList.add('active');
			self.activeScenes.push(scene);
			var onactivated = self.scenes[scene.dataset.sceneId].onactivated;
			if(typeof onactivated === 'function'){
				onactivated.call();
			}
		}
	}
	self.deactivate = function(scene){
		scene.classList.remove('active');
	}
	self.deactivateAll = function(){
		for(var i in self.activeScenes){
			self.deactivate(self.activeScenes[i])
		}
		self.activeScenes = [];
	}
	self.reset = function(scene){
		self.deactivateAll();
		self.activate(scene);
	}
	return self;
}

sk.ui.field = function(args){
	var field = {};
	field.element = sk.div(args);
	field.element.classList.add('skui-field');

	field.header = sk.div({
		parent: field.element,
		cls: 'skui-field-header',
	});

	field.body = sk.div({
		parent: field.element,
		cls: 'skui-field-body',
	});

	field.label = sk.html({
		tag: 'label',
		parent: field.header,
		cls: 'skui-field-label',
		text: args.label,
	});
	return field;
}

skui.controlContainer = function(args, label){
	var out = {
		container: sk.c('div', args),
	};
	out.container.classList.add('control-container');
	out.container.classList.add('form-group');
	out.header = sk.c('div', {
		parent: out.container,
		cls: 'header',
	})
	out.label = sk.c('label', {
		parent: out.header,
		cls: 'control-label',
		content: label,
	})
	out.body = sk.c('div', {
		parent: out.container,
		cls: 'body',
	})
	return out;
}

skui.textControl = function(args, label, name, value){
	var control = skui.controlContainer(args, label);
	control.input = sk.c('input', {
		parent: control.body,
		content: value,
		id: true,
		attr: {
			name: name,
			type: 'text',
		},
		cls: 'control text-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.textareaControl = function(args, label, name, value){
	var control = skui.controlContainer(args, label);
	control.input = sk.c('textarea', {
		parent: control.body,
		content: value,
		id: true,
		attr: {
			name: name,
		},
		cls: 'control textarea-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.numberControl = function(){
	var args = sk.args(arguments,
		'obj? contArgs, str label, str name, args?',
		{
			label: 'Number',
		});
	var control = skui.controlContainer(args.contArgs, args.label);
	control.input = sk.c('input', {
		parent: control.body,
		id: true,
		attr: {
			name: args.name,
			type: 'number',
		},
		cls: 'control number-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.fileControl = function(){
	var args = sk.args(arguments,
		'obj? contArgs, str label, str name, args?',
		{
			label: 'File',
		});
	var control = skui.controlContainer(args.contArgs, args.label);
	control.input = sk.c('input', {
		parent: control.body,
		id: true,
		attr: {
			name: args.name,
			type: 'file',
		},
		cls: 'control file-control form-control',
	});
	control.label.htmlFor = control.input.id;
	return control;
}

skui.menu = function(){
	var menu = {};
	menu.element = sk.c('ul',{
		cls: 'menu-list'
	});
	menu.container = menu.element;
	menu.activator = sk.activator({
		activation: function(prev, next){
			next.element.classList.add('active');
		},
		deactivation: function(prev){
			prev.element.classList.remove('active');
		}
	});
	menu.item = function(content, action){
		var item = {
			action: action,
			menu: menu,
		};
		item.element = sk.c('li', menu.element, {
			action: function(){
				item.activate();
			}
		});
		item.element.appendChild(content);
		item.activate = function(){
			if(typeof item.action === 'function'){
				item.action();
			}
		}
	}
	return menu;
}

sk.ui.admin = function(args){
	var admin = {};
	admin.element = sk.div(args);
	admin.element.classList.add('skui-admin');
	admin.header = sk.div({
		parent: admin.element,
		cls: 'skui-admin-header'
	});
	admin.body = sk.div({
		parent: admin.element,
		cls: 'skui-admin-body',
	})
	admin.navigation = sk.div({
		parent: admin.body,
		cls: 'skui-admin-nav',
	});
	admin.main = sk.ui.scenes({
		parent: admin.body,
		cls: 'skui-admin-main',
	});
	admin.footer = sk.div({
		parent: admin.element,
		cls: 'skui-admin-footer'
	});

	admin.menu = sk.ui.scenes({
		parent: admin.navigation,
	});

	admin.brand = sk.span({
		parent: admin.header,
		cls: 'skui-admin-brand',
		text: args.brandName || '',
	});

	return admin;
}
<|endoftext|>


<commit_before>/**
 * @module ol/style/Text
 */
import Fill from './Fill.js';
import TextPlacement from './TextPlacement.js';

/**
 * The default fill color to use if no fill was set at construction time; a
 * blackish `#333`.
 *
 * @const {string}
 */
const DEFAULT_FILL_COLOR = '#333';

/**
 * @typedef {Object} Options
 * @property {string} [font] Font style as CSS 'font' value, see:
 * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font. Default is '10px sans-serif'
 * @property {number} [maxAngle] When `placement` is set to `'line'`, allow a maximum angle between adjacent characters.
 * The expected value is in radians, and the default is 45° (`Math.PI / 4`).
 * @property {number} [offsetX=0] Horizontal text offset in pixels. A positive will shift the text right.
 * @property {number} [offsetY=0] Vertical text offset in pixels. A positive will shift the text down.
 * @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed
 * the width of the polygon at the label position or the length of the path that it follows.
 * @property {import("./TextPlacement.js").default|string} [placement] Text placement.
 * @property {number} [scale] Scale.
 * @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.
 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
 * @property {string} [text] Text content.
 * @property {string} [textAlign] Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
 * Default is 'center' for `placement: 'point'`. For `placement: 'line'`, the default is to let the renderer choose a
 * placement where `maxAngle` is not exceeded.
 * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
 * 'hanging', 'ideographic'.
 * @property {import("./Fill.js").default} [fill] Fill style. If none is provided, we'll use a dark fill-style (#333).
 * @property {import("./Stroke.js").default} [stroke] Stroke style.
 * @property {import("./Fill.js").default} [backgroundFill] Fill style for the text background when `placement` is
 * `'point'`. Default is no fill.
 * @property {import("./Stroke.js").default} [backgroundStroke] Stroke style for the text background  when `placement`
 * is `'point'`. Default is no stroke.
 * @property {Array<number>} [padding=[0, 0, 0, 0]] Padding in pixels around the text for decluttering and background. The order of
 * values in the array is `[top, right, bottom, left]`.
 */

/**
 * @classdesc
 * Set text style for vector features.
 * @api
 */
class Text {
  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    const options = opt_options || {};

    /**
    * @private
    * @type {string|undefined}
    */
    this.font_ = options.font;

    /**
    * @private
    * @type {number|undefined}
    */
    this.rotation_ = options.rotation;

    /**
    * @private
    * @type {boolean|undefined}
    */
    this.rotateWithView_ = options.rotateWithView;

    /**
    * @private
    * @type {number|undefined}
    */
    this.scale_ = options.scale;

    /**
    * @private
    * @type {string|undefined}
    */
    this.text_ = options.text;

    /**
    * @private
    * @type {string|undefined}
    */
    this.textAlign_ = options.textAlign;

    /**
    * @private
    * @type {string|undefined}
    */
    this.textBaseline_ = options.textBaseline;

    /**
    * @private
    * @type {import("./Fill.js").default}
    */
    this.fill_ = options.fill !== undefined ? options.fill :
      new Fill({color: DEFAULT_FILL_COLOR});

    /**
    * @private
    * @type {number}
    */
    this.maxAngle_ = options.maxAngle !== undefined ? options.maxAngle : Math.PI / 4;

    /**
    * @private
    * @type {import("./TextPlacement.js").default|string}
    */
    this.placement_ = options.placement !== undefined ? options.placement : TextPlacement.POINT;

    /**
    * @private
    * @type {boolean}
    */
    this.overflow_ = !!options.overflow;

    /**
    * @private
    * @type {import("./Stroke.js").default}
    */
    this.stroke_ = options.stroke !== undefined ? options.stroke : null;

    /**
    * @private
    * @type {number}
    */
    this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;

    /**
    * @private
    * @type {number}
    */
    this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;

    /**
    * @private
    * @type {import("./Fill.js").default}
    */
    this.backgroundFill_ = options.backgroundFill ? options.backgroundFill : null;

    /**
    * @private
    * @type {import("./Stroke.js").default}
    */
    this.backgroundStroke_ = options.backgroundStroke ? options.backgroundStroke : null;

    /**
    * @private
    * @type {Array<number>}
    */
    this.padding_ = options.padding === undefined ? null : options.padding;
  }

  /**
  * Clones the style.
  * @return {Text} The cloned style.
  * @api
  */
  clone() {
    return new Text({
      font: this.getFont(),
      placement: this.getPlacement(),
      maxAngle: this.getMaxAngle(),
      overflow: this.getOverflow(),
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      scale: this.getScale(),
      text: this.getText(),
      textAlign: this.getTextAlign(),
      textBaseline: this.getTextBaseline(),
      fill: this.getFill() ? this.getFill().clone() : undefined,
      stroke: this.getStroke() ? this.getStroke().clone() : undefined,
      offsetX: this.getOffsetX(),
      offsetY: this.getOffsetY(),
      backgroundFill: this.getBackgroundFill() ? this.getBackgroundFill().clone() : undefined,
      backgroundStroke: this.getBackgroundStroke() ? this.getBackgroundStroke().clone() : undefined
    });
  }

  /**
  * Get the `overflow` configuration.
  * @return {boolean} Let text overflow the length of the path they follow.
  * @api
  */
  getOverflow() {
    return this.overflow_;
  }

  /**
  * Get the font name.
  * @return {string|undefined} Font.
  * @api
  */
  getFont() {
    return this.font_;
  }

  /**
  * Get the maximum angle between adjacent characters.
  * @return {number} Angle in radians.
  * @api
  */
  getMaxAngle() {
    return this.maxAngle_;
  }

  /**
  * Get the label placement.
  * @return {import("./TextPlacement.js").default|string} Text placement.
  * @api
  */
  getPlacement() {
    return this.placement_;
  }

  /**
  * Get the x-offset for the text.
  * @return {number} Horizontal text offset.
  * @api
  */
  getOffsetX() {
    return this.offsetX_;
  }

  /**
  * Get the y-offset for the text.
  * @return {number} Vertical text offset.
  * @api
  */
  getOffsetY() {
    return this.offsetY_;
  }

  /**
  * Get the fill style for the text.
  * @return {import("./Fill.js").default} Fill style.
  * @api
  */
  getFill() {
    return this.fill_;
  }

  /**
  * Determine whether the text rotates with the map.
  * @return {boolean|undefined} Rotate with map.
  * @api
  */
  getRotateWithView() {
    return this.rotateWithView_;
  }

  /**
  * Get the text rotation.
  * @return {number|undefined} Rotation.
  * @api
  */
  getRotation() {
    return this.rotation_;
  }

  /**
  * Get the text scale.
  * @return {number|undefined} Scale.
  * @api
  */
  getScale() {
    return this.scale_;
  }

  /**
  * Get the stroke style for the text.
  * @return {import("./Stroke.js").default} Stroke style.
  * @api
  */
  getStroke() {
    return this.stroke_;
  }

  /**
  * Get the text to be rendered.
  * @return {string|undefined} Text.
  * @api
  */
  getText() {
    return this.text_;
  }

  /**
  * Get the text alignment.
  * @return {string|undefined} Text align.
  * @api
  */
  getTextAlign() {
    return this.textAlign_;
  }

  /**
  * Get the text baseline.
  * @return {string|undefined} Text baseline.
  * @api
  */
  getTextBaseline() {
    return this.textBaseline_;
  }

  /**
  * Get the background fill style for the text.
  * @return {import("./Fill.js").default} Fill style.
  * @api
  */
  getBackgroundFill() {
    return this.backgroundFill_;
  }

  /**
  * Get the background stroke style for the text.
  * @return {import("./Stroke.js").default} Stroke style.
  * @api
  */
  getBackgroundStroke() {
    return this.backgroundStroke_;
  }

  /**
  * Get the padding for the text.
  * @return {Array<number>} Padding.
  * @api
  */
  getPadding() {
    return this.padding_;
  }

  /**
  * Set the `overflow` property.
  *
  * @param {boolean} overflow Let text overflow the path that it follows.
  * @api
  */
  setOverflow(overflow) {
    this.overflow_ = overflow;
  }

  /**
  * Set the font.
  *
  * @param {string|undefined} font Font.
  * @api
  */
  setFont(font) {
    this.font_ = font;
  }

  /**
  * Set the maximum angle between adjacent characters.
  *
  * @param {number} maxAngle Angle in radians.
  * @api
  */
  setMaxAngle(maxAngle) {
    this.maxAngle_ = maxAngle;
  }

  /**
  * Set the x offset.
  *
  * @param {number} offsetX Horizontal text offset.
  * @api
  */
  setOffsetX(offsetX) {
    this.offsetX_ = offsetX;
  }

  /**
  * Set the y offset.
  *
  * @param {number} offsetY Vertical text offset.
  * @api
  */
  setOffsetY(offsetY) {
    this.offsetY_ = offsetY;
  }

  /**
  * Set the text placement.
  *
  * @param {import("./TextPlacement.js").default|string} placement Placement.
  * @api
  */
  setPlacement(placement) {
    this.placement_ = placement;
  }

  /**
  * Set the fill.
  *
  * @param {import("./Fill.js").default} fill Fill style.
  * @api
  */
  setFill(fill) {
    this.fill_ = fill;
  }

  /**
  * Set the rotation.
  *
  * @param {number|undefined} rotation Rotation.
  * @api
  */
  setRotation(rotation) {
    this.rotation_ = rotation;
  }

  /**
  * Set the scale.
  *
  * @param {number|undefined} scale Scale.
  * @api
  */
  setScale(scale) {
    this.scale_ = scale;
  }

  /**
  * Set the stroke.
  *
  * @param {import("./Stroke.js").default} stroke Stroke style.
  * @api
  */
  setStroke(stroke) {
    this.stroke_ = stroke;
  }

  /**
  * Set the text.
  *
  * @param {string|undefined} text Text.
  * @api
  */
  setText(text) {
    this.text_ = text;
  }

  /**
  * Set the text alignment.
  *
  * @param {string|undefined} textAlign Text align.
  * @api
  */
  setTextAlign(textAlign) {
    this.textAlign_ = textAlign;
  }

  /**
  * Set the text baseline.
  *
  * @param {string|undefined} textBaseline Text baseline.
  * @api
  */
  setTextBaseline(textBaseline) {
    this.textBaseline_ = textBaseline;
  }

  /**
  * Set the background fill.
  *
  * @param {import("./Fill.js").default} fill Fill style.
  * @api
  */
  setBackgroundFill(fill) {
    this.backgroundFill_ = fill;
  }

  /**
  * Set the background stroke.
  *
  * @param {import("./Stroke.js").default} stroke Stroke style.
  * @api
  */
  setBackgroundStroke(stroke) {
    this.backgroundStroke_ = stroke;
  }

  /**
  * Set the padding (`[top, right, bottom, left]`).
  *
  * @param {!Array<number>} padding Padding.
  * @api
  */
  setPadding(padding) {
    this.padding_ = padding;
  }
}

export default Text;
<commit_msg>Fix comments indentation<commit_after>/**
 * @module ol/style/Text
 */
import Fill from './Fill.js';
import TextPlacement from './TextPlacement.js';

/**
 * The default fill color to use if no fill was set at construction time; a
 * blackish `#333`.
 *
 * @const {string}
 */
const DEFAULT_FILL_COLOR = '#333';

/**
 * @typedef {Object} Options
 * @property {string} [font] Font style as CSS 'font' value, see:
 * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font. Default is '10px sans-serif'
 * @property {number} [maxAngle] When `placement` is set to `'line'`, allow a maximum angle between adjacent characters.
 * The expected value is in radians, and the default is 45° (`Math.PI / 4`).
 * @property {number} [offsetX=0] Horizontal text offset in pixels. A positive will shift the text right.
 * @property {number} [offsetY=0] Vertical text offset in pixels. A positive will shift the text down.
 * @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed
 * the width of the polygon at the label position or the length of the path that it follows.
 * @property {import("./TextPlacement.js").default|string} [placement] Text placement.
 * @property {number} [scale] Scale.
 * @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.
 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
 * @property {string} [text] Text content.
 * @property {string} [textAlign] Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
 * Default is 'center' for `placement: 'point'`. For `placement: 'line'`, the default is to let the renderer choose a
 * placement where `maxAngle` is not exceeded.
 * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
 * 'hanging', 'ideographic'.
 * @property {import("./Fill.js").default} [fill] Fill style. If none is provided, we'll use a dark fill-style (#333).
 * @property {import("./Stroke.js").default} [stroke] Stroke style.
 * @property {import("./Fill.js").default} [backgroundFill] Fill style for the text background when `placement` is
 * `'point'`. Default is no fill.
 * @property {import("./Stroke.js").default} [backgroundStroke] Stroke style for the text background  when `placement`
 * is `'point'`. Default is no stroke.
 * @property {Array<number>} [padding=[0, 0, 0, 0]] Padding in pixels around the text for decluttering and background. The order of
 * values in the array is `[top, right, bottom, left]`.
 */

/**
 * @classdesc
 * Set text style for vector features.
 * @api
 */
class Text {
  /**
   * @param {Options=} opt_options Options.
   */
  constructor(opt_options) {

    const options = opt_options || {};

    /**
     * @private
     * @type {string|undefined}
     */
    this.font_ = options.font;

    /**
     * @private
     * @type {number|undefined}
     */
    this.rotation_ = options.rotation;

    /**
     * @private
     * @type {boolean|undefined}
     */
    this.rotateWithView_ = options.rotateWithView;

    /**
     * @private
     * @type {number|undefined}
     */
    this.scale_ = options.scale;

    /**
     * @private
     * @type {string|undefined}
     */
    this.text_ = options.text;

    /**
     * @private
     * @type {string|undefined}
     */
    this.textAlign_ = options.textAlign;

    /**
     * @private
     * @type {string|undefined}
     */
    this.textBaseline_ = options.textBaseline;

    /**
     * @private
     * @type {import("./Fill.js").default}
     */
    this.fill_ = options.fill !== undefined ? options.fill :
      new Fill({color: DEFAULT_FILL_COLOR});

    /**
     * @private
     * @type {number}
     */
    this.maxAngle_ = options.maxAngle !== undefined ? options.maxAngle : Math.PI / 4;

    /**
     * @private
     * @type {import("./TextPlacement.js").default|string}
     */
    this.placement_ = options.placement !== undefined ? options.placement : TextPlacement.POINT;

    /**
     * @private
     * @type {boolean}
     */
    this.overflow_ = !!options.overflow;

    /**
     * @private
     * @type {import("./Stroke.js").default}
     */
    this.stroke_ = options.stroke !== undefined ? options.stroke : null;

    /**
     * @private
     * @type {number}
     */
    this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;

    /**
     * @private
     * @type {number}
     */
    this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;

    /**
     * @private
     * @type {import("./Fill.js").default}
     */
    this.backgroundFill_ = options.backgroundFill ? options.backgroundFill : null;

    /**
     * @private
     * @type {import("./Stroke.js").default}
     */
    this.backgroundStroke_ = options.backgroundStroke ? options.backgroundStroke : null;

    /**
     * @private
     * @type {Array<number>}
     */
    this.padding_ = options.padding === undefined ? null : options.padding;
  }

  /**
   * Clones the style.
   * @return {Text} The cloned style.
   * @api
   */
  clone() {
    return new Text({
      font: this.getFont(),
      placement: this.getPlacement(),
      maxAngle: this.getMaxAngle(),
      overflow: this.getOverflow(),
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
      scale: this.getScale(),
      text: this.getText(),
      textAlign: this.getTextAlign(),
      textBaseline: this.getTextBaseline(),
      fill: this.getFill() ? this.getFill().clone() : undefined,
      stroke: this.getStroke() ? this.getStroke().clone() : undefined,
      offsetX: this.getOffsetX(),
      offsetY: this.getOffsetY(),
      backgroundFill: this.getBackgroundFill() ? this.getBackgroundFill().clone() : undefined,
      backgroundStroke: this.getBackgroundStroke() ? this.getBackgroundStroke().clone() : undefined
    });
  }

  /**
   * Get the `overflow` configuration.
   * @return {boolean} Let text overflow the length of the path they follow.
   * @api
   */
  getOverflow() {
    return this.overflow_;
  }

  /**
   * Get the font name.
   * @return {string|undefined} Font.
   * @api
   */
  getFont() {
    return this.font_;
  }

  /**
   * Get the maximum angle between adjacent characters.
   * @return {number} Angle in radians.
   * @api
   */
  getMaxAngle() {
    return this.maxAngle_;
  }

  /**
   * Get the label placement.
   * @return {import("./TextPlacement.js").default|string} Text placement.
   * @api
   */
  getPlacement() {
    return this.placement_;
  }

  /**
   * Get the x-offset for the text.
   * @return {number} Horizontal text offset.
   * @api
   */
  getOffsetX() {
    return this.offsetX_;
  }

  /**
   * Get the y-offset for the text.
   * @return {number} Vertical text offset.
   * @api
   */
  getOffsetY() {
    return this.offsetY_;
  }

  /**
   * Get the fill style for the text.
   * @return {import("./Fill.js").default} Fill style.
   * @api
   */
  getFill() {
    return this.fill_;
  }

  /**
   * Determine whether the text rotates with the map.
   * @return {boolean|undefined} Rotate with map.
   * @api
   */
  getRotateWithView() {
    return this.rotateWithView_;
  }

  /**
   * Get the text rotation.
   * @return {number|undefined} Rotation.
   * @api
   */
  getRotation() {
    return this.rotation_;
  }

  /**
   * Get the text scale.
   * @return {number|undefined} Scale.
   * @api
   */
  getScale() {
    return this.scale_;
  }

  /**
   * Get the stroke style for the text.
   * @return {import("./Stroke.js").default} Stroke style.
   * @api
   */
  getStroke() {
    return this.stroke_;
  }

  /**
   * Get the text to be rendered.
   * @return {string|undefined} Text.
   * @api
   */
  getText() {
    return this.text_;
  }

  /**
   * Get the text alignment.
   * @return {string|undefined} Text align.
   * @api
   */
  getTextAlign() {
    return this.textAlign_;
  }

  /**
   * Get the text baseline.
   * @return {string|undefined} Text baseline.
   * @api
   */
  getTextBaseline() {
    return this.textBaseline_;
  }

  /**
   * Get the background fill style for the text.
   * @return {import("./Fill.js").default} Fill style.
   * @api
   */
  getBackgroundFill() {
    return this.backgroundFill_;
  }

  /**
   * Get the background stroke style for the text.
   * @return {import("./Stroke.js").default} Stroke style.
   * @api
   */
  getBackgroundStroke() {
    return this.backgroundStroke_;
  }

  /**
   * Get the padding for the text.
   * @return {Array<number>} Padding.
   * @api
   */
  getPadding() {
    return this.padding_;
  }

  /**
   * Set the `overflow` property.
   *
   * @param {boolean} overflow Let text overflow the path that it follows.
   * @api
   */
  setOverflow(overflow) {
    this.overflow_ = overflow;
  }

  /**
   * Set the font.
   *
   * @param {string|undefined} font Font.
   * @api
   */
  setFont(font) {
    this.font_ = font;
  }

  /**
   * Set the maximum angle between adjacent characters.
   *
   * @param {number} maxAngle Angle in radians.
   * @api
   */
  setMaxAngle(maxAngle) {
    this.maxAngle_ = maxAngle;
  }

  /**
   * Set the x offset.
   *
   * @param {number} offsetX Horizontal text offset.
   * @api
   */
  setOffsetX(offsetX) {
    this.offsetX_ = offsetX;
  }

  /**
   * Set the y offset.
   *
   * @param {number} offsetY Vertical text offset.
   * @api
   */
  setOffsetY(offsetY) {
    this.offsetY_ = offsetY;
  }

  /**
   * Set the text placement.
   *
   * @param {import("./TextPlacement.js").default|string} placement Placement.
   * @api
   */
  setPlacement(placement) {
    this.placement_ = placement;
  }

  /**
   * Set the fill.
   *
   * @param {import("./Fill.js").default} fill Fill style.
   * @api
   */
  setFill(fill) {
    this.fill_ = fill;
  }

  /**
   * Set the rotation.
   *
   * @param {number|undefined} rotation Rotation.
   * @api
   */
  setRotation(rotation) {
    this.rotation_ = rotation;
  }

  /**
   * Set the scale.
   *
   * @param {number|undefined} scale Scale.
   * @api
   */
  setScale(scale) {
    this.scale_ = scale;
  }

  /**
   * Set the stroke.
   *
   * @param {import("./Stroke.js").default} stroke Stroke style.
   * @api
   */
  setStroke(stroke) {
    this.stroke_ = stroke;
  }

  /**
   * Set the text.
   *
   * @param {string|undefined} text Text.
   * @api
   */
  setText(text) {
    this.text_ = text;
  }

  /**
   * Set the text alignment.
   *
   * @param {string|undefined} textAlign Text align.
   * @api
   */
  setTextAlign(textAlign) {
    this.textAlign_ = textAlign;
  }

  /**
   * Set the text baseline.
   *
   * @param {string|undefined} textBaseline Text baseline.
   * @api
   */
  setTextBaseline(textBaseline) {
    this.textBaseline_ = textBaseline;
  }

  /**
   * Set the background fill.
   *
   * @param {import("./Fill.js").default} fill Fill style.
   * @api
   */
  setBackgroundFill(fill) {
    this.backgroundFill_ = fill;
  }

  /**
   * Set the background stroke.
   *
   * @param {import("./Stroke.js").default} stroke Stroke style.
   * @api
   */
  setBackgroundStroke(stroke) {
    this.backgroundStroke_ = stroke;
  }

  /**
   * Set the padding (`[top, right, bottom, left]`).
   *
   * @param {!Array<number>} padding Padding.
   * @api
   */
  setPadding(padding) {
    this.padding_ = padding;
  }
}

export default Text;
<|endoftext|>