<commit_before>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['js/DragDrop/DropTarget',
        './DiagramDesignerWidget.Constants'], function (dropTarget,
                                                        DiagramDesignerWidgetConstants) {

    var DiagramDesignerWidgetDroppable,
        DROP_REGION_MARGIN = 0;

    DiagramDesignerWidgetDroppable = function () {
    };

    DiagramDesignerWidgetDroppable.prototype._initDroppable = function () {
        var self = this;

        this._acceptDroppable = false;

        this.skinParts.$dropRegion = $('<div/>', { "class" : DiagramDesignerWidgetConstants.DROP_REGION_CLASS });

        this.skinParts.$dropRegion.insertBefore(this.skinParts.$itemsContainer);

        dropTarget.makeDroppable(this.skinParts.$dropRegion, {
            'over': function( event, dragInfo ) {
                self._onDroppableOver(event, dragInfo);
            },
            'out': function(/*event, dragInfo*/) {
                self._onDroppableOut(/*event, dragInfo*/);
            },
            'drop': function( event, dragInfo ) {
                self._onBackgroundDrop(event, dragInfo);
            },
            'activate': function(/*event, dragInfo*/) {
                self._onDroppableActivate(/*event, dragInfo*/);
            },
            'deactivate': function(/*event, dragInfo*/) {
                self._onDroppableDeactivate(/*event, dragInfo*/);
            }
        });
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableActivate = function (/*event, dragInfo*/) {
        if (this.mode === this.OPERATING_MODES.DESIGN) {
            this.skinParts.$dropRegion.css({"width": this._containerSize.w - 2 * DROP_REGION_MARGIN,
                "height": this._containerSize.h - 2 * DROP_REGION_MARGIN,
                "top": this._scrollPos.top + DROP_REGION_MARGIN,
                "left": this._scrollPos.left + DROP_REGION_MARGIN });
        }
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableDeactivate = function (/*event, dragInfo*/) {
        this.skinParts.$dropRegion.css({"width": "0px",
            "height": "0px",
            "top": "0px",
            "left": "0px"});
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableOver = function (event, dragInfo) {
        this.logger.debug('_onDroppableOver: ' + JSON.stringify(dragInfo));

        this.selectionManager.clear();

        this._doAcceptDroppable(this.onBackgroundDroppableAccept(event, dragInfo), true);
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableOut = function (/*event, dragInfo*/) {
        this._doAcceptDroppable(false, false);
    };

    DiagramDesignerWidgetDroppable.prototype._onBackgroundDrop = function (event, dragInfo) {
        var mPos = this.getAdjustedMousePos(event),
            posX = mPos.mX,
            posY = mPos.mY;

        this.logger.debug('_onBackgroundDrop: ' + JSON.stringify(dragInfo));

        if (this._acceptDroppable === true) {
            this.onBackgroundDrop(event, dragInfo, { "x": posX, "y": posY });
        }

        this._doAcceptDroppable(false, false);
    };

    DiagramDesignerWidgetDroppable.prototype._doAcceptDroppable = function (accept, uiFeedback) {
        this.skinParts.$dropRegion.removeClass(DiagramDesignerWidgetConstants.DROP_REGION_ACCEPT_DROPPABLE_CLASS);
        this.skinParts.$dropRegion.removeClass(DiagramDesignerWidgetConstants.DROP_REGION_REJECT_DROPPABLE_CLASS);

        if (accept === true) {
            this._acceptDroppable = true;
            if (uiFeedback) {
                this.skinParts.$dropRegion.addClass(DiagramDesignerWidgetConstants.DROP_REGION_ACCEPT_DROPPABLE_CLASS);
            }
        } else {
            this._acceptDroppable = false;
            if (uiFeedback) {
                this.skinParts.$dropRegion.addClass(DiagramDesignerWidgetConstants.DROP_REGION_REJECT_DROPPABLE_CLASS);
            }
        }
    };

    DiagramDesignerWidgetDroppable.prototype.onBackgroundDroppableAccept = function (event, dragInfo) {
        this.logger.warning("DiagramDesignerWidget.prototype.onBackgroundDroppableAccept(event, dragInfo) not overridden in controller!!! dragInfo:" + JSON.stringify(dragInfo));
        return false;
    };

    DiagramDesignerWidgetDroppable.prototype.onBackgroundDrop = function (event, dragInfo, position) {
        this.logger.warning("DiagramDesignerWidget.prototype.onBackgroundDrop(event, dragInfo) not overridden in controller!!! dragInfo:" + JSON.stringify(dragInfo) + " , position: '" + JSON.stringify(position) + "'");
    };

    DiagramDesignerWidgetDroppable.prototype._enableDroppable = function (enabled) {
        if (this.skinParts.$dropRegion) {
            if (enabled === true) {
                dropTarget.enableDroppable(this.skinParts.$dropRegion, true);
                this.skinParts.$dropRegion.droppable("enable");
                if (this._savedAcceptDroppable !== undefined) {
                    this._doAcceptDroppable(this._savedAcceptDroppable, false);
                    this._savedAcceptDroppable = undefined;
                }
            } else {
                dropTarget.enableDroppable(this.skinParts.$dropRegion, false);
                this._savedAcceptDroppable = this._acceptDroppable;
                this._doAcceptDroppable(false, false);
            }
        }
    };

    return DiagramDesignerWidgetDroppable;
});
<commit_msg>bugfix with droppable enable/disable<commit_after>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['js/DragDrop/DropTarget',
        './DiagramDesignerWidget.Constants'], function (dropTarget,
                                                        DiagramDesignerWidgetConstants) {

    var DiagramDesignerWidgetDroppable,
        DROP_REGION_MARGIN = 0;

    DiagramDesignerWidgetDroppable = function () {
    };

    DiagramDesignerWidgetDroppable.prototype._initDroppable = function () {
        var self = this;

        this._acceptDroppable = false;

        this.skinParts.$dropRegion = $('<div/>', { "class" : DiagramDesignerWidgetConstants.DROP_REGION_CLASS });

        this.skinParts.$dropRegion.insertBefore(this.skinParts.$itemsContainer);

        dropTarget.makeDroppable(this.skinParts.$dropRegion, {
            'over': function( event, dragInfo ) {
                self._onDroppableOver(event, dragInfo);
            },
            'out': function(/*event, dragInfo*/) {
                self._onDroppableOut(/*event, dragInfo*/);
            },
            'drop': function( event, dragInfo ) {
                self._onBackgroundDrop(event, dragInfo);
            },
            'activate': function(/*event, dragInfo*/) {
                self._onDroppableActivate(/*event, dragInfo*/);
            },
            'deactivate': function(/*event, dragInfo*/) {
                self._onDroppableDeactivate(/*event, dragInfo*/);
            }
        });
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableActivate = function (/*event, dragInfo*/) {
        if (this.mode === this.OPERATING_MODES.DESIGN) {
            this.skinParts.$dropRegion.css({"width": this._containerSize.w - 2 * DROP_REGION_MARGIN,
                "height": this._containerSize.h - 2 * DROP_REGION_MARGIN,
                "top": this._scrollPos.top + DROP_REGION_MARGIN,
                "left": this._scrollPos.left + DROP_REGION_MARGIN });
        }
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableDeactivate = function (/*event, dragInfo*/) {
        this.skinParts.$dropRegion.css({"width": "0px",
            "height": "0px",
            "top": "0px",
            "left": "0px"});
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableOver = function (event, dragInfo) {
        this.logger.debug('_onDroppableOver: ' + JSON.stringify(dragInfo));

        this.selectionManager.clear();

        this._doAcceptDroppable(this.onBackgroundDroppableAccept(event, dragInfo), true);
    };

    DiagramDesignerWidgetDroppable.prototype._onDroppableOut = function (/*event, dragInfo*/) {
        this._doAcceptDroppable(false, false);
    };

    DiagramDesignerWidgetDroppable.prototype._onBackgroundDrop = function (event, dragInfo) {
        var mPos = this.getAdjustedMousePos(event),
            posX = mPos.mX,
            posY = mPos.mY;

        this.logger.debug('_onBackgroundDrop: ' + JSON.stringify(dragInfo));

        if (this._acceptDroppable === true) {
            this.onBackgroundDrop(event, dragInfo, { "x": posX, "y": posY });
        }

        this._doAcceptDroppable(false, false);
    };

    DiagramDesignerWidgetDroppable.prototype._doAcceptDroppable = function (accept, uiFeedback) {
        this.skinParts.$dropRegion.removeClass(DiagramDesignerWidgetConstants.DROP_REGION_ACCEPT_DROPPABLE_CLASS);
        this.skinParts.$dropRegion.removeClass(DiagramDesignerWidgetConstants.DROP_REGION_REJECT_DROPPABLE_CLASS);

        if (accept === true) {
            this._acceptDroppable = true;
            if (uiFeedback) {
                this.skinParts.$dropRegion.addClass(DiagramDesignerWidgetConstants.DROP_REGION_ACCEPT_DROPPABLE_CLASS);
            }
        } else {
            this._acceptDroppable = false;
            if (uiFeedback) {
                this.skinParts.$dropRegion.addClass(DiagramDesignerWidgetConstants.DROP_REGION_REJECT_DROPPABLE_CLASS);
            }
        }
    };

    DiagramDesignerWidgetDroppable.prototype.onBackgroundDroppableAccept = function (event, dragInfo) {
        this.logger.warning("DiagramDesignerWidget.prototype.onBackgroundDroppableAccept(event, dragInfo) not overridden in controller!!! dragInfo:" + JSON.stringify(dragInfo));
        return false;
    };

    DiagramDesignerWidgetDroppable.prototype.onBackgroundDrop = function (event, dragInfo, position) {
        this.logger.warning("DiagramDesignerWidget.prototype.onBackgroundDrop(event, dragInfo) not overridden in controller!!! dragInfo:" + JSON.stringify(dragInfo) + " , position: '" + JSON.stringify(position) + "'");
    };

    DiagramDesignerWidgetDroppable.prototype._enableDroppable = function (enabled) {
        if (this.skinParts.$dropRegion) {
            if (enabled === true) {
                dropTarget.enableDroppable(this.skinParts.$dropRegion, true);
                if (this._savedAcceptDroppable !== undefined) {
                    this._doAcceptDroppable(this._savedAcceptDroppable, true);
                    this._savedAcceptDroppable = undefined;
                }
            } else {
                dropTarget.enableDroppable(this.skinParts.$dropRegion, false);
                this._savedAcceptDroppable = this._acceptDroppable;
                this._doAcceptDroppable(false, false);
            }
        }
    };

    return DiagramDesignerWidgetDroppable;
});
<|endoftext|>


<commit_before>// @flow
import $ from 'jquery';
import Backbone from 'backbone';
import _ from 'lodash';
import setupOnce from './setup_once';
import ee from '../shared/pub_sub';
import GlobalEvents from '../shared/global_events';
import Clipboard from 'clipboard';

const SharesEditor = Backbone.View.extend({
  events: {
    'ajax:success form.shares-editor__delete-variant': 'deleteVariant',
    'click .shares-editor__toggle-edit': 'toggleEditor',
    'click .shares-editor__new-type-toggle .btn': 'switchVariantForm',
    'click .shares-editor__view-toggle .btn': 'switchView',
    'ajax:success form.shares-editor__new-form': 'clearFormAndConformView',
  },

  globalEvents: {
    'page:saved': 'updateSummaryRows',
    'page:errors': 'openEditorForErrors',
    'image:success': 'addImageSelectors',
    'image:destroyed': 'pruneImageSelectors',
  },

  initialize: function() {
    this.view = 'summary';
    GlobalEvents.bindEvents(this);
  },

  deleteVariant: function(e) {
    const $target = $(e.target);
    const $summary_row = $target.parents('.shares-editor__summary-row');
    const $stats_row = $summary_row.next('.shares-editor__stats-row');
    const $edit_row = $stats_row.next('.shares-editor__edit-row');
    $summary_row.remove();
    $stats_row.remove();
    $edit_row.remove();
  },

  editRow: function($row) {
    if (!$row.hasClass('shares-editor__stats-row')) {
      $row = $row.next('.shares-editor__stats-row');
    }
    return $row.next('.shares-editor__edit-row');
  },

  toggleEditor: function(e) {
    let $target = this.$(e.target);
    $target = $target.is('tr') ? $target : $target.parents('tr');
    const $btn = $target.find('.shares-editor__toggle-edit');
    this.editRow($target).toggleClass('hidden-closed');
    $btn.text($btn.text() == 'Edit' ? 'Done' : 'Edit');
  },

  openEditor: function($edit_row) {
    const $prev = $edit_row.prev('.shares-editor__summary-row');
    const $btn = $prev.find('.shares-editor__toggle-edit');
    $btn.text('Done');
    $edit_row.removeClass('hidden-closed');
  },

  switchVariantForm: function(e) {
    const $target = this.$(e.target);
    const desired = $target.data('state');
    if (desired) {
      this.$('.shares-editor__new-type-toggle .btn').removeClass('btn-primary');
      $target.addClass('btn-primary');
      this.$('.shares-editor__new-form').addClass('hidden-closed');
      this.$(`.shares-editor__new-form[data-share="${desired}"]`).removeClass(
        'hidden-closed'
      );
    }
  },

  switchView: function(e) {
    const $target = this.$(e.target);
    const desired = $target.data('state');
    if (desired) {
      this.setView(desired);
    }
  },

  setView: function(desired) {
    this.view = desired;
    this.$('.shares-editor__view-toggle .btn').removeClass('btn-primary');
    this.$(`[data-state="${desired}"]`).addClass('btn-primary');
    if (desired === 'summary') {
      this.$('.shares-editor__summary-row').removeClass('hidden-closed');
      this.$('.shares-editor__stats-row').addClass('hidden-closed');
      this.$('.shares-editor__stats-heading').addClass('hidden-closed');
    } else {
      this.$('.shares-editor__summary-row').addClass('hidden-closed');
      this.$('.shares-editor__stats-row').removeClass('hidden-closed');
      this.$('.shares-editor__stats-heading').removeClass('hidden-closed');
    }
  },

  clearFormAndConformView: function(e) {
    $(e.target)
      .find('input[type="text"], textarea')
      .val('');
    this.setView(this.view); // make new rows conform
  },

  openEditorForErrors: function() {
    this.openEditor(this.$('.has-error').parents('.shares-editor__edit-row'));
  },

  updateSummaryRows: function(e, data) {
    // this only updates existing shares. new ones are appended by
    // code in view/share/shares/create.js.erb, using rails UJS
    $.get(`/api/pages/${data.id}/share-rows`, rows => {
      _.each(rows, row => {
        let $row = $(row.html);
        const $original = $(`#${$row.prop('id')}`);
        if ($original.hasClass('hidden-closed')) {
          $row.addClass('hidden-closed');
        }
        $row = $original.replaceWith($row);
        $row = $(`#${$row.prop('id')}`);
        if (!this.editRow($row).hasClass('hidden-closed')) {
          $row.find('.shares-editor__toggle-edit').text('Done');
        }
      });
    });
  },

  addImageSelectors: function(e, file, id, html) {
    const newOption = `<option value='${id}'>${file.name}</option>`;
    this.$('.shares-editor__image-selector').append(newOption);
  },

  pruneImageSelectors: function(id) {
    this.$(`option[value="${id}"]`).remove();
  },
});

ee.on('shares:edit', function() {
  setupOnce('.shares-editor', SharesEditor);
});

$(function() {
  new Clipboard('.share-copy-url');

  $('.shares-editor__existing').on(
    'click',
    '.share-copy-url',
    (e: JQueryEventObject) => {
      e.preventDefault();
    }
  );
});
<commit_msg>Fix shares_editor.js event handler<commit_after>// @flow
import $ from 'jquery';
import Backbone from 'backbone';
import _ from 'lodash';
import setupOnce from './setup_once';
import ee from '../shared/pub_sub';
import GlobalEvents from '../shared/global_events';
import Clipboard from 'clipboard';

const SharesEditor = Backbone.View.extend({
  events: {
    'ajax:success form.shares-editor__delete-variant': 'deleteVariant',
    'click .shares-editor__toggle-edit': 'toggleEditor',
    'click .shares-editor__new-type-toggle .btn': 'switchVariantForm',
    'click .shares-editor__view-toggle .btn': 'switchView',
    'ajax:success form.shares-editor__new-form': 'clearFormAndConformView',
  },

  globalEvents: {
    'page:saved': 'updateSummaryRows',
    'page:errors': 'openEditorForErrors',
    'image:success': 'addImageSelectors',
    'image:destroyed': 'pruneImageSelectors',
  },

  initialize: function() {
    this.view = 'summary';
    GlobalEvents.bindEvents(this);
  },

  deleteVariant: function(e) {
    const $target = $(e.target);
    const $summary_row = $target.parents('.shares-editor__summary-row');
    const $stats_row = $summary_row.next('.shares-editor__stats-row');
    const $edit_row = $stats_row.next('.shares-editor__edit-row');
    $summary_row.remove();
    $stats_row.remove();
    $edit_row.remove();
  },

  editRow: function($row) {
    if (!$row.hasClass('shares-editor__stats-row')) {
      $row = $row.next('.shares-editor__stats-row');
    }
    return $row.next('.shares-editor__edit-row');
  },

  toggleEditor: function(e) {
    let $target = this.$(e.target);
    $target = $target.is('tr') ? $target : $target.parents('tr');
    const $btn = $target.find('.shares-editor__toggle-edit');
    this.editRow($target).toggleClass('hidden-closed');
    $btn.text($btn.text() == 'Edit' ? 'Done' : 'Edit');
  },

  openEditor: function($edit_row) {
    const $prev = $edit_row.prev('.shares-editor__summary-row');
    const $btn = $prev.find('.shares-editor__toggle-edit');
    $btn.text('Done');
    $edit_row.removeClass('hidden-closed');
  },

  switchVariantForm: function(e) {
    const $target = this.$(e.target);
    const desired = $target.data('state');
    if (desired) {
      this.$('.shares-editor__new-type-toggle .btn').removeClass('btn-primary');
      $target.addClass('btn-primary');
      this.$('.shares-editor__new-form').addClass('hidden-closed');
      this.$(`.shares-editor__new-form[data-share="${desired}"]`).removeClass(
        'hidden-closed'
      );
    }
  },

  switchView: function(e) {
    const $target = this.$(e.target);
    const desired = $target.data('state');
    if (desired) {
      this.setView(desired);
    }
  },

  setView: function(desired) {
    this.view = desired;
    this.$('.shares-editor__view-toggle .btn').removeClass('btn-primary');
    this.$(`[data-state="${desired}"]`).addClass('btn-primary');
    if (desired === 'summary') {
      this.$('.shares-editor__summary-row').removeClass('hidden-closed');
      this.$('.shares-editor__stats-row').addClass('hidden-closed');
      this.$('.shares-editor__stats-heading').addClass('hidden-closed');
    } else {
      this.$('.shares-editor__summary-row').addClass('hidden-closed');
      this.$('.shares-editor__stats-row').removeClass('hidden-closed');
      this.$('.shares-editor__stats-heading').removeClass('hidden-closed');
    }
  },

  clearFormAndConformView: function(e) {
    $(e.target)
      .find('input[type="text"], textarea')
      .val('');
    this.setView(this.view); // make new rows conform
  },

  openEditorForErrors: function() {
    this.openEditor(this.$('.has-error').parents('.shares-editor__edit-row'));
  },

  updateSummaryRows: function(data) {
    // this only updates existing shares. new ones are appended by
    // code in view/share/shares/create.js.erb, using rails UJS
    $.get(`/api/pages/${data.id}/share-rows`, rows => {
      _.each(rows, row => {
        let $row = $(row.html);
        const $original = $(`#${$row.prop('id')}`);
        if ($original.hasClass('hidden-closed')) {
          $row.addClass('hidden-closed');
        }
        $row = $original.replaceWith($row);
        $row = $(`#${$row.prop('id')}`);
        if (!this.editRow($row).hasClass('hidden-closed')) {
          $row.find('.shares-editor__toggle-edit').text('Done');
        }
      });
    });
  },

  addImageSelectors: function(file, id, html) {
    const newOption = `<option value='${id}'>${file.name}</option>`;
    this.$('.shares-editor__image-selector').append(newOption);
  },

  pruneImageSelectors: function(id) {
    this.$(`option[value="${id}"]`).remove();
  },
});

ee.on('shares:edit', function() {
  setupOnce('.shares-editor', SharesEditor);
});

$(function() {
  new Clipboard('.share-copy-url');

  $('.shares-editor__existing').on(
    'click',
    '.share-copy-url',
    (e: JQueryEventObject) => {
      e.preventDefault();
    }
  );
});
<|endoftext|>


<commit_before>import _ from "../helpers";
import { HTML } from "../constants";
import { $Element } from "../types";

/* es6-transpiler has-iterators:false, has-generators: false */

var reSpace = /[\n\t\r]/g;

function makeClassesMethod(nativeMethodName, fallback) {
    var methodName = nativeMethodName === "contains" ? "hasClass" : nativeMethodName + "Class";
    // use fallback if browser does not support classList API
    if (!HTML.classList) nativeMethodName = null;

    if (methodName === "hasClass" || methodName === "toggleClass") {
        return function(className, force) {
            var node = this[0];

            if (node) {
                if (typeof force === "boolean") {
                    this[force ? "addClass" : "removeClass"](className);

                    return force;
                }

                if (nativeMethodName) {
                    return node.classList[nativeMethodName](className);
                } else {
                    return fallback(node, className);
                }
            }
        };
    } else {
        return function(className) {
            var node = this[0],
                args = arguments;

            if (node) {
                for (className of args) {
                    if (nativeMethodName) {
                        node.classList[nativeMethodName](className);
                    } else {
                        fallback(node, className);
                    }
                }
            }

            return this;
        };
    }
}

/**
 * Check if element contains class name
 * @memberof! $Element#
 * @alias $Element#hasClass
 * @param  {String}   className class name
 * @return {Boolean}  true if the element contains the class
 * @function
 */
$Element.prototype.hasClass = makeClassesMethod("contains", function(node, className) {
    return (" " + node.className + " ").replace(reSpace, " ").indexOf(" " + className + " ") >= 0;
});

/**
 * Add class(es) to element
 * @memberof! $Element#
 * @alias $Element#addClass
 * @param  {...String} classNames class name(s)
 * @return {$Element}
 * @function
 */
$Element.prototype.addClass = makeClassesMethod("add", function(node, className) {
    if (!this.hasClass(className)) node.className += " " + className;
});

/**
 * Remove class(es) from element
 * @memberof! $Element#
 * @alias $Element#removeClass
 * @param  {...String} classNames class name(s)
 * @return {$Element}
 * @function
 */
$Element.prototype.removeClass = makeClassesMethod("remove", function(node, className) {
    className = (" " + node.className + " ").replace(reSpace, " ").replace(" " + className + " ", " ");

    node.className = className.trim();
});

/**
 * Toggle a class on element
 * @memberof! $Element#
 * @alias $Element#toggleClass
 * @param  {String}  className class name(s)
 * @param  {Boolean} [force] if true then adds the className; if false - removes it
 * @return {Boolean} true if the className is now present, and false otherwise.
 * @function
 */
$Element.prototype.toggleClass = makeClassesMethod("toggle", function(node, className) {
    var oldClassName = node.className;

    this.addClass(className);

    if (oldClassName !== node.className) return true;

    this.removeClass(className);

    return false;
});
<commit_msg>throw errors id className is not a string<commit_after>import { MethodError } from "../errors";
import { HTML } from "../constants";
import { $Element } from "../types";

/* es6-transpiler has-iterators:false, has-generators: false */

var reSpace = /[\n\t\r]/g;

function makeClassesMethod(nativeMethodName, fallback) {
    var methodName = nativeMethodName === "contains" ? "hasClass" : nativeMethodName + "Class";
    // use fallback if browser does not support classList API
    if (!HTML.classList) nativeMethodName = null;

    if (methodName === "hasClass" || methodName === "toggleClass") {
        return function(className, force) {
            var node = this[0];

            if (node) {
                if (typeof force === "boolean" && methodName === "toggleClass") {
                    this[force ? "addClass" : "removeClass"](className);

                    return force;
                }

                if (typeof className !== "string") throw new MethodError(methodName);

                if (nativeMethodName) {
                    return node.classList[nativeMethodName](className);
                } else {
                    return fallback(node, className);
                }
            }
        };
    } else {
        return function(className) {
            var node = this[0],
                args = arguments;

            if (node) {
                for (className of args) {
                    if (typeof className !== "string") throw new MethodError(methodName);

                    if (nativeMethodName) {
                        node.classList[nativeMethodName](className);
                    } else {
                        fallback(node, className);
                    }
                }
            }

            return this;
        };
    }
}

/**
 * Check if element contains class name
 * @memberof! $Element#
 * @alias $Element#hasClass
 * @param  {String}   className class name
 * @return {Boolean}  true if the element contains the class
 * @function
 */
$Element.prototype.hasClass = makeClassesMethod("contains", function(node, className) {
    return (" " + node.className + " ").replace(reSpace, " ").indexOf(" " + className + " ") >= 0;
});

/**
 * Add class(es) to element
 * @memberof! $Element#
 * @alias $Element#addClass
 * @param  {...String} classNames class name(s)
 * @return {$Element}
 * @function
 */
$Element.prototype.addClass = makeClassesMethod("add", function(node, className) {
    if (!this.hasClass(className)) node.className += " " + className;
});

/**
 * Remove class(es) from element
 * @memberof! $Element#
 * @alias $Element#removeClass
 * @param  {...String} classNames class name(s)
 * @return {$Element}
 * @function
 */
$Element.prototype.removeClass = makeClassesMethod("remove", function(node, className) {
    className = (" " + node.className + " ").replace(reSpace, " ").replace(" " + className + " ", " ");

    node.className = className.trim();
});

/**
 * Toggle a class on element
 * @memberof! $Element#
 * @alias $Element#toggleClass
 * @param  {String}  className class name(s)
 * @param  {Boolean} [force] if true then adds the className; if false - removes it
 * @return {Boolean} true if the className is now present, and false otherwise.
 * @function
 */
$Element.prototype.toggleClass = makeClassesMethod("toggle", function(node, className) {
    var oldClassName = node.className;

    this.addClass(className);

    if (oldClassName !== node.className) return true;

    this.removeClass(className);

    return false;
});
<|endoftext|>


<commit_before>var IS_PURE = require('../internals/is-pure');
var $ = require('../internals/export');
var global = require('../internals/global');
var getBuiltin = require('../internals/get-built-in');
var uncurryThis = require('../internals/function-uncurry-this');
var fails = require('../internals/fails');
var uid = require('../internals/uid');
var isCallable = require('../internals/is-callable');
var isConstructor = require('../internals/is-constructor');
var isObject = require('../internals/is-object');
var isSymbol = require('../internals/is-symbol');
var iterate = require('../internals/iterate');
var anObject = require('../internals/an-object');
var classof = require('../internals/classof');
var hasOwn = require('../internals/has-own-property');
var createProperty = require('../internals/create-property');
var createNonEnumerableProperty = require('../internals/create-non-enumerable-property');
var lengthOfArrayLike = require('../internals/length-of-array-like');
var regExpFlags = require('../internals/regexp-flags');
var ERROR_STACK_INSTALLABLE = require('../internals/error-stack-installable');

var Object = global.Object;
var Date = global.Date;
var Error = global.Error;
var EvalError = global.EvalError;
var RangeError = global.RangeError;
var ReferenceError = global.ReferenceError;
var SyntaxError = global.SyntaxError;
var TypeError = global.TypeError;
var URIError = global.URIError;
var PerformanceMark = global.PerformanceMark;
var WebAssembly = global.WebAssembly;
var CompileError = WebAssembly && WebAssembly.CompileError || Error;
var LinkError = WebAssembly && WebAssembly.LinkError || Error;
var RuntimeError = WebAssembly && WebAssembly.RuntimeError || Error;
var DOMException = getBuiltin('DOMException');
var Set = getBuiltin('Set');
var Map = getBuiltin('Map');
var MapPrototype = Map.prototype;
var mapHas = uncurryThis(MapPrototype.has);
var mapGet = uncurryThis(MapPrototype.get);
var mapSet = uncurryThis(MapPrototype.set);
var setAdd = uncurryThis(Set.prototype.add);
var objectKeys = getBuiltin('Object', 'keys');
var push = uncurryThis([].push);
var bolleanValueOf = uncurryThis(true.valueOf);
var numberValueOf = uncurryThis(1.0.valueOf);
var stringValueOf = uncurryThis(''.valueOf);
var getFlags = uncurryThis(regExpFlags);
var getTime = uncurryThis(Date.prototype.getTime);
var PERFORMANCE_MARK = uid('structuredClone');
var DATA_CLONE_ERROR = 'DataCloneError';
var TRANSFERRING = 'Transferring';

var checkBasicSemantic = function (structuredCloneImplementation) {
  return !fails(function () {
    var set1 = new global.Set([7]);
    var set2 = structuredCloneImplementation(set1);
    var number = structuredCloneImplementation(Object(7));
    return set2 == set1 || !set2.has(7) || typeof number != 'object' || number != 7;
  }) && structuredCloneImplementation;
};

// https://github.com/whatwg/html/pull/5749
var checkNewErrorsSemantic = function (structuredCloneImplementation) {
  return !fails(function () {
    var test = structuredCloneImplementation(new global.AggregateError([1], PERFORMANCE_MARK, { cause: 3 }));
    return test.name != 'AggregateError' || test.errors[0] != 1 || test.message != PERFORMANCE_MARK || test.cause != 3;
  }) && structuredCloneImplementation;
};

// FF94+, Safari TP134+, Chrome Canary 98+, NodeJS 17.0+, Deno 1.13+
// current FF and Safari implementations can't clone errors
// https://bugzilla.mozilla.org/show_bug.cgi?id=1556604
// no one of current implementations supports new (html/5749) error cloning semantic
var nativeStructuredClone = global.structuredClone;

var FORCED_REPLACEMENT = IS_PURE || !checkNewErrorsSemantic(nativeStructuredClone);

// Chrome 82+, Safari 14.1+, Deno 1.11+
// Chrome 78-81 implementation swaps `.name` and `.message` of cloned `DOMException`
// Safari 14.1 implementation doesn't clone some `RegExp` flags, so requires a workaround
// current Safari implementation can't clone errors
// Deno 1.2-1.10 implementations too naive
// NodeJS 16.0+ does not have `PerformanceMark` constructor, structured cloning implementation
//   from `performance.mark` is too naive and can't clone, for example, `RegExp` or some boxed primitives
//   https://github.com/nodejs/node/issues/40840
// no one of current implementations supports new (html/5749) error cloning semantic
var structuredCloneFromMark = !nativeStructuredClone && checkBasicSemantic(function (value) {
  return new PerformanceMark(PERFORMANCE_MARK, { detail: value }).detail;
});

var nativeRestrictedStructuredClone = checkBasicSemantic(nativeStructuredClone) || structuredCloneFromMark;

var throwUncloneable = function (type) {
  throw new DOMException('Uncloneable type: ' + type, DATA_CLONE_ERROR);
};

var throwUnpolyfillable = function (type, kind) {
  throw new DOMException((kind || 'Cloning') + ' of ' + type + ' cannot be properly polyfilled in this engine', DATA_CLONE_ERROR);
};

var structuredCloneInternal = function (value, map) {
  if (isSymbol(value)) throwUncloneable('Symbol');
  if (!isObject(value)) return value;
  // effectively preserves circular references
  if (map) {
    if (mapHas(map, value)) return mapGet(map, value);
  } else map = new Map();

  var type = classof(value);
  var deep = false;
  var C, name, cloned, dataTransfer, i, length, keys, key, source, target;

  switch (type) {
    case 'Array':
      cloned = [];
      deep = true;
      break;
    case 'Object':
      cloned = {};
      deep = true;
      break;
    case 'Map':
      cloned = new Map();
      deep = true;
      break;
    case 'Set':
      cloned = new Set();
      deep = true;
      break;
    case 'RegExp':
      // in this block because of a Safari 14.1 bug
      // old FF does not clone regexes passed to the constructor, so get the source and flags directly
      cloned = new RegExp(value.source, 'flags' in value ? value.flags : getFlags(value));
      break;
    case 'Error':
      name = value.name;
      switch (name) {
        case 'AggregateError':
          cloned = getBuiltin('AggregateError')([]);
          break;
        case 'EvalError':
          cloned = EvalError();
          break;
        case 'RangeError':
          cloned = RangeError();
          break;
        case 'ReferenceError':
          cloned = ReferenceError();
          break;
        case 'SyntaxError':
          cloned = SyntaxError();
          break;
        case 'TypeError':
          cloned = TypeError();
          break;
        case 'URIError':
          cloned = URIError();
          break;
        case 'CompileError':
          cloned = CompileError();
          break;
        case 'LinkError':
          cloned = LinkError();
          break;
        case 'RuntimeError':
          cloned = RuntimeError();
          break;
        default:
          cloned = Error();
      }
      deep = true;
      break;
    case 'DOMException':
      cloned = new DOMException(value.message, value.name);
      deep = true;
      break;
    case 'DataView':
    case 'Int8Array':
    case 'Uint8Array':
    case 'Uint8ClampedArray':
    case 'Int16Array':
    case 'Uint16Array':
    case 'Int32Array':
    case 'Uint32Array':
    case 'Float32Array':
    case 'Float64Array':
    case 'BigInt64Array':
    case 'BigUint64Array':
      C = global[type];
      if (!isConstructor(C)) throwUnpolyfillable(type);
      cloned = new C(
        // this is safe, since arraybuffer cannot have circular references
        structuredCloneInternal(value.buffer, map),
        value.byteOffset,
        type === 'DataView' ? value.byteLength : value.length
      );
      break;
    case 'DOMQuad':
      C = global.DOMQuad;
      if (isConstructor(C)) {
        cloned = new C(
          structuredCloneInternal(value.p1, map),
          structuredCloneInternal(value.p2, map),
          structuredCloneInternal(value.p3, map),
          structuredCloneInternal(value.p4, map)
        );
      } else if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else throwUnpolyfillable(type);
      break;
    case 'FileList':
      C = global.DataTransfer;
      if (isConstructor(C)) {
        dataTransfer = new C();
        for (i = 0, length = lengthOfArrayLike(value); i < length; i++) {
          dataTransfer.items.add(structuredCloneInternal(value[i], map));
        }
        cloned = dataTransfer.files;
      } else if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else throwUnpolyfillable(type);
      break;
    case 'ImageData':
      // Safari 9 ImageData is a constructor, but typeof ImageData is 'object'
      try {
        cloned = new ImageData(
          structuredCloneInternal(value.data, map),
          value.width,
          value.height,
          { colorSpace: value.colorSpace }
        );
      } catch (error) {
        if (nativeRestrictedStructuredClone) {
          cloned = nativeRestrictedStructuredClone(value);
        } else throwUnpolyfillable(type);
      } break;
    default:
      if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else switch (type) {
        case 'BigInt':
          // can be a 3rd party polyfill
          cloned = Object(value.valueOf());
          break;
        case 'Boolean':
          cloned = Object(bolleanValueOf(value));
          break;
        case 'Number':
          cloned = Object(numberValueOf(value));
          break;
        case 'String':
          cloned = Object(stringValueOf(value));
          break;
        case 'Date':
          cloned = new Date(getTime(value));
          break;
        case 'ArrayBuffer':
          // detached buffers throws in `DataView` and `.slice`
          try {
            // `ArrayBuffer#slice` is not available in IE10
            if (typeof value.slice == 'function') {
              cloned = value.slice(0);
            } else {
              length = value.byteLength;
              cloned = new ArrayBuffer(length);
              // eslint-disable-next-line es/no-typed-arrays -- ok
              source = new DataView(value);
              // eslint-disable-next-line es/no-typed-arrays -- ok
              target = new DataView(cloned);
              for (i = 0; i < length; i++) {
                target.setUint8(i, source.getUint8(i));
              }
            }
          } catch (error) {
            throw new DOMException('ArrayBuffer is deatched', DATA_CLONE_ERROR);
          } break;
        case 'SharedArrayBuffer':
          // SharedArrayBuffer should use shared memory, we can't polyfill it, so return the original
          cloned = value;
          break;
        case 'Blob':
          try {
            cloned = value.slice(0, value.size, value.type);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMPoint':
        case 'DOMPointReadOnly':
          C = global[type];
          try {
            cloned = C.fromPoint
              ? C.fromPoint(value)
              : new C(value.x, value.y, value.z, value.w);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMRect':
        case 'DOMRectReadOnly':
          C = global[type];
          try {
            cloned = C.fromRect
              ? C.fromRect(value)
              : new C(value.x, value.y, value.width, value.height);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMMatrix':
        case 'DOMMatrixReadOnly':
          C = global[type];
          try {
            cloned = C.fromMatrix
              ? C.fromMatrix(value)
              : new C(value);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'AudioData':
        case 'VideoFrame':
          if (!isCallable(value.clone)) throwUnpolyfillable(type);
          try {
            cloned = value.clone();
          } catch (error) {
            throwUncloneable(type);
          } break;
        case 'File':
          try {
            cloned = new File([value], value.name, value);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'CryptoKey':
        case 'GPUCompilationMessage':
        case 'GPUCompilationInfo':
        case 'ImageBitmap':
        case 'RTCCertificate':
        case 'WebAssembly.Module':
          throwUnpolyfillable(type);
          // break omitted
        default:
          throwUncloneable(type);
      }
  }

  mapSet(map, value, cloned);

  if (deep) switch (type) {
    case 'Array':
    case 'Object':
      keys = objectKeys(value);
      for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) {
        key = keys[i];
        createProperty(cloned, key, structuredCloneInternal(value[key], map));
      } break;
    case 'Map':
      value.forEach(function (v, k) {
        mapSet(cloned, structuredCloneInternal(k, map), structuredCloneInternal(v, map));
      });
      break;
    case 'Set':
      value.forEach(function (v) {
        setAdd(cloned, structuredCloneInternal(v, map));
      });
      break;
    case 'Error':
      createNonEnumerableProperty(cloned, 'message', structuredCloneInternal(value.message, map));
      if (hasOwn(value, 'cause')) {
        createNonEnumerableProperty(cloned, 'cause', structuredCloneInternal(value.cause, map));
      }
      if (name == 'AggregateError') {
        cloned.errors = structuredCloneInternal(value.errors, map);
      } // break omitted
    case 'DOMException':
      if (ERROR_STACK_INSTALLABLE) {
        createNonEnumerableProperty(cloned, 'stack', structuredCloneInternal(value.stack, map));
      }
  }

  return cloned;
};

var PROPER_TRANSFER = nativeStructuredClone && !fails(function () {
  var buffer = new ArrayBuffer(8);
  var clone = nativeStructuredClone(buffer, { transfer: [buffer] });
  return buffer.byteLength != 0 || clone.byteLength != 8;
});

var tryToTransfer = function (rawTransfer, map) {
  if (!isObject(rawTransfer)) throw TypeError('Transfer option cannot be converted to a sequence');

  var transfer = [];

  iterate(rawTransfer, function (value) {
    push(transfer, anObject(value));
  });

  var i = 0;
  var length = lengthOfArrayLike(transfer);
  var value, type, C, transferredArray, transferred, canvas, context;

  if (PROPER_TRANSFER) {
    transferredArray = nativeStructuredClone(transfer, { transfer: transfer });
    while (i < length) mapSet(map, transfer[i], transferredArray[i++]);
  } else while (i < length) {
    value = transfer[i++];
    if (mapHas(map, value)) throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR);

    type = classof(value);

    switch (type) {
      case 'ImageBitmap':
        C = global.OffscreenCanvas;
        if (!isConstructor(C)) throwUnpolyfillable(type, TRANSFERRING);
        try {
          canvas = new C(value.width, value.height);
          context = canvas.getContext('bitmaprenderer');
          context.transferFromImageBitmap(value);
          transferred = canvas.transferToImageBitmap();
        } catch (error) { /* empty */ }
        break;
      case 'AudioData':
      case 'VideoFrame':
        if (!isCallable(value.clone) || !isCallable(value.close)) throwUnpolyfillable(type, TRANSFERRING);
        try {
          transferred = value.clone();
          value.close();
        } catch (error) { /* empty */ }
        break;
      case 'ArrayBuffer':
      case 'MessagePort':
      case 'OffscreenCanvas':
      case 'ReadableStream':
      case 'TransformStream':
      case 'WritableStream':
        throwUnpolyfillable(type, TRANSFERRING);
    }

    if (transferred === undefined) throw new DOMException('This object cannot be transferred: ' + type, DATA_CLONE_ERROR);
    mapSet(map, value, transferred);
  }
};

$({ global: true, enumerable: true, sham: !PROPER_TRANSFER, forced: FORCED_REPLACEMENT }, {
  structuredClone: function structuredClone(value /* , { transfer } */) {
    var options = arguments.length > 1 ? anObject(arguments[1]) : undefined;
    var transfer = options ? options.transfer : undefined;
    var map;

    if (transfer !== undefined) {
      map = new Map();
      tryToTransfer(transfer, map);
    }

    return structuredCloneInternal(value, map);
  }
});
<commit_msg>workaround of incorrect `typeof Uint8ClampedArray` in Safari 9<commit_after>var IS_PURE = require('../internals/is-pure');
var $ = require('../internals/export');
var global = require('../internals/global');
var getBuiltin = require('../internals/get-built-in');
var uncurryThis = require('../internals/function-uncurry-this');
var fails = require('../internals/fails');
var uid = require('../internals/uid');
var isCallable = require('../internals/is-callable');
var isConstructor = require('../internals/is-constructor');
var isObject = require('../internals/is-object');
var isSymbol = require('../internals/is-symbol');
var iterate = require('../internals/iterate');
var anObject = require('../internals/an-object');
var classof = require('../internals/classof');
var hasOwn = require('../internals/has-own-property');
var createProperty = require('../internals/create-property');
var createNonEnumerableProperty = require('../internals/create-non-enumerable-property');
var lengthOfArrayLike = require('../internals/length-of-array-like');
var regExpFlags = require('../internals/regexp-flags');
var ERROR_STACK_INSTALLABLE = require('../internals/error-stack-installable');

var Object = global.Object;
var Date = global.Date;
var Error = global.Error;
var EvalError = global.EvalError;
var RangeError = global.RangeError;
var ReferenceError = global.ReferenceError;
var SyntaxError = global.SyntaxError;
var TypeError = global.TypeError;
var URIError = global.URIError;
var PerformanceMark = global.PerformanceMark;
var WebAssembly = global.WebAssembly;
var CompileError = WebAssembly && WebAssembly.CompileError || Error;
var LinkError = WebAssembly && WebAssembly.LinkError || Error;
var RuntimeError = WebAssembly && WebAssembly.RuntimeError || Error;
var DOMException = getBuiltin('DOMException');
var Set = getBuiltin('Set');
var Map = getBuiltin('Map');
var MapPrototype = Map.prototype;
var mapHas = uncurryThis(MapPrototype.has);
var mapGet = uncurryThis(MapPrototype.get);
var mapSet = uncurryThis(MapPrototype.set);
var setAdd = uncurryThis(Set.prototype.add);
var objectKeys = getBuiltin('Object', 'keys');
var push = uncurryThis([].push);
var bolleanValueOf = uncurryThis(true.valueOf);
var numberValueOf = uncurryThis(1.0.valueOf);
var stringValueOf = uncurryThis(''.valueOf);
var getFlags = uncurryThis(regExpFlags);
var getTime = uncurryThis(Date.prototype.getTime);
var PERFORMANCE_MARK = uid('structuredClone');
var DATA_CLONE_ERROR = 'DataCloneError';
var TRANSFERRING = 'Transferring';

var checkBasicSemantic = function (structuredCloneImplementation) {
  return !fails(function () {
    var set1 = new global.Set([7]);
    var set2 = structuredCloneImplementation(set1);
    var number = structuredCloneImplementation(Object(7));
    return set2 == set1 || !set2.has(7) || typeof number != 'object' || number != 7;
  }) && structuredCloneImplementation;
};

// https://github.com/whatwg/html/pull/5749
var checkNewErrorsSemantic = function (structuredCloneImplementation) {
  return !fails(function () {
    var test = structuredCloneImplementation(new global.AggregateError([1], PERFORMANCE_MARK, { cause: 3 }));
    return test.name != 'AggregateError' || test.errors[0] != 1 || test.message != PERFORMANCE_MARK || test.cause != 3;
  }) && structuredCloneImplementation;
};

// FF94+, Safari TP134+, Chrome Canary 98+, NodeJS 17.0+, Deno 1.13+
// current FF and Safari implementations can't clone errors
// https://bugzilla.mozilla.org/show_bug.cgi?id=1556604
// no one of current implementations supports new (html/5749) error cloning semantic
var nativeStructuredClone = global.structuredClone;

var FORCED_REPLACEMENT = IS_PURE || !checkNewErrorsSemantic(nativeStructuredClone);

// Chrome 82+, Safari 14.1+, Deno 1.11+
// Chrome 78-81 implementation swaps `.name` and `.message` of cloned `DOMException`
// Safari 14.1 implementation doesn't clone some `RegExp` flags, so requires a workaround
// current Safari implementation can't clone errors
// Deno 1.2-1.10 implementations too naive
// NodeJS 16.0+ does not have `PerformanceMark` constructor, structured cloning implementation
//   from `performance.mark` is too naive and can't clone, for example, `RegExp` or some boxed primitives
//   https://github.com/nodejs/node/issues/40840
// no one of current implementations supports new (html/5749) error cloning semantic
var structuredCloneFromMark = !nativeStructuredClone && checkBasicSemantic(function (value) {
  return new PerformanceMark(PERFORMANCE_MARK, { detail: value }).detail;
});

var nativeRestrictedStructuredClone = checkBasicSemantic(nativeStructuredClone) || structuredCloneFromMark;

var throwUncloneable = function (type) {
  throw new DOMException('Uncloneable type: ' + type, DATA_CLONE_ERROR);
};

var throwUnpolyfillable = function (type, kind) {
  throw new DOMException((kind || 'Cloning') + ' of ' + type + ' cannot be properly polyfilled in this engine', DATA_CLONE_ERROR);
};

var structuredCloneInternal = function (value, map) {
  if (isSymbol(value)) throwUncloneable('Symbol');
  if (!isObject(value)) return value;
  // effectively preserves circular references
  if (map) {
    if (mapHas(map, value)) return mapGet(map, value);
  } else map = new Map();

  var type = classof(value);
  var deep = false;
  var C, name, cloned, dataTransfer, i, length, keys, key, source, target;

  switch (type) {
    case 'Array':
      cloned = [];
      deep = true;
      break;
    case 'Object':
      cloned = {};
      deep = true;
      break;
    case 'Map':
      cloned = new Map();
      deep = true;
      break;
    case 'Set':
      cloned = new Set();
      deep = true;
      break;
    case 'RegExp':
      // in this block because of a Safari 14.1 bug
      // old FF does not clone regexes passed to the constructor, so get the source and flags directly
      cloned = new RegExp(value.source, 'flags' in value ? value.flags : getFlags(value));
      break;
    case 'Error':
      name = value.name;
      switch (name) {
        case 'AggregateError':
          cloned = getBuiltin('AggregateError')([]);
          break;
        case 'EvalError':
          cloned = EvalError();
          break;
        case 'RangeError':
          cloned = RangeError();
          break;
        case 'ReferenceError':
          cloned = ReferenceError();
          break;
        case 'SyntaxError':
          cloned = SyntaxError();
          break;
        case 'TypeError':
          cloned = TypeError();
          break;
        case 'URIError':
          cloned = URIError();
          break;
        case 'CompileError':
          cloned = CompileError();
          break;
        case 'LinkError':
          cloned = LinkError();
          break;
        case 'RuntimeError':
          cloned = RuntimeError();
          break;
        default:
          cloned = Error();
      }
      deep = true;
      break;
    case 'DOMException':
      cloned = new DOMException(value.message, value.name);
      deep = true;
      break;
    case 'DataView':
    case 'Int8Array':
    case 'Uint8Array':
    case 'Uint8ClampedArray':
    case 'Int16Array':
    case 'Uint16Array':
    case 'Int32Array':
    case 'Uint32Array':
    case 'Float32Array':
    case 'Float64Array':
    case 'BigInt64Array':
    case 'BigUint64Array':
      C = global[type];
      // in some old engines like Safari 9, typeof C is 'object'
      // on Uint8ClampedArray or some other constructors
      if (!isObject(C)) throwUnpolyfillable(type);
      cloned = new C(
        // this is safe, since arraybuffer cannot have circular references
        structuredCloneInternal(value.buffer, map),
        value.byteOffset,
        type === 'DataView' ? value.byteLength : value.length
      );
      break;
    case 'DOMQuad':
      C = global.DOMQuad;
      if (isConstructor(C)) {
        cloned = new C(
          structuredCloneInternal(value.p1, map),
          structuredCloneInternal(value.p2, map),
          structuredCloneInternal(value.p3, map),
          structuredCloneInternal(value.p4, map)
        );
      } else if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else throwUnpolyfillable(type);
      break;
    case 'FileList':
      C = global.DataTransfer;
      if (isConstructor(C)) {
        dataTransfer = new C();
        for (i = 0, length = lengthOfArrayLike(value); i < length; i++) {
          dataTransfer.items.add(structuredCloneInternal(value[i], map));
        }
        cloned = dataTransfer.files;
      } else if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else throwUnpolyfillable(type);
      break;
    case 'ImageData':
      // Safari 9 ImageData is a constructor, but typeof ImageData is 'object'
      try {
        cloned = new ImageData(
          structuredCloneInternal(value.data, map),
          value.width,
          value.height,
          { colorSpace: value.colorSpace }
        );
      } catch (error) {
        if (nativeRestrictedStructuredClone) {
          cloned = nativeRestrictedStructuredClone(value);
        } else throwUnpolyfillable(type);
      } break;
    default:
      if (nativeRestrictedStructuredClone) {
        cloned = nativeRestrictedStructuredClone(value);
      } else switch (type) {
        case 'BigInt':
          // can be a 3rd party polyfill
          cloned = Object(value.valueOf());
          break;
        case 'Boolean':
          cloned = Object(bolleanValueOf(value));
          break;
        case 'Number':
          cloned = Object(numberValueOf(value));
          break;
        case 'String':
          cloned = Object(stringValueOf(value));
          break;
        case 'Date':
          cloned = new Date(getTime(value));
          break;
        case 'ArrayBuffer':
          // detached buffers throws in `DataView` and `.slice`
          try {
            // `ArrayBuffer#slice` is not available in IE10
            if (typeof value.slice == 'function') {
              cloned = value.slice(0);
            } else {
              length = value.byteLength;
              cloned = new ArrayBuffer(length);
              // eslint-disable-next-line es/no-typed-arrays -- ok
              source = new DataView(value);
              // eslint-disable-next-line es/no-typed-arrays -- ok
              target = new DataView(cloned);
              for (i = 0; i < length; i++) {
                target.setUint8(i, source.getUint8(i));
              }
            }
          } catch (error) {
            throw new DOMException('ArrayBuffer is deatched', DATA_CLONE_ERROR);
          } break;
        case 'SharedArrayBuffer':
          // SharedArrayBuffer should use shared memory, we can't polyfill it, so return the original
          cloned = value;
          break;
        case 'Blob':
          try {
            cloned = value.slice(0, value.size, value.type);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMPoint':
        case 'DOMPointReadOnly':
          C = global[type];
          try {
            cloned = C.fromPoint
              ? C.fromPoint(value)
              : new C(value.x, value.y, value.z, value.w);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMRect':
        case 'DOMRectReadOnly':
          C = global[type];
          try {
            cloned = C.fromRect
              ? C.fromRect(value)
              : new C(value.x, value.y, value.width, value.height);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'DOMMatrix':
        case 'DOMMatrixReadOnly':
          C = global[type];
          try {
            cloned = C.fromMatrix
              ? C.fromMatrix(value)
              : new C(value);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'AudioData':
        case 'VideoFrame':
          if (!isCallable(value.clone)) throwUnpolyfillable(type);
          try {
            cloned = value.clone();
          } catch (error) {
            throwUncloneable(type);
          } break;
        case 'File':
          try {
            cloned = new File([value], value.name, value);
          } catch (error) {
            throwUnpolyfillable(type);
          } break;
        case 'CryptoKey':
        case 'GPUCompilationMessage':
        case 'GPUCompilationInfo':
        case 'ImageBitmap':
        case 'RTCCertificate':
        case 'WebAssembly.Module':
          throwUnpolyfillable(type);
          // break omitted
        default:
          throwUncloneable(type);
      }
  }

  mapSet(map, value, cloned);

  if (deep) switch (type) {
    case 'Array':
    case 'Object':
      keys = objectKeys(value);
      for (i = 0, length = lengthOfArrayLike(keys); i < length; i++) {
        key = keys[i];
        createProperty(cloned, key, structuredCloneInternal(value[key], map));
      } break;
    case 'Map':
      value.forEach(function (v, k) {
        mapSet(cloned, structuredCloneInternal(k, map), structuredCloneInternal(v, map));
      });
      break;
    case 'Set':
      value.forEach(function (v) {
        setAdd(cloned, structuredCloneInternal(v, map));
      });
      break;
    case 'Error':
      createNonEnumerableProperty(cloned, 'message', structuredCloneInternal(value.message, map));
      if (hasOwn(value, 'cause')) {
        createNonEnumerableProperty(cloned, 'cause', structuredCloneInternal(value.cause, map));
      }
      if (name == 'AggregateError') {
        cloned.errors = structuredCloneInternal(value.errors, map);
      } // break omitted
    case 'DOMException':
      if (ERROR_STACK_INSTALLABLE) {
        createNonEnumerableProperty(cloned, 'stack', structuredCloneInternal(value.stack, map));
      }
  }

  return cloned;
};

var PROPER_TRANSFER = nativeStructuredClone && !fails(function () {
  var buffer = new ArrayBuffer(8);
  var clone = nativeStructuredClone(buffer, { transfer: [buffer] });
  return buffer.byteLength != 0 || clone.byteLength != 8;
});

var tryToTransfer = function (rawTransfer, map) {
  if (!isObject(rawTransfer)) throw TypeError('Transfer option cannot be converted to a sequence');

  var transfer = [];

  iterate(rawTransfer, function (value) {
    push(transfer, anObject(value));
  });

  var i = 0;
  var length = lengthOfArrayLike(transfer);
  var value, type, C, transferredArray, transferred, canvas, context;

  if (PROPER_TRANSFER) {
    transferredArray = nativeStructuredClone(transfer, { transfer: transfer });
    while (i < length) mapSet(map, transfer[i], transferredArray[i++]);
  } else while (i < length) {
    value = transfer[i++];
    if (mapHas(map, value)) throw new DOMException('Duplicate transferable', DATA_CLONE_ERROR);

    type = classof(value);

    switch (type) {
      case 'ImageBitmap':
        C = global.OffscreenCanvas;
        if (!isConstructor(C)) throwUnpolyfillable(type, TRANSFERRING);
        try {
          canvas = new C(value.width, value.height);
          context = canvas.getContext('bitmaprenderer');
          context.transferFromImageBitmap(value);
          transferred = canvas.transferToImageBitmap();
        } catch (error) { /* empty */ }
        break;
      case 'AudioData':
      case 'VideoFrame':
        if (!isCallable(value.clone) || !isCallable(value.close)) throwUnpolyfillable(type, TRANSFERRING);
        try {
          transferred = value.clone();
          value.close();
        } catch (error) { /* empty */ }
        break;
      case 'ArrayBuffer':
      case 'MessagePort':
      case 'OffscreenCanvas':
      case 'ReadableStream':
      case 'TransformStream':
      case 'WritableStream':
        throwUnpolyfillable(type, TRANSFERRING);
    }

    if (transferred === undefined) throw new DOMException('This object cannot be transferred: ' + type, DATA_CLONE_ERROR);
    mapSet(map, value, transferred);
  }
};

$({ global: true, enumerable: true, sham: !PROPER_TRANSFER, forced: FORCED_REPLACEMENT }, {
  structuredClone: function structuredClone(value /* , { transfer } */) {
    var options = arguments.length > 1 ? anObject(arguments[1]) : undefined;
    var transfer = options ? options.transfer : undefined;
    var map;

    if (transfer !== undefined) {
      map = new Map();
      tryToTransfer(transfer, map);
    }

    return structuredCloneInternal(value, map);
  }
});
<|endoftext|>


<commit_before>import dateTimeFormats from './fixture/datetime'

const desc = VueI18n.availabilities.dateTimeFormat ? describe : describe.skip
desc('datetime format', () => {
  describe('dateTimeFormats', () => {
    it('should be worked', done => {
      const i18n = new VueI18n({
        locale: 'en-US',
        dateTimeFormats
      })
      Vue.nextTick().then(() => {
        assert.deepEqual(dateTimeFormats, i18n.dateTimeFormats)
      }).then(done)
    })
  })

  describe('getDateTimeFormat / setDateTimeFormat', () => {
    it('should be worked', done => {
      const i18n = new VueI18n({
        locale: 'en-US',
        dateTimeFormats
      })
      const el = document.createElement('div')
      document.body.appendChild(el)

      const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
      const vm = new Vue({
        i18n,
        render (h) {
          return h('p', { ref: 'text' }, [this.$d(dt, 'short')])
        }
      }).$mount(el)

      const { text } = vm.$refs
      const zhFormat = {
        short: {
          year: 'numeric', month: '2-digit', day: '2-digit',
          hour: '2-digit', minute: '2-digit'
        }
      }

      Vue.nextTick().then(() => {
        // NOTE: avoid webkit(phatomjs/safari) & Intl polyfill wired localization...
        isChrome && assert.strictEqual(text.textContent, '12/19/2012, 10:00 PM')
        i18n.setDateTimeFormat('zh-CN', zhFormat)
        assert.deepEqual(i18n.getDateTimeFormat('zh-CN'), zhFormat)
        i18n.locale = 'zh-CN'
      }).then(() => {
        // NOTE: avoid webkit(phatomjs/safari) & Intl polyfill wired localization...
        isChrome && assert.strictEqual(text.textContent, '2012/12/20 下午12:00')
      }).then(done)
    })
  })

  describe('mergeDateTimeFormat', () => {
    it('should be merged', () => {
      const i18n = new VueI18n({
        locale: 'ja-JP',
        dateTimeFormats
      })
      const foo = {
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit'
      }
      i18n.mergeDateTimeFormat('en-US', { foo })
      assert.deepEqual(foo, i18n.getDateTimeFormat('en-US').foo)
    })
  })

  describe('fallback', () => {
    it('should be fallbacked', done => {
      const i18n = new VueI18n({
        locale: 'en-uk',
        fallbackLocale: ['de', 'en-us'],
        dateTimeFormats: {
          de: {
            short: { day: '2-digit', month: '2-digit', year: '2-digit' }
          }
        }
      })
      const el = document.createElement('div')
      document.body.appendChild(el)

      const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
      const vm = new Vue({
        i18n,
        render (h) {
          return h('p', { ref: 'text' }, [this.$d(dt, 'short')])
        }
      }).$mount(el)

      const { text } = vm.$refs

      Vue.nextTick().then(() => {
        assert.strictEqual(text.textContent, '20.12.12')
      }).then(done)
    })
  })
})
<commit_msg>fix: CI fail<commit_after>import dateTimeFormats from './fixture/datetime'

const desc = VueI18n.availabilities.dateTimeFormat ? describe : describe.skip
desc('datetime format', () => {
  describe('dateTimeFormats', () => {
    it('should be worked', done => {
      const i18n = new VueI18n({
        locale: 'en-US',
        dateTimeFormats
      })
      Vue.nextTick().then(() => {
        assert.deepEqual(dateTimeFormats, i18n.dateTimeFormats)
      }).then(done)
    })
  })

  describe('getDateTimeFormat / setDateTimeFormat', () => {
    it('should be worked', done => {
      const i18n = new VueI18n({
        locale: 'en-US',
        dateTimeFormats
      })
      const el = document.createElement('div')
      document.body.appendChild(el)

      const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
      const vm = new Vue({
        i18n,
        render (h) {
          return h('p', { ref: 'text' }, [this.$d(dt, 'short')])
        }
      }).$mount(el)

      const { text } = vm.$refs
      const zhFormat = {
        short: {
          year: 'numeric', month: '2-digit', day: '2-digit',
          hour: '2-digit', minute: '2-digit'
        }
      }

      Vue.nextTick().then(() => {
        // NOTE: avoid webkit(phatomjs/safari) & Intl polyfill wired localization...
        isChrome && assert.strictEqual(text.textContent, '12/19/2012, 10:00 PM')
        i18n.setDateTimeFormat('zh-CN', zhFormat)
        assert.deepEqual(i18n.getDateTimeFormat('zh-CN'), zhFormat)
        i18n.locale = 'zh-CN'
      }).then(() => {
        // NOTE: avoid webkit(phatomjs/safari) & Intl polyfill wired localization...
        isChrome && assert.strictEqual(text.textContent, '2012/12/20 12:00')
      }).then(done)
    })
  })

  describe('mergeDateTimeFormat', () => {
    it('should be merged', () => {
      const i18n = new VueI18n({
        locale: 'ja-JP',
        dateTimeFormats
      })
      const foo = {
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit'
      }
      i18n.mergeDateTimeFormat('en-US', { foo })
      assert.deepEqual(foo, i18n.getDateTimeFormat('en-US').foo)
    })
  })

  describe('fallback', () => {
    it('should be fallbacked', done => {
      const i18n = new VueI18n({
        locale: 'en-uk',
        fallbackLocale: ['de', 'en-us'],
        dateTimeFormats: {
          de: {
            short: { day: '2-digit', month: '2-digit', year: '2-digit' }
          }
        }
      })
      const el = document.createElement('div')
      document.body.appendChild(el)

      const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0))
      const vm = new Vue({
        i18n,
        render (h) {
          return h('p', { ref: 'text' }, [this.$d(dt, 'short')])
        }
      }).$mount(el)

      const { text } = vm.$refs

      Vue.nextTick().then(() => {
        assert.strictEqual(text.textContent, '20.12.12')
      }).then(done)
    })
  })
})
<|endoftext|>


<commit_before>import lowerCase from 'lodash/lowerCase';
import sortBy from 'lodash/sortBy';
import compact from 'lodash/compact';
import moment from 'moment';
import { translateText } from 'utils/transifex';

import allOptions from '../options';

export const getForestTypes = ({
  forestTypes,
  settings,
  polynamesWhitelist,
  adm0
}) =>
  forestTypes
    .filter(o => {
      const isGlobal = !polynamesWhitelist && o.global;
      const hasPolyname =
        isGlobal ||
        (polynamesWhitelist &&
          polynamesWhitelist.includes(o.newTableKey || o.tableKey));
      return isGlobal || hasPolyname;
    })
    .map(f => ({
      ...f,
      label: f.label.includes('{iflYear}')
        ? f.label.replace('{iflYear}', settings.ifl || 2016)
        : f.label,
      metaKey:
        f.metaKey === 'primary_forest'
          ? `${lowerCase(adm0)}_${f.metaKey}${adm0 === 'IDN' ? 's' : ''}`
          : f.metaKey
    }));

export const getLandCategories = ({ landCategories, polynamesWhitelist }) =>
  landCategories.filter(o => {
    const isGlobal = !polynamesWhitelist && o.global;
    const hasPolyname =
      isGlobal ||
      (polynamesWhitelist &&
        polynamesWhitelist.includes(o.newTableKey || o.tableKey));
    return isGlobal || hasPolyname;
  });

export const getSettingsConfig = ({
  settingsConfig,
  settings,
  dataOptions,
  polynamesWhitelist,
  pendingKeys,
  status
}) =>
  settingsConfig &&
  settingsConfig
    .filter(
      s =>
        status !== 'pending' ||
        !pendingKeys ||
        (pendingKeys && pendingKeys.includes(s.key))
    )
    .map(o => {
      const {
        key,
        compareKey,
        startKey,
        endKey,
        options,
        whitelist,
        locationType,
        noSort
      } =
        o || {};
      let mergedOptions =
        (dataOptions && dataOptions[key]) || options || allOptions[key];
      if (key === 'forestType') {
        mergedOptions =
          mergedOptions &&
          getForestTypes({
            forestTypes: mergedOptions,
            settings,
            polynamesWhitelist,
            locationType
          });
      } else if (key === 'landCategory') {
        mergedOptions =
          mergedOptions &&
          getLandCategories({
            landCategories: mergedOptions,
            polynamesWhitelist,
            locationType
          });
      }
      const parsedOptions = noSort
        ? mergedOptions
        : sortBy(mergedOptions, 'label');

      return {
        ...o,
        ...(parsedOptions && {
          options: parsedOptions.filter(
            opt => !whitelist || whitelist.includes(opt.value)
          ),
          value: parsedOptions.find(opt => opt.value === settings[key]),
          ...(startKey && {
            startOptions: parsedOptions.filter(
              opt => opt.value <= settings[endKey]
            ),
            startValue: parsedOptions.find(
              opt => opt.value === settings[startKey]
            )
          }),
          ...(endKey && {
            endOptions: parsedOptions.filter(
              opt => opt.value >= settings[startKey]
            ),
            endValue: parsedOptions.find(opt => opt.value === settings[endKey])
          }),
          ...(compareKey && {
            compareOptions: parsedOptions.filter(
              opt => opt.value !== settings[key]
            ),
            compareValue: parsedOptions.find(
              opt => opt.value === settings[compareKey]
            )
          })
        })
      };
    });

export const getOptionsSelected = options =>
  options &&
  options.reduce(
    (obj, option) => ({
      ...obj,
      [option.key]: option.options.find(o => o === option.value)
    }),
    {}
  );

export const getIndicator = (forestType, landCategory) => {
  if (!forestType && !landCategory) return null;
  let label = '';
  let value = '';
  let forestTypeLabel = (forestType && forestType.label) || '';
  let landCatLabel = (landCategory && landCategory.label) || '';

  forestTypeLabel =
    forestType && forestType.preserveString === true
      ? forestTypeLabel
      : forestTypeLabel.toLowerCase();
  landCatLabel =
    landCategory && landCategory.preserveString === true
      ? landCatLabel
      : landCatLabel.toLowerCase();

  if (forestType && landCategory) {
    label = `${forestTypeLabel} in ${landCatLabel}`;
    value = `${forestType.value}__${landCategory.value}`;
  } else if (landCategory) {
    label = landCatLabel;
    value = landCategory.value;
  } else {
    label = forestTypeLabel;
    value = forestType.value;
  }

  return {
    label,
    value
  };
};

export const getWidgetDatasets = ({
  datasets,
  extentYear,
  startYear,
  endYear,
  year,
  weeks,
  startDateAbsolute,
  endDateAbsolute,
  latestDate,
  threshold
}) =>
  datasets &&
  datasets.map(d => ({
    ...d,
    opacity: 1,
    visibility: true,
    ...(!d.boundary && {
      layers:
        extentYear && !Array.isArray(d.layers)
          ? [d.layers[extentYear]]
          : d.layers,
      ...(((startYear && endYear) || year) && {
        timelineParams: {
          startDate: `${startYear || year}-01-01`,
          endDate: `${endYear || year}-12-31`,
          trimEndDate: `${endYear || year}-12-31`
        }
      }),
      ...(weeks && {
        timelineParams: {
          startDate: moment(latestDate || undefined)
            .subtract(weeks, 'weeks')
            .format('YYYY-MM-DD'),
          endDate: moment(latestDate || undefined).format('YYYY-MM-DD'),
          trimEndDate: moment(latestDate || undefined).format('YYYY-MM-DD')
        }
      }),
      ...(threshold && {
        params: {
          thresh: threshold,
          visibility: true
        }
      }),
      ...(startDateAbsolute &&
        endDateAbsolute && {
        params: {
          startDateAbsolute,
          endDateAbsolute
        }
      })
    })
  }));

export const getPolynameDatasets = ({ optionsSelected, settings }) => {
  const { ifl, forestType, landCategory } = settings;
  const polynames = [
    ...allOptions.forestType,
    ...allOptions.landCategory
  ].filter(p => [forestType, landCategory].includes(p.value));
  const iflYear =
    optionsSelected &&
    optionsSelected.ifl &&
    optionsSelected.ifl.find(opt => opt.value === ifl);

  return (
    polynames &&
    polynames.flatMap(
      polyname =>
        polyname.datasets &&
        polyname.datasets.map(d => ({
          opacity: 0.7,
          visibility: true,
          ...d,
          sqlParams: iflYear && {
            where: {
              class: iflYear.layerValue
            }
          }
        }))
    )
  );
};

export const getNonGlobalIndicator = ({
  forestType,
  landCategory,
  type,
  datasets
}) => {
  if (!datasets || type !== 'global') return null;

  const forestTypeCount = datasets[forestType && forestType.value];
  const landCategoryCount = datasets[landCategory && landCategory.value];

  const indicators = [];
  if (forestTypeCount) {
    indicators.push({
      label: forestType.label,
      count: forestTypeCount
    });
  }
  if (landCategoryCount) {
    indicators.push({
      label: landCategory.label,
      count: landCategoryCount
    });
  }

  return indicators;
};

export const getStatements = ({
  settings,
  type,
  dataType,
  landCategory,
  forestType,
  datasets
  // active
}) => {
  if (!settings) return null;
  const { extentYear, threshold } = settings;

  const indicators = getNonGlobalIndicator({
    forestType,
    landCategory,
    type,
    datasets
  });

  const indicatorStatements =
    indicators &&
    indicators.map(
      i =>
        (i
          ? translateText(
            '*{indicator} are available in {datasetsCount} countries only',
            {
              indicator: i.label.toLowerCase(),
              datasetsCount: i.count
            }
          )
          : null)
    );
  const statements = compact([
    extentYear && (dataType !== 'lossPrimary' || dataType !== 'fires')
      ? translateText('{extentYear} tree cover extent', { extentYear })
      : null,
    dataType === 'lossPrimary'
      ? translateText('2001 primary forest extent remaining')
      : null,
    threshold || threshold === 0
      ? translateText('>{threshold}% tree canopy', { threshold })
      : null,
    dataType === 'fires' &&
      active &&
      '*when on the map you can show up to 3 months of fires data',
    dataType === 'loss'
      ? translateText(
        'these estimates do not take tree cover gain into account'
      )
      : null,
    dataType === 'nlcd_landcover'
      ? translateText(
        '*raw NLCD categories have been re-classed to match IPCC categories'
      )
      : null,
    ...(indicatorStatements || [])
  ]);

  return statements;
};

export const getLocationPath = (routeType, type, query, params) => ({
  type: routeType,
  payload: {
    type: type === 'global' ? 'country' : type,
    ...params
  },
  query: {
    ...query,
    map: {
      ...(query && query.map),
      canBound: true
    }
  }
});
<commit_msg>Add active to disclaimer check<commit_after>import lowerCase from 'lodash/lowerCase';
import sortBy from 'lodash/sortBy';
import compact from 'lodash/compact';
import moment from 'moment';
import { translateText } from 'utils/transifex';

import allOptions from '../options';

export const getForestTypes = ({
  forestTypes,
  settings,
  polynamesWhitelist,
  adm0
}) =>
  forestTypes
    .filter(o => {
      const isGlobal = !polynamesWhitelist && o.global;
      const hasPolyname =
        isGlobal ||
        (polynamesWhitelist &&
          polynamesWhitelist.includes(o.newTableKey || o.tableKey));
      return isGlobal || hasPolyname;
    })
    .map(f => ({
      ...f,
      label: f.label.includes('{iflYear}')
        ? f.label.replace('{iflYear}', settings.ifl || 2016)
        : f.label,
      metaKey:
        f.metaKey === 'primary_forest'
          ? `${lowerCase(adm0)}_${f.metaKey}${adm0 === 'IDN' ? 's' : ''}`
          : f.metaKey
    }));

export const getLandCategories = ({ landCategories, polynamesWhitelist }) =>
  landCategories.filter(o => {
    const isGlobal = !polynamesWhitelist && o.global;
    const hasPolyname =
      isGlobal ||
      (polynamesWhitelist &&
        polynamesWhitelist.includes(o.newTableKey || o.tableKey));
    return isGlobal || hasPolyname;
  });

export const getSettingsConfig = ({
  settingsConfig,
  settings,
  dataOptions,
  polynamesWhitelist,
  pendingKeys,
  status
}) =>
  settingsConfig &&
  settingsConfig
    .filter(
      s =>
        status !== 'pending' ||
        !pendingKeys ||
        (pendingKeys && pendingKeys.includes(s.key))
    )
    .map(o => {
      const {
        key,
        compareKey,
        startKey,
        endKey,
        options,
        whitelist,
        locationType,
        noSort
      } =
        o || {};
      let mergedOptions =
        (dataOptions && dataOptions[key]) || options || allOptions[key];
      if (key === 'forestType') {
        mergedOptions =
          mergedOptions &&
          getForestTypes({
            forestTypes: mergedOptions,
            settings,
            polynamesWhitelist,
            locationType
          });
      } else if (key === 'landCategory') {
        mergedOptions =
          mergedOptions &&
          getLandCategories({
            landCategories: mergedOptions,
            polynamesWhitelist,
            locationType
          });
      }
      const parsedOptions = noSort
        ? mergedOptions
        : sortBy(mergedOptions, 'label');

      return {
        ...o,
        ...(parsedOptions && {
          options: parsedOptions.filter(
            opt => !whitelist || whitelist.includes(opt.value)
          ),
          value: parsedOptions.find(opt => opt.value === settings[key]),
          ...(startKey && {
            startOptions: parsedOptions.filter(
              opt => opt.value <= settings[endKey]
            ),
            startValue: parsedOptions.find(
              opt => opt.value === settings[startKey]
            )
          }),
          ...(endKey && {
            endOptions: parsedOptions.filter(
              opt => opt.value >= settings[startKey]
            ),
            endValue: parsedOptions.find(opt => opt.value === settings[endKey])
          }),
          ...(compareKey && {
            compareOptions: parsedOptions.filter(
              opt => opt.value !== settings[key]
            ),
            compareValue: parsedOptions.find(
              opt => opt.value === settings[compareKey]
            )
          })
        })
      };
    });

export const getOptionsSelected = options =>
  options &&
  options.reduce(
    (obj, option) => ({
      ...obj,
      [option.key]: option.options.find(o => o === option.value)
    }),
    {}
  );

export const getIndicator = (forestType, landCategory) => {
  if (!forestType && !landCategory) return null;
  let label = '';
  let value = '';
  let forestTypeLabel = (forestType && forestType.label) || '';
  let landCatLabel = (landCategory && landCategory.label) || '';

  forestTypeLabel =
    forestType && forestType.preserveString === true
      ? forestTypeLabel
      : forestTypeLabel.toLowerCase();
  landCatLabel =
    landCategory && landCategory.preserveString === true
      ? landCatLabel
      : landCatLabel.toLowerCase();

  if (forestType && landCategory) {
    label = `${forestTypeLabel} in ${landCatLabel}`;
    value = `${forestType.value}__${landCategory.value}`;
  } else if (landCategory) {
    label = landCatLabel;
    value = landCategory.value;
  } else {
    label = forestTypeLabel;
    value = forestType.value;
  }

  return {
    label,
    value
  };
};

export const getWidgetDatasets = ({
  datasets,
  extentYear,
  startYear,
  endYear,
  year,
  weeks,
  startDateAbsolute,
  endDateAbsolute,
  latestDate,
  threshold
}) =>
  datasets &&
  datasets.map(d => ({
    ...d,
    opacity: 1,
    visibility: true,
    ...(!d.boundary && {
      layers:
        extentYear && !Array.isArray(d.layers)
          ? [d.layers[extentYear]]
          : d.layers,
      ...(((startYear && endYear) || year) && {
        timelineParams: {
          startDate: `${startYear || year}-01-01`,
          endDate: `${endYear || year}-12-31`,
          trimEndDate: `${endYear || year}-12-31`
        }
      }),
      ...(weeks && {
        timelineParams: {
          startDate: moment(latestDate || undefined)
            .subtract(weeks, 'weeks')
            .format('YYYY-MM-DD'),
          endDate: moment(latestDate || undefined).format('YYYY-MM-DD'),
          trimEndDate: moment(latestDate || undefined).format('YYYY-MM-DD')
        }
      }),
      ...(threshold && {
        params: {
          thresh: threshold,
          visibility: true
        }
      }),
      ...(startDateAbsolute &&
        endDateAbsolute && {
        params: {
          startDateAbsolute,
          endDateAbsolute
        }
      })
    })
  }));

export const getPolynameDatasets = ({ optionsSelected, settings }) => {
  const { ifl, forestType, landCategory } = settings;
  const polynames = [
    ...allOptions.forestType,
    ...allOptions.landCategory
  ].filter(p => [forestType, landCategory].includes(p.value));
  const iflYear =
    optionsSelected &&
    optionsSelected.ifl &&
    optionsSelected.ifl.find(opt => opt.value === ifl);

  return (
    polynames &&
    polynames.flatMap(
      polyname =>
        polyname.datasets &&
        polyname.datasets.map(d => ({
          opacity: 0.7,
          visibility: true,
          ...d,
          sqlParams: iflYear && {
            where: {
              class: iflYear.layerValue
            }
          }
        }))
    )
  );
};

export const getNonGlobalIndicator = ({
  forestType,
  landCategory,
  type,
  datasets
}) => {
  if (!datasets || type !== 'global') return null;

  const forestTypeCount = datasets[forestType && forestType.value];
  const landCategoryCount = datasets[landCategory && landCategory.value];

  const indicators = [];
  if (forestTypeCount) {
    indicators.push({
      label: forestType.label,
      count: forestTypeCount
    });
  }
  if (landCategoryCount) {
    indicators.push({
      label: landCategory.label,
      count: landCategoryCount
    });
  }

  return indicators;
};

export const getStatements = ({
  settings,
  type,
  dataType,
  landCategory,
  forestType,
  datasets,
  active
}) => {
  if (!settings) return null;
  const { extentYear, threshold } = settings;

  const indicators = getNonGlobalIndicator({
    forestType,
    landCategory,
    type,
    datasets
  });

  const indicatorStatements =
    indicators &&
    indicators.map(
      i =>
        (i
          ? translateText(
            '*{indicator} are available in {datasetsCount} countries only',
            {
              indicator: i.label.toLowerCase(),
              datasetsCount: i.count
            }
          )
          : null)
    );
  const statements = compact([
    extentYear && (dataType !== 'lossPrimary' || dataType !== 'fires')
      ? translateText('{extentYear} tree cover extent', { extentYear })
      : null,
    dataType === 'lossPrimary'
      ? translateText('2001 primary forest extent remaining')
      : null,
    threshold || threshold === 0
      ? translateText('>{threshold}% tree canopy', { threshold })
      : null,
    dataType === 'fires' &&
      active &&
      '*when on the map you can show up to 3 months of fires data',
    dataType === 'loss'
      ? translateText(
        'these estimates do not take tree cover gain into account'
      )
      : null,
    dataType === 'nlcd_landcover'
      ? translateText(
        '*raw NLCD categories have been re-classed to match IPCC categories'
      )
      : null,
    ...(indicatorStatements || [])
  ]);

  return statements;
};

export const getLocationPath = (routeType, type, query, params) => ({
  type: routeType,
  payload: {
    type: type === 'global' ? 'country' : type,
    ...params
  },
  query: {
    ...query,
    map: {
      ...(query && query.map),
      canBound: true
    }
  }
});
<|endoftext|>


<commit_before>import m from 'mithril';
import R from 'ramda';
import Velocity from 'velocity-animate';
import Promise from 'bluebird';

import {Head, Spotify, SongPreview} from '../components';

import {getUserSongsByUsercode} from '../socket/RestRequests';
import {getDataFromURIS} from '../songData';

import Graph from './components/graph';
import EndCard from './components/EndCard';
import PreviewCard from './components/PreviewCard';
import { selectCard, deselectCard} from '../projector/animations';

import d3 from 'd3';

/* eslint-ignore */
const songData = [
  {
    album: 'We Like it Here',
    name: 'Shofukan',
    year: '2014',
    length: '6:33',
    description: 'This is some smooth funkalucious stuff right here',
    uri: '41kg2RvdwBuIv0OPpvBS4v',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
  {
    album: 'We Like it Here',
    name: 'What About Me?',
    year: '2014',
    length: '6:43',
    description: 'Trey loves this fuckadelic stuff, he tells his grandma about it every sunday',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
  {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },

];

// VIEW MODEL
const vm = {
  init: function(){
    vm.songCards = m.prop([]);
    vm.circleRadius = m.prop([10,5,5,5,5,5]);
  },
};

const select = function(i){
  const arr = [false, false, false,false,false,false];
  arr[i] = true;
  vm.songCards(R.zip(songData, arr));
};

const selectedCard = data =>

    <EndCard
      song={data}
    />

;

const unselectedCard = i =>

    <PreviewCard />

;

const view = () =>

        Back

 Mixy Tape

				<div className='graphSpace' config={function(){Graph.init(".graphSpace",vm.circleRadius());
											d3.selectAll("circle").on("click",function(){
												//reset the values to the original size
												vm.circleRadius([5,5,5,5,5,5]);
												//increase the clicked circles radius by setting the size in the vm
												vm.circleRadius()[d3.select(this).attr("class")] = 10;
												//select the card that matches with the clicked circle
					 							select(d3.select(this).attr("class"));
					 							//draw the view again
					 							m.redraw();
					 						})}}>

 Your Rock Journey

                  {
                      vm.songCards().map(
                      ([card, visible], i) => visible ? selectedCard(card) : unselectedCard(i))
                  }

        <SongPreview />
				<input
					className="button is-medium container"
					type="button"
          config={() =>
            getUserSongsByUsercode(m.route.param('usercode'))
            .then(resp => {
              const currentData = getDataFromURIS(resp);
              const zipArray = R.concat([true], R.repeat(false, currentData.length - 1));
              vm.songCards(R.zip(currentData, zipArray));
            })
          }
        	value="Finalize" />

    ;

const controller = () => {
  vm.init();
  m.redraw.strategy("diff");
};

export default {
  vm,
  view,
  controller,
};
<commit_msg>Fix card selection<commit_after>import m from 'mithril';
import R from 'ramda';
import Velocity from 'velocity-animate';
import Promise from 'bluebird';

import {Head, Spotify, SongPreview} from '../components';

import {getUserSongsByUsercode} from '../socket/RestRequests';
import {getDataFromURIS} from '../songData';

import Graph from './components/graph';
import EndCard from './components/EndCard';
import PreviewCard from './components/PreviewCard';
import { selectCard, deselectCard} from '../projector/animations';

import d3 from 'd3';

const songData = [
  {
    album: 'We Like it Here',
    name: 'Shofukan',
    year: '2014',
    length: '6:33',
    description: 'This is some smooth funkalucious stuff right here',
    uri: '41kg2RvdwBuIv0OPpvBS4v',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
  {
    album: 'We Like it Here',
    name: 'What About Me?',
    year: '2014',
    length: '6:43',
    description: 'Trey loves this fuckadelic stuff, he tells his grandma about it every sunday',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
  {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    img: 'http://placehold.it/433x433',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },
   {
    album: 'We Like it Here',
    name: 'Tia Macaco',
    year: '2014',
    length: '5:44',
    description: 'Bring it home with some fucktastic sounds',
    uri: '4CYENH0iPFuWXpWsrstBW3',
    remove: "spotify:track:41kg2RvdwBuIv0OPpvBS4v",
    img: 'http://placehold.it/433x433',
    artist: 'Peter',
    genre: "Alternative, maybe",
  },

];

// VIEW MODEL
const vm = {
  init: function(){
    vm.songCards = m.prop([]);
    vm.circleRadius = m.prop([10,5,5,5,5,5]);
    vm.songDataArray = [];
    vm.needsSongs = m.prop(true);
  },
};

const select = i => {
  const arr = R.repeat(false, vm.songDataArray.length);
  arr[i] = true;
  vm.songCards(R.zip(vm.songDataArray, arr));
};

const selectedCard = data =>

    <EndCard
      song={data}
    />

;

const unselectedCard = i =>

    <PreviewCard />

;

const getLuv = () =>
  vm.needsSongs() && getUserSongsByUsercode(m.route.param('usercode'))
  .then(resp => {
    vm.songDataArray = getDataFromURIS(resp);
    const zipArray = R.concat([true], R.repeat(false, vm.songDataArray.length - 1));
    vm.songCards(R.zip(vm.songDataArray, zipArray));
    vm.needsSongs(false);
  });

const view = () =>

        Back

 Mixy Tape

				<div className='graphSpace'
          config={function () {
            Graph.init(".graphSpace",vm.circleRadius());
  						d3.selectAll("circle").on("click",function(){
  							//reset the values to the original size
  							vm.circleRadius([5,5,5,5,5,5]);
  							//increase the clicked circles radius by setting the size in the vm
  							vm.circleRadius()[d3.select(this).attr("class")] = 10;
  							//select the card that matches with the clicked circle
   							select(d3.select(this).attr("class"));
   							//draw the view again
   							m.redraw();
   						})}}>

 Your Rock Journey

                  {
                      vm.songCards().map(
                      ([card, visible], i) => visible ? selectedCard(card) : unselectedCard(i))
                  }

        <SongPreview />
				<input
					className="button is-medium container"
					type="button"
        	value="Finalize" />

    ;

const controller = () => {
  vm.init();
  m.redraw.strategy("diff");
};

export default {
  vm,
  view,
  controller,
};
<|endoftext|>