<commit_before>jQuery(document).ready(function ($) {

    //add class body
    if (active_tab) {
        $('body').addClass('js-' + active_tab);
    }

    /**
     * document
     * */
    if ($('.js-document').size()) {

        symfony_ajax.behaviors.type_document = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                if (_uniqid) {
                    $('#' + _uniqid + '_type_document', context).change(function () {

                        $('#sonata-ba-field-container-' + _uniqid + '_date_notaire, #sonata-ba-field-container-' + _uniqid + '_date_apostille, #sonata-ba-field-container-' + _uniqid + '_statut_document_notaire, #sonata-ba-field-container-' + _uniqid + '_statut_document_apostille')[['show', 'hide'][$(this).val() == 2 ? 0 : 1]]();

                        $('#sonata-ba-field-container-' + _uniqid + '_preavis')[['show', 'hide'][($(this).val() == 1 || $(this).val() == 3) ? 0 : 1]]();

                        if ($(this).val() == 2){
                            $('#' + _uniqid + '_statut_document_notaire, #' + _uniqid + '_statut_document_apostille').each(function(){
                                if ($(this).val() == ''){
                                    $(this).val(1);
                                }
                            });
                        }
                        else {
                            $('#' + _uniqid + '_statut_document_notaire, #' + _uniqid + '_statut_document_apostille').val('');
                        }

                    }).trigger('change');

                    $('#sonata-ba-field-container-' + _uniqid + '_date_notaire').addClass('date_notaire');
                    $('#sonata-ba-field-container-' + _uniqid + '_statut_document_notaire').after('

').addClass('statut_document_notaire');
                    $('#sonata-ba-field-container-' + _uniqid + '_date_apostille').addClass('date_apostille');
                    $('#sonata-ba-field-container-' + _uniqid + '_statut_document_apostille').addClass('statut_document_apostille');
                }
            }
        };

        $('.sonata-ba-list-field-text').removeAttr('objectid');
    }

    /**
     * garantie
     * */

    if ($('.js-garantie').size()) {

        /**
         * @type {Object}
         */
        symfony_ajax.behaviors.garantie = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                $('.form-horizontal div.control-group [name]', context).each(function (i) {
                    var name = $(this).attr('name').split('[').pop();
                    $(this).addClass(name.substr(0, name.length - 1));
                });

                $('#' + _uniqid + '_type_garantie', context).change(function () {
                    symfony_ajax.garantie(_uniqid, context);
                }).trigger('change');

                $('#' + _uniqid + '_nom_de_la_banques_id', context).change(function () {
                    symfony_ajax.garantie(_uniqid, context);
                }).trigger('change');

                $('#' + _uniqid + '_nom_de_lemeteur', context).keyup(function () {
                    $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id')[['hide', 'show'][$(this).val() ? 0 : 1]]();
                }).keyup();
            }
        }

        /**
         * @param _uniqid
         * @param context
         * @param id
         */
        symfony_ajax.garantie_valute = function (_uniqid, context, id) {

            $('#' + _uniqid + '_montant_devise option', context).each(function () {
                if (id == 0) {
                    $(this).show();
                }
                else {
                    if ($(this).val() == id) {
                        $(this).show();
                    }
                    else {
                        $(this).hide();
                    }
                }
            });
        }

        /**
         * @param _uniqid
         * @param context
         */
        symfony_ajax.garantie = function (_uniqid, context) {

            var type = $('#' + _uniqid + '_type_garantie :selected', context).val();
            var status = $('#' + _uniqid + '_nom_de_la_banques_id :selected', context).val();

            var $show_block = $('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur, ' +
                '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_demission,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_decheance,' +
                '#sonata-ba-field-container-' + _uniqid + '_expire', context);

            var $require_block = $('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur input, ' +
                '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie input,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_demission input,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_decheance input', context);

            if ((type == 1 || type == 3)) {

                var valute_all = 0;
                symfony_ajax.garantie_valute(_uniqid, context, valute_all);

                $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id').show();

                if (status == 1) {
                    $require_block.removeAttr('required');

                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                    $show_block.hide();
                }
                else {
                    $require_block.attr('required', 'required');

                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                    $show_block.show();
                }
            }
            else if (type == 2) {
                $require_block.removeAttr('required');

                $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_date_decheance, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_expire', context).hide();

                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                $('#sonata-ba-field-container-' + _uniqid + '_date_demission', context).show();
                $('#sonata-ba-field-container-' + _uniqid + '_date_demission input', context).attr('required', 'required');

                //Euro
                var valute_euro = 1;
                symfony_ajax.garantie_valute(_uniqid, context, valute_euro);
                $('#' + _uniqid + '_montant_devise', context).val(valute_euro);
            }
        }
    }

    if ($('.js-tarif').size()) {

        $('.form-horizontal div.control-group').each(function (i) {
            var name = $(this).children().children().attr('name').split('[').pop();
            $(this).addClass('groups-' + name.substr(0, name.length - 1));
        });

        $('.js-tarif .form-client-invoicing .field-4 label').remove();
    }
    ;

    /*
     * coordonnees
     * */
    if ($('.js-coordonnees').size()) {

        var $tbody = $(' .sonata-ba-list .table tbody');
        var handle = '

	';

        $('.sonata-ba-list .table thead tr').append('	');

        $('.sonata-ba-list .table tbody tr').append(handle);

        $('.sonata-ba-list .table thead a').click(function () {
            return false;
        })

        $tbody.sortable({
            handle:'.handle',
            helper:function (e, ui) {
                ui.children().each(function () {
                    $(this).width($(this).width());
                });
                return ui;
            },
            update:function (event, ui) {
                var sort_data = [];
                $('.sonata-ba-list .ui-sortable tr').each(function (i) {
                    var objectid = $(this).find('td[objectid]:last').attr('objectid');
                    if (objectid) {
                        sort_data.push(objectid);
                    }
                });

                $.ajax({
                    url:Sonata.url.sortable,
                    type:'POST',
                    data:{'ids':sort_data},
                    dataType:'json',
                    async:false,
                    success:function (i) {
                        Admin.log(i);
                    }
                });
            }
        }).disableSelection();
    }

    /**
     * tarif
     */
    if ($('.js-tarif').size()) {
        symfony_ajax.behaviors.tarif = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                if (_uniqid) {
                    var tarif_value_percentage = $('#' + _uniqid + '_value_percentage');
                    var tarif_value = $('#' + _uniqid + '_value');

                    $('#' + _uniqid + '_mode_de_facturation').change(function () {

                        if (Sonata.mode_de_facturation[$(this).val()]) {

                            switch (Sonata.mode_de_facturation[$(this).val()].unit) {

                                case '%':
                                    tarif_value_percentage.removeAttr('disabled');
                                    tarif_value.attr('disabled', 'disabled').val('');
                                    Admin.log('%');
                                    break;

                                case 'V':
                                    tarif_value.removeAttr('disabled');
                                    tarif_value_percentage.attr('disabled', 'disabled').val('');
                                    Admin.log('V');
                                    break;
                            }
                        }
                    }).trigger('change');
                }
            }
        };
    }

    /**
     * compte & compte_de_depot
     */
    if ($('.js-compte, .js-compte_de_depot').size()) {
        var $inactiveTr = $('div.inactive_compte').parent().parent();
        $inactiveTr.find('.sonata-ba-list-field-action').html('');
        $inactiveTr.find('td').addClass('no-edit');
    }
});<commit_msg>Feature #1523 :: Client Admin - Documents - Form Mandat spécifique<commit_after>jQuery(document).ready(function ($) {

    //add class body
    if (active_tab) {
        $('body').addClass('js-' + active_tab);
    }

    /**
     * document
     * */
    if ($('.js-document').size()) {

        symfony_ajax.behaviors.type_document = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                if (_uniqid) {
                    $('#' + _uniqid + '_type_document', context).change(function () {

                        $('#sonata-ba-field-container-' + _uniqid + '_date_notaire, #sonata-ba-field-container-' + _uniqid + '_date_apostille, #sonata-ba-field-container-' + _uniqid + '_statut_document_notaire, #sonata-ba-field-container-' + _uniqid + '_statut_document_apostille')[['show', 'hide'][($(this).val() == 2 || $(this).val() == 6) ? 0 : 1]]();

                        $('#sonata-ba-field-container-' + _uniqid + '_preavis')[['show', 'hide'][($(this).val() == 1 || $(this).val() == 3) ? 0 : 1]]();

                        if ($(this).val() == 2 || $(this).val() == 6){
                            $('#' + _uniqid + '_statut_document_notaire, #' + _uniqid + '_statut_document_apostille').each(function(){
                                if ($(this).val() == ''){
                                    $(this).val(1);
                                }
                            });
                        }
                        else {
                            $('#' + _uniqid + '_statut_document_notaire, #' + _uniqid + '_statut_document_apostille').val('');
                        }

                    }).trigger('change');

                    $('#sonata-ba-field-container-' + _uniqid + '_date_notaire').addClass('date_notaire');
                    $('#sonata-ba-field-container-' + _uniqid + '_statut_document_notaire').after('

').addClass('statut_document_notaire');
                    $('#sonata-ba-field-container-' + _uniqid + '_date_apostille').addClass('date_apostille');
                    $('#sonata-ba-field-container-' + _uniqid + '_statut_document_apostille').addClass('statut_document_apostille');
                }
            }
        };

        $('.sonata-ba-list-field-text').removeAttr('objectid');
    }

    /**
     * garantie
     * */

    if ($('.js-garantie').size()) {

        /**
         * @type {Object}
         */
        symfony_ajax.behaviors.garantie = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                $('.form-horizontal div.control-group [name]', context).each(function (i) {
                    var name = $(this).attr('name').split('[').pop();
                    $(this).addClass(name.substr(0, name.length - 1));
                });

                $('#' + _uniqid + '_type_garantie', context).change(function () {
                    symfony_ajax.garantie(_uniqid, context);
                }).trigger('change');

                $('#' + _uniqid + '_nom_de_la_banques_id', context).change(function () {
                    symfony_ajax.garantie(_uniqid, context);
                }).trigger('change');

                $('#' + _uniqid + '_nom_de_lemeteur', context).keyup(function () {
                    $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id')[['hide', 'show'][$(this).val() ? 0 : 1]]();
                }).keyup();
            }
        }

        /**
         * @param _uniqid
         * @param context
         * @param id
         */
        symfony_ajax.garantie_valute = function (_uniqid, context, id) {

            $('#' + _uniqid + '_montant_devise option', context).each(function () {
                if (id == 0) {
                    $(this).show();
                }
                else {
                    if ($(this).val() == id) {
                        $(this).show();
                    }
                    else {
                        $(this).hide();
                    }
                }
            });
        }

        /**
         * @param _uniqid
         * @param context
         */
        symfony_ajax.garantie = function (_uniqid, context) {

            var type = $('#' + _uniqid + '_type_garantie :selected', context).val();
            var status = $('#' + _uniqid + '_nom_de_la_banques_id :selected', context).val();

            var $show_block = $('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur, ' +
                '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_demission,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_decheance,' +
                '#sonata-ba-field-container-' + _uniqid + '_expire', context);

            var $require_block = $('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur input, ' +
                '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie input,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_demission input,' +
                '#sonata-ba-field-container-' + _uniqid + '_date_decheance input', context);

            if ((type == 1 || type == 3)) {

                var valute_all = 0;
                symfony_ajax.garantie_valute(_uniqid, context, valute_all);

                $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id').show();

                if (status == 1) {
                    $require_block.removeAttr('required');

                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                    rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                    $show_block.hide();
                }
                else {
                    $require_block.attr('required', 'required');

                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                    add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                    $show_block.show();
                }
            }
            else if (type == 2) {
                $require_block.removeAttr('required');

                $('#sonata-ba-field-container-' + _uniqid + '_nom_de_la_banques_id, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_date_decheance, ' +
                    '#sonata-ba-field-container-' + _uniqid + '_expire', context).hide();

                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_nom_de_lemeteur label', context));
                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_num_de_ganrantie label', context));
                rm_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_decheance label', context));

                add_label_required($('#sonata-ba-field-container-' + _uniqid + '_date_demission label', context));
                $('#sonata-ba-field-container-' + _uniqid + '_date_demission', context).show();
                $('#sonata-ba-field-container-' + _uniqid + '_date_demission input', context).attr('required', 'required');

                //Euro
                var valute_euro = 1;
                symfony_ajax.garantie_valute(_uniqid, context, valute_euro);
                $('#' + _uniqid + '_montant_devise', context).val(valute_euro);
            }
        }
    }

    if ($('.js-tarif').size()) {

        $('.form-horizontal div.control-group').each(function (i) {
            var name = $(this).children().children().attr('name').split('[').pop();
            $(this).addClass('groups-' + name.substr(0, name.length - 1));
        });

        $('.js-tarif .form-client-invoicing .field-4 label').remove();
    }
    ;

    /*
     * coordonnees
     * */
    if ($('.js-coordonnees').size()) {

        var $tbody = $(' .sonata-ba-list .table tbody');
        var handle = '

	';

        $('.sonata-ba-list .table thead tr').append('	');

        $('.sonata-ba-list .table tbody tr').append(handle);

        $('.sonata-ba-list .table thead a').click(function () {
            return false;
        })

        $tbody.sortable({
            handle:'.handle',
            helper:function (e, ui) {
                ui.children().each(function () {
                    $(this).width($(this).width());
                });
                return ui;
            },
            update:function (event, ui) {
                var sort_data = [];
                $('.sonata-ba-list .ui-sortable tr').each(function (i) {
                    var objectid = $(this).find('td[objectid]:last').attr('objectid');
                    if (objectid) {
                        sort_data.push(objectid);
                    }
                });

                $.ajax({
                    url:Sonata.url.sortable,
                    type:'POST',
                    data:{'ids':sort_data},
                    dataType:'json',
                    async:false,
                    success:function (i) {
                        Admin.log(i);
                    }
                });
            }
        }).disableSelection();
    }

    /**
     * tarif
     */
    if ($('.js-tarif').size()) {
        symfony_ajax.behaviors.tarif = {
            attach:function (context) {
                var _uniqid = symfony_ajax.get_uniqid();

                if (_uniqid) {
                    var tarif_value_percentage = $('#' + _uniqid + '_value_percentage');
                    var tarif_value = $('#' + _uniqid + '_value');

                    $('#' + _uniqid + '_mode_de_facturation').change(function () {

                        if (Sonata.mode_de_facturation[$(this).val()]) {

                            switch (Sonata.mode_de_facturation[$(this).val()].unit) {

                                case '%':
                                    tarif_value_percentage.removeAttr('disabled');
                                    tarif_value.attr('disabled', 'disabled').val('');
                                    Admin.log('%');
                                    break;

                                case 'V':
                                    tarif_value.removeAttr('disabled');
                                    tarif_value_percentage.attr('disabled', 'disabled').val('');
                                    Admin.log('V');
                                    break;
                            }
                        }
                    }).trigger('change');
                }
            }
        };
    }

    /**
     * compte & compte_de_depot
     */
    if ($('.js-compte, .js-compte_de_depot').size()) {
        var $inactiveTr = $('div.inactive_compte').parent().parent();
        $inactiveTr.find('.sonata-ba-list-field-action').html('');
        $inactiveTr.find('td').addClass('no-edit');
    }
});<|endoftext|>


<commit_before>/* vim: set ts=2 sts=2 sw=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

if (!window.__firefox__) {
    Object.defineProperty(window, "__firefox__", {
      enumerable: false,
      configurable: false,
      writable: false,
      value: {
      userScripts: {},
      includeOnce: function(userScript, initializer) {
          if (!__firefox__.userScripts[userScript]) {
              __firefox__.userScripts[userScript] = true;
              if (typeof initializer === 'function') {
                  initializer();
              }
              return false;
          }
          return true;
          }
      }
  });
}

const MAXIMUM_HIGHLIGHT_COUNT = 500;
const SCROLL_OFFSET_Y = 40;
const SCROLL_DURATION = 100;

const HIGHLIGHT_CLASS_NAME = "__firefox__find-highlight";
const HIGHLIGHT_CLASS_NAME_ACTIVE = "__firefox__find-highlight-active";

const HIGHLIGHT_COLOR = "#ffde49";
const HIGHLIGHT_COLOR_ACTIVE = "#f19750";

// IMPORTANT!!!: If this CSS is ever changed, the sha256-base64
// hash in Client/Frontend/Reader/ReaderModeHandlers.swift will
// also need updated. The value of `ReaderModeStyleHash` in that
// file represents the sha256-base64 hash of the `HIGHLIGHT_CSS`.
const HIGHLIGHT_CSS =
`.${HIGHLIGHT_CLASS_NAME} {
  color: #000;
  background-color: ${HIGHLIGHT_COLOR};
  border-radius: 1px;
  box-shadow: 0 0 0 2px ${HIGHLIGHT_COLOR};
  transition: all ${SCROLL_DURATION}ms ease ${SCROLL_DURATION}ms;
}
.${HIGHLIGHT_CLASS_NAME}.${HIGHLIGHT_CLASS_NAME_ACTIVE} {
  background-color: ${HIGHLIGHT_COLOR_ACTIVE};
  box-shadow: 0 0 0 4px ${HIGHLIGHT_COLOR_ACTIVE},0 1px 3px 3px rgba(0,0,0,.75);
}`;

var lastEscapedQuery = "";
var lastFindOperation = null;
var lastReplacements = null;
var lastHighlights = null;
var activeHighlightIndex = -1;

var highlightSpan = document.createElement("span");
highlightSpan.className = HIGHLIGHT_CLASS_NAME;

var styleElement = document.createElement("style");
styleElement.innerHTML = HIGHLIGHT_CSS;

function find(query) {
  let trimmedQuery = query.trim();

  // If the trimmed query is empty, use it instead of the escaped
  // query to prevent searching for nothing but whitepsace.
  let escapedQuery = !trimmedQuery ? trimmedQuery : query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
  if (escapedQuery === lastEscapedQuery) {
    return;
  }

  if (lastFindOperation) {
    lastFindOperation.cancel();
  }

  clear();

  lastEscapedQuery = escapedQuery;

  if (!escapedQuery) {
    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: 0, totalResults: 0 });
    return;
  }

  let queryRegExp = new RegExp("(" + escapedQuery + ")", "gi");

  lastFindOperation = getMatchingNodeReplacements(queryRegExp, function(replacements, highlights) {
    let replacement;
    for (let i = 0, length = replacements.length; i < length; i++) {
      replacement = replacements[i];

      replacement.originalNode.replaceWith(replacement.replacementFragment);
    }

    lastFindOperation = null;
    lastReplacements = replacements;
    lastHighlights = highlights;
    activeHighlightIndex = -1;

    let totalResults = highlights.length;
    webkit.messageHandlers.findInPageHandler.postMessage({ totalResults: totalResults });

    findNext();
  });
}

function findNext() {
  if (lastHighlights) {
    activeHighlightIndex = (activeHighlightIndex + lastHighlights.length + 1) % lastHighlights.length;
    updateActiveHighlight();
  }
}

function findPrevious() {
  if (lastHighlights) {
    activeHighlightIndex = (activeHighlightIndex + lastHighlights.length - 1) % lastHighlights.length;
    updateActiveHighlight();
  }
}

function findDone() {
  styleElement.remove();
  clear();

  lastEscapedQuery = "";
}

function clear() {
  if (!lastHighlights) {
    return;
  }

  let replacements = lastReplacements;
  let highlights = lastHighlights;

  let highlight;
  for (let i = 0, length = highlights.length; i < length; i++) {
    highlight = highlights[i];

    removeHighlight(highlight);
  }

  lastReplacements = null;
  lastHighlights = null;
  activeHighlightIndex = -1;
}

function updateActiveHighlight() {
  if (!styleElement.parentNode) {
    document.body.appendChild(styleElement);
  }

  let lastActiveHighlight = document.querySelector("." + HIGHLIGHT_CLASS_NAME_ACTIVE);
  if (lastActiveHighlight) {
    lastActiveHighlight.className = HIGHLIGHT_CLASS_NAME;
  }

  if (!lastHighlights) {
    return;
  }

  let activeHighlight = lastHighlights[activeHighlightIndex];
  if (activeHighlight) {
    activeHighlight.className = HIGHLIGHT_CLASS_NAME + " " + HIGHLIGHT_CLASS_NAME_ACTIVE;
    scrollToElement(activeHighlight, SCROLL_DURATION);

    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: activeHighlightIndex + 1 });
  } else {
    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: 0 });
  }
}

function removeHighlight(highlight) {
  let parent = highlight.parentNode;
  if (parent) {
    while (highlight.firstChild) {
      parent.insertBefore(highlight.firstChild, highlight);
    }

    highlight.remove();
    parent.normalize();
  }
}

function asyncTextNodeWalker(iterator) {
  let operation = new Operation();
  let walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);

  let timeout = setTimeout(function() {
    chunkedLoop(function() { return walker.nextNode(); }, function(node) {
      if (operation.cancelled) {
        return false;
      }

      iterator(node);
      return true;
    }, 100).then(function() {
      operation.complete();
    });
  }, 50);

  operation.oncancelled = function() {
    clearTimeout(timeout);
  };

  return operation;
}

function getMatchingNodeReplacements(regExp, callback) {
  let replacements = [];
  let highlights = [];
  let isMaximumHighlightCount = false;
  let operation = asyncTextNodeWalker(function(originalNode) {
    if (!isTextNodeVisible(originalNode)) {
      return;
    }

    let originalTextContent = originalNode.textContent;
    let lastIndex = 0;
    let replacementFragment = document.createDocumentFragment();
    let hasReplacement = false;
    let match;

    while ((match = regExp.exec(originalTextContent))) {
      let matchTextContent = match[0];

      // Add any text before this match.
      if (match.index > 0) {
        let leadingSubstring = originalTextContent.substring(lastIndex, match.index);
        replacementFragment.appendChild(document.createTextNode(leadingSubstring));
      }

      // Add element for this match.
      let element = highlightSpan.cloneNode(false);
      element.textContent = matchTextContent;
      replacementFragment.appendChild(element);
      highlights.push(element);

      lastIndex = regExp.lastIndex;
      hasReplacement = true;

      if (highlights.length > MAXIMUM_HIGHLIGHT_COUNT) {
        isMaximumHighlightCount = true;
        break;
      }
    }

    if (hasReplacement) {
      // Add any text after the matches.
      if (lastIndex < originalTextContent.length) {
        let trailingSubstring = originalTextContent.substring(lastIndex, originalTextContent.length);
        replacementFragment.appendChild(document.createTextNode(trailingSubstring));
      }

      replacements.push({
        originalNode: originalNode,
        replacementFragment: replacementFragment
      });
    }

    if (isMaximumHighlightCount) {
      operation.cancel();
      callback(replacements, highlights);
    }
  });

  // Callback for if/when the text node loop completes (should
  // happen unless the maximum highlight count is reached).
  operation.oncompleted = function() {
    callback(replacements, highlights);
  };

  return operation;
}

function chunkedLoop(condition, iterator, chunkSize) {
  return new Promise(function(resolve, reject) {
    setTimeout(doChunk, 0);

    function doChunk() {
      let argument;
      for (let i = 0; i < chunkSize; i++) {
        argument = condition();
        if (!argument || iterator(argument) === false) {
          resolve();
          return;
        }
      }

      setTimeout(doChunk, 0);
    }
  });
}

function scrollToElement(element, duration) {
  let rect = element.getBoundingClientRect();

  let targetX = clamp(rect.left + window.scrollX - window.innerWidth / 2, 0, document.body.scrollWidth);
  let targetY = clamp(SCROLL_OFFSET_Y + rect.top + window.scrollY - window.innerHeight / 2, 0, document.body.scrollHeight);

  let startX = window.scrollX;
  let startY = window.scrollY;

  let deltaX = targetX - startX;
  let deltaY = targetY - startY;

  let startTimestamp;

  function step(timestamp) {
    if (!startTimestamp) {
      startTimestamp = timestamp;
    }

    let time = timestamp - startTimestamp;
    let percent = Math.min(time / duration, 1);

    let x = startX + deltaX * percent;
    let y = startY + deltaY * percent;

    window.scrollTo(x, y);

    if (time < duration) {
      requestAnimationFrame(step);
    }
  }

  requestAnimationFrame(step);
}

function isTextNodeVisible(textNode) {
  let element = textNode.parentElement;
  return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
}

function clamp(value, min, max) {
  return Math.max(min, Math.min(value, max));
}

function Operation() {
  this.cancelled = false;
  this.completed = false;
}

Operation.prototype.constructor = Operation;

Operation.prototype.cancel = function() {
  this.cancelled = true;

  if (typeof this.oncancelled === "function") {
    this.oncancelled();
  }
};

Operation.prototype.complete = function() {
  this.completed = true;

  if (typeof this.oncompleted === "function") {
    if (!this.cancelled) {
      this.oncompleted();
    }
  }
};

Object.defineProperty(window.__firefox__, "find", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: find
});

Object.defineProperty(window.__firefox__, "findNext", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findNext
});

Object.defineProperty(window.__firefox__, "findPrevious", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findPrevious
});

Object.defineProperty(window.__firefox__, "findDone", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findDone
});
<commit_msg>Fixes #1087: find in page showing inflated results (#1124)<commit_after>/* vim: set ts=2 sts=2 sw=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

if (!window.__firefox__) {
    Object.defineProperty(window, "__firefox__", {
      enumerable: false,
      configurable: false,
      writable: false,
      value: {
      userScripts: {},
      includeOnce: function(userScript, initializer) {
          if (!__firefox__.userScripts[userScript]) {
              __firefox__.userScripts[userScript] = true;
              if (typeof initializer === 'function') {
                  initializer();
              }
              return false;
          }
          return true;
          }
      }
  });
}

const MAXIMUM_HIGHLIGHT_COUNT = 500;
const SCROLL_OFFSET_Y = 40;
const SCROLL_DURATION = 100;

const HIGHLIGHT_CLASS_NAME = "__firefox__find-highlight";
const HIGHLIGHT_CLASS_NAME_ACTIVE = "__firefox__find-highlight-active";

const HIGHLIGHT_COLOR = "#ffde49";
const HIGHLIGHT_COLOR_ACTIVE = "#f19750";

// IMPORTANT!!!: If this CSS is ever changed, the sha256-base64
// hash in Client/Frontend/Reader/ReaderModeHandlers.swift will
// also need updated. The value of `ReaderModeStyleHash` in that
// file represents the sha256-base64 hash of the `HIGHLIGHT_CSS`.
const HIGHLIGHT_CSS =
`.${HIGHLIGHT_CLASS_NAME} {
  color: #000;
  background-color: ${HIGHLIGHT_COLOR};
  border-radius: 1px;
  box-shadow: 0 0 0 2px ${HIGHLIGHT_COLOR};
  transition: all ${SCROLL_DURATION}ms ease ${SCROLL_DURATION}ms;
}
.${HIGHLIGHT_CLASS_NAME}.${HIGHLIGHT_CLASS_NAME_ACTIVE} {
  background-color: ${HIGHLIGHT_COLOR_ACTIVE};
  box-shadow: 0 0 0 4px ${HIGHLIGHT_COLOR_ACTIVE},0 1px 3px 3px rgba(0,0,0,.75);
}`;

var lastEscapedQuery = "";
var lastFindOperation = null;
var lastReplacements = null;
var lastHighlights = null;
var activeHighlightIndex = -1;

var highlightSpan = document.createElement("span");
highlightSpan.className = HIGHLIGHT_CLASS_NAME;

var styleElement = document.createElement("style");
styleElement.innerHTML = HIGHLIGHT_CSS;

function find(query) {
  let trimmedQuery = query.trim();

  // If the trimmed query is empty, use it instead of the escaped
  // query to prevent searching for nothing but whitepsace.
  let escapedQuery = !trimmedQuery ? trimmedQuery : query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
  if (escapedQuery === lastEscapedQuery) {
    return;
  }

  if (lastFindOperation) {
    lastFindOperation.cancel();
  }

  clear();

  lastEscapedQuery = escapedQuery;

  if (!escapedQuery) {
    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: 0, totalResults: 0 });
    return;
  }

  let queryRegExp = new RegExp("(" + escapedQuery + ")", "gi");

  lastFindOperation = getMatchingNodeReplacements(queryRegExp, function(replacements, highlights) {
    let replacement;
    for (let i = 0, length = replacements.length; i < length; i++) {
      replacement = replacements[i];

      replacement.originalNode.replaceWith(replacement.replacementFragment);
    }

    lastFindOperation = null;
    lastReplacements = replacements;
    lastHighlights = highlights;
    activeHighlightIndex = -1;

    let totalResults = highlights.length;
    webkit.messageHandlers.findInPageHandler.postMessage({ totalResults: totalResults });

    findNext();
  });
}

function findNext() {
  if (lastHighlights) {
    activeHighlightIndex = (activeHighlightIndex + lastHighlights.length + 1) % lastHighlights.length;
    updateActiveHighlight();
  }
}

function findPrevious() {
  if (lastHighlights) {
    activeHighlightIndex = (activeHighlightIndex + lastHighlights.length - 1) % lastHighlights.length;
    updateActiveHighlight();
  }
}

function findDone() {
  styleElement.remove();
  clear();

  lastEscapedQuery = "";
}

function clear() {
  if (!lastHighlights) {
    return;
  }

  let replacements = lastReplacements;
  let highlights = lastHighlights;

  let highlight;
  for (let i = 0, length = highlights.length; i < length; i++) {
    highlight = highlights[i];

    removeHighlight(highlight);
  }

  lastReplacements = null;
  lastHighlights = null;
  activeHighlightIndex = -1;
}

function updateActiveHighlight() {
  if (!styleElement.parentNode) {
    document.body.appendChild(styleElement);
  }

  let lastActiveHighlight = document.querySelector("." + HIGHLIGHT_CLASS_NAME_ACTIVE);
  if (lastActiveHighlight) {
    lastActiveHighlight.className = HIGHLIGHT_CLASS_NAME;
  }

  if (!lastHighlights) {
    return;
  }

  let activeHighlight = lastHighlights[activeHighlightIndex];
  if (activeHighlight) {
    activeHighlight.className = HIGHLIGHT_CLASS_NAME + " " + HIGHLIGHT_CLASS_NAME_ACTIVE;
    scrollToElement(activeHighlight, SCROLL_DURATION);

    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: activeHighlightIndex + 1 });
  } else {
    webkit.messageHandlers.findInPageHandler.postMessage({ currentResult: 0 });
  }
}

function removeHighlight(highlight) {
  let parent = highlight.parentNode;
  if (parent) {
    while (highlight.firstChild) {
      parent.insertBefore(highlight.firstChild, highlight);
    }

    highlight.remove();
    parent.normalize();
  }
}

function asyncTextNodeWalker(iterator) {
  let operation = new Operation();
  let walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);

  let timeout = setTimeout(function() {
    chunkedLoop(function() { return walker.nextNode(); }, function(node) {
      if (operation.cancelled) {
        return false;
      }

      iterator(node);
      return true;
    }, 100).then(function() {
      operation.complete();
    });
  }, 50);

  operation.oncancelled = function() {
    clearTimeout(timeout);
  };

  return operation;
}

function getMatchingNodeReplacements(regExp, callback) {
  let replacements = [];
  let highlights = [];
  let isMaximumHighlightCount = false;
  let operation = asyncTextNodeWalker(function(originalNode) {
    if (!isTextNodeVisible(originalNode) || originalNode.parentElement.nodeName === "IFRAME") {
      return;
    }

    let originalTextContent = originalNode.textContent;
    let lastIndex = 0;
    let replacementFragment = document.createDocumentFragment();
    let hasReplacement = false;
    let match;

    while ((match = regExp.exec(originalTextContent))) {
      let matchTextContent = match[0];

      // Add any text before this match.
      if (match.index > 0) {
        let leadingSubstring = originalTextContent.substring(lastIndex, match.index);
        replacementFragment.appendChild(document.createTextNode(leadingSubstring));
      }

      // Add element for this match.
      let element = highlightSpan.cloneNode(false);
      element.textContent = matchTextContent;
      replacementFragment.appendChild(element);
      highlights.push(element);

      lastIndex = regExp.lastIndex;
      hasReplacement = true;

      if (highlights.length > MAXIMUM_HIGHLIGHT_COUNT) {
        isMaximumHighlightCount = true;
        break;
      }
    }

    if (hasReplacement) {
      // Add any text after the matches.
      if (lastIndex < originalTextContent.length) {
        let trailingSubstring = originalTextContent.substring(lastIndex, originalTextContent.length);
        replacementFragment.appendChild(document.createTextNode(trailingSubstring));
      }

      replacements.push({
        originalNode: originalNode,
        replacementFragment: replacementFragment
      });
    }

    if (isMaximumHighlightCount) {
      operation.cancel();
      callback(replacements, highlights);
    }
  });

  // Callback for if/when the text node loop completes (should
  // happen unless the maximum highlight count is reached).
  operation.oncompleted = function() {
    callback(replacements, highlights);
  };

  return operation;
}

function chunkedLoop(condition, iterator, chunkSize) {
  return new Promise(function(resolve, reject) {
    setTimeout(doChunk, 0);

    function doChunk() {
      let argument;
      for (let i = 0; i < chunkSize; i++) {
        argument = condition();
        if (!argument || iterator(argument) === false) {
          resolve();
          return;
        }
      }

      setTimeout(doChunk, 0);
    }
  });
}

function scrollToElement(element, duration) {
  let rect = element.getBoundingClientRect();

  let targetX = clamp(rect.left + window.scrollX - window.innerWidth / 2, 0, document.body.scrollWidth);
  let targetY = clamp(SCROLL_OFFSET_Y + rect.top + window.scrollY - window.innerHeight / 2, 0, document.body.scrollHeight);

  let startX = window.scrollX;
  let startY = window.scrollY;

  let deltaX = targetX - startX;
  let deltaY = targetY - startY;

  let startTimestamp;

  function step(timestamp) {
    if (!startTimestamp) {
      startTimestamp = timestamp;
    }

    let time = timestamp - startTimestamp;
    let percent = Math.min(time / duration, 1);

    let x = startX + deltaX * percent;
    let y = startY + deltaY * percent;

    window.scrollTo(x, y);

    if (time < duration) {
      requestAnimationFrame(step);
    }
  }

  requestAnimationFrame(step);
}

function isTextNodeVisible(textNode) {
  let element = textNode.parentElement;
  if (!element) {
    return false;
  }
  return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
}

function clamp(value, min, max) {
  return Math.max(min, Math.min(value, max));
}

function Operation() {
  this.cancelled = false;
  this.completed = false;
}

Operation.prototype.constructor = Operation;

Operation.prototype.cancel = function() {
  this.cancelled = true;

  if (typeof this.oncancelled === "function") {
    this.oncancelled();
  }
};

Operation.prototype.complete = function() {
  this.completed = true;

  if (typeof this.oncompleted === "function") {
    if (!this.cancelled) {
      this.oncompleted();
    }
  }
};

Object.defineProperty(window.__firefox__, "find", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: find
});

Object.defineProperty(window.__firefox__, "findNext", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findNext
});

Object.defineProperty(window.__firefox__, "findPrevious", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findPrevious
});

Object.defineProperty(window.__firefox__, "findDone", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: findDone
});
<|endoftext|>


<commit_before>import { moduleFor, test } from 'ember-qunit';
import JsonSerializer from '../../../storagekit/serializers/json';

/*global sinon*/

let sandbox;

moduleFor('storagekit/adapter:instance', 'Unit | Adapter | instance', {
  setup() {
    sandbox = sinon.sandbox;
  },
  teardown() {
    sandbox.restore();
  }
});

test('it exists', function (assert) {
  var adapter = this.subject();
  assert.ok(adapter);
});

test('Returns null for key that does not exist', function (assert) {
  assert.expect(1);

  const storageService = this.subject();

  assert.strictEqual(storageService.key('nonExistentKey'), null);
});

test('Returns key from index based on keys ordered alphabetically.', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: {
      serialize(value) {
        return value;
      }
    }
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('bar', 'qux');

  assert.strictEqual(adapter.key(0), 'bar', 'Index zero should be first alphabetical key');
  assert.strictEqual(adapter.key(1), 'foo', 'Index one should be second alphabetical key');
});

test('Properly reorganizes key indices when key is deleted', function (assert) {
  assert.expect(1);

  const adapter = this.subject({
    serializer: {
      serialize(value) {
        return value;
      }
    }
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('bar', 'qux');

  adapter.removeItem('bar');

  assert.strictEqual(adapter.key(0), 'foo', 'deleting first value shifts other values towards index 0');
});

test('Treats keys that are objects uniformly', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem({}, 'foo');

  assert.strictEqual(adapter.getItem({}), 'foo');
  assert.strictEqual(adapter.getItem({foo: 'bar'}), 'foo', 'a different object be interpreted as the same key');
});

test('Treats keys that are arrays as a string of values', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem([1, 2, 3], 'foo');

  assert.strictEqual(adapter.getItem([1, 2, 3]), 'foo');
  assert.notEqual(adapter.getItem(['a', 'b', 'c']), 'foo', 'a different object be interpreted as the same key');
});

test('undefined is a valid key', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem(undefined, 'bar');

  assert.strictEqual(adapter.getItem(undefined), 'bar');

  assert.strictEqual(adapter.getItem('undefined'), 'bar');
});

test('null is a valid key', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem(null, 'bar');

  assert.strictEqual(adapter.getItem(null), 'bar');

  assert.strictEqual(adapter.getItem('null'), 'bar');
});

test('keys returns all keys in storage when namespace is present', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    namespace: 'baz',
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem('foo', 'bar');

  assert.equal(adapter.keys().length, 1);
  assert.equal(adapter.keys()[0], 'foo');
});

test('keys returns all keys in storage when namespace is not present', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem('foo', 'bar');

  assert.equal(adapter.keys().length, 1);
  assert.equal(adapter.keys()[0], 'foo');
});

test('keys returns all keys in alphabetical order', function (assert) {
  assert.expect(3);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  sinon.stub(adapter.get('container'), 'lookupFactory', () => {
    return {};
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('baz', 'qux');

  const keys = adapter.keys();

  assert.equal(keys.length, 2);
  assert.equal(keys[0], 'baz');
  assert.equal(keys[1], 'foo');
});
<commit_msg>removed usage of container from instance adapter unit tests<commit_after>import { moduleFor, test } from 'ember-qunit';
import JsonSerializer from '../../../storagekit/serializers/json';

/*global sinon*/

let sandbox;

moduleFor('storagekit/adapter:instance', 'Unit | Adapter | instance', {
  setup() {
    sandbox = sinon.sandbox;
  },
  teardown() {
    sandbox.restore();
  }
});

test('it exists', function (assert) {
  var adapter = this.subject();
  assert.ok(adapter);
});

test('Returns null for key that does not exist', function (assert) {
  assert.expect(1);

  const storageService = this.subject();

  assert.strictEqual(storageService.key('nonExistentKey'), null);
});

test('Returns key from index based on keys ordered alphabetically.', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: {
      serialize(value) {
        return value;
      }
    }
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('bar', 'qux');

  assert.strictEqual(adapter.key(0), 'bar', 'Index zero should be first alphabetical key');
  assert.strictEqual(adapter.key(1), 'foo', 'Index one should be second alphabetical key');
});

test('Properly reorganizes key indices when key is deleted', function (assert) {
  assert.expect(1);

  const adapter = this.subject({
    serializer: {
      serialize(value) {
        return value;
      }
    }
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('bar', 'qux');

  adapter.removeItem('bar');

  assert.strictEqual(adapter.key(0), 'foo', 'deleting first value shifts other values towards index 0');
});

test('Treats keys that are objects uniformly', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem({}, 'foo');

  assert.strictEqual(adapter.getItem({}), 'foo');
  assert.strictEqual(adapter.getItem({foo: 'bar'}), 'foo', 'a different object be interpreted as the same key');
});

test('Treats keys that are arrays as a string of values', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem([1, 2, 3], 'foo');

  assert.strictEqual(adapter.getItem([1, 2, 3]), 'foo');
  assert.notEqual(adapter.getItem(['a', 'b', 'c']), 'foo', 'a different object be interpreted as the same key');
});

test('undefined is a valid key', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem(undefined, 'bar');

  assert.strictEqual(adapter.getItem(undefined), 'bar');

  assert.strictEqual(adapter.getItem('undefined'), 'bar');
});

test('null is a valid key', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem(null, 'bar');

  assert.strictEqual(adapter.getItem(null), 'bar');

  assert.strictEqual(adapter.getItem('null'), 'bar');
});

test('keys returns all keys in storage when namespace is present', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    namespace: 'baz',
    serializer: JsonSerializer.create()
  });

  adapter.setItem('foo', 'bar');

  assert.equal(adapter.keys().length, 1);
  assert.equal(adapter.keys()[0], 'foo');
});

test('keys returns all keys in storage when namespace is not present', function (assert) {
  assert.expect(2);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem('foo', 'bar');

  assert.equal(adapter.keys().length, 1);
  assert.equal(adapter.keys()[0], 'foo');
});

test('keys returns all keys in alphabetical order', function (assert) {
  assert.expect(3);

  const adapter = this.subject({
    serializer: JsonSerializer.create()
  });

  adapter.setItem('foo', 'bar');
  adapter.setItem('baz', 'qux');

  const keys = adapter.keys();

  assert.equal(keys.length, 2);
  assert.equal(keys[0], 'baz');
  assert.equal(keys[1], 'foo');
});
<|endoftext|>


<commit_before>/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-extraneous-dependencies */

import 'vtk.js/Sources/favicon';

import HttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkColorMaps from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction/ColorMaps';
import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract';
import vtkXMLPolyDataReader from 'vtk.js/Sources/IO/XML/XMLPolyDataReader';
import vtkFPSMonitor from 'vtk.js/Sources/Interaction/UI/FPSMonitor';

import {
  ColorMode,
  ScalarMode,
} from 'vtk.js/Sources/Rendering/Core/Mapper/Constants';

import style from './GeometryViewer.mcss';
import icon from '../../../Documentation/content/icon/favicon-96x96.png';

let autoInit = true;
let background = [0, 0, 0];
let renderWindow;
let renderer;

global.pipeline = {};

// Process arguments from URL
const userParams = vtkURLExtract.extractURLParameters();

// Background handling
if (userParams.background) {
  background = userParams.background.split(',').map((s) => Number(s));
}
const selectorClass =
  background.length === 3 && background.reduce((a, b) => a + b, 0) < 1.5
    ? style.dark
    : style.light;

// name
const defaultName = userParams.name || '';

// lut
const lutName = userParams.lut || 'erdc_rainbow_bright';

// field
const field = userParams.field || '';

// camera
function updateCamera(camera) {
  ['zoom', 'pitch', 'elevation', 'yaw', 'azimuth', 'roll', 'dolly'].forEach(
    (key) => {
      if (userParams[key]) {
        camera[key](userParams[key]);
      }
      renderWindow.render();
    }
  );
}

function preventDefaults(e) {
  e.preventDefault();
  e.stopPropagation();
}

// ----------------------------------------------------------------------------
// DOM containers for UI control
// ----------------------------------------------------------------------------

const rootControllerContainer = document.createElement('div');
rootControllerContainer.setAttribute('class', style.rootController);

const addDataSetButton = document.createElement('img');
addDataSetButton.setAttribute('class', style.button);
addDataSetButton.setAttribute('src', icon);
addDataSetButton.addEventListener('click', () => {
  const isVisible = rootControllerContainer.style.display !== 'none';
  rootControllerContainer.style.display = isVisible ? 'none' : 'flex';
});

const fpsMonitor = vtkFPSMonitor.newInstance();
const fpsElm = fpsMonitor.getFpsMonitorContainer();
fpsElm.classList.add(style.fpsMonitor);

// ----------------------------------------------------------------------------
// Add class to body if iOS device
// ----------------------------------------------------------------------------

const iOS = /iPad|iPhone|iPod/.test(window.navigator.platform);

if (iOS) {
  document.querySelector('body').classList.add('is-ios-device');
}

// ----------------------------------------------------------------------------

function emptyContainer(container) {
  fpsMonitor.setContainer(null);
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
}

// ----------------------------------------------------------------------------

function createViewer(container) {
  const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
    background,
    rootContainer: container,
    containerStyle: { height: '100%', width: '100%', position: 'absolute' },
  });
  renderer = fullScreenRenderer.getRenderer();
  renderWindow = fullScreenRenderer.getRenderWindow();
  renderWindow.getInteractor().setDesiredUpdateRate(15);

  container.appendChild(rootControllerContainer);
  container.appendChild(addDataSetButton);

  if (userParams.fps) {
    fpsMonitor.setRenderWindow(renderWindow);
    fpsMonitor.setContainer(container);
    fullScreenRenderer.setResizeCallback(fpsMonitor.update);
  }
}

// ----------------------------------------------------------------------------

function createPipeline(fileName, fileContents) {
  // Create UI
  const presetSelector = document.createElement('select');
  presetSelector.setAttribute('class', selectorClass);
  presetSelector.innerHTML = vtkColorMaps.rgbPresetNames
    .map(
      (name) =>
        `<option value="${name}" ${
          lutName === name ? 'selected="selected"' : ''
        }>${name}</option>`
    )
    .join('');

  const representationSelector = document.createElement('select');
  representationSelector.setAttribute('class', selectorClass);
  representationSelector.innerHTML = [
    'Hidden',
    'Points',
    'Wireframe',
    'Surface',
    'Surface with Edge',
  ]
    .map(
      (name, idx) =>
        `<option value="${idx === 0 ? 0 : 1}:${idx < 4 ? idx - 1 : 2}:${
          idx === 4 ? 1 : 0
        }">${name}</option>`
    )
    .join('');
  representationSelector.value = '1:2:0';

  const colorBySelector = document.createElement('select');
  colorBySelector.setAttribute('class', selectorClass);

  const componentSelector = document.createElement('select');
  componentSelector.setAttribute('class', selectorClass);
  componentSelector.style.display = 'none';

  const opacitySelector = document.createElement('input');
  opacitySelector.setAttribute('class', selectorClass);
  opacitySelector.setAttribute('type', 'range');
  opacitySelector.setAttribute('value', '100');
  opacitySelector.setAttribute('max', '100');
  opacitySelector.setAttribute('min', '1');

  const labelSelector = document.createElement('label');
  labelSelector.setAttribute('class', selectorClass);
  labelSelector.innerHTML = fileName;

  const controlContainer = document.createElement('div');
  controlContainer.setAttribute('class', style.control);
  controlContainer.appendChild(labelSelector);
  controlContainer.appendChild(representationSelector);
  controlContainer.appendChild(presetSelector);
  controlContainer.appendChild(colorBySelector);
  controlContainer.appendChild(componentSelector);
  controlContainer.appendChild(opacitySelector);
  rootControllerContainer.appendChild(controlContainer);

  // VTK pipeline
  const vtpReader = vtkXMLPolyDataReader.newInstance();
  vtpReader.parseAsArrayBuffer(fileContents);

  const lookupTable = vtkColorTransferFunction.newInstance();
  const source = vtpReader.getOutputData(0);
  const mapper = vtkMapper.newInstance({
    interpolateScalarsBeforeMapping: false,
    useLookupTableScalarRange: true,
    lookupTable,
    scalarVisibility: false,
  });
  const actor = vtkActor.newInstance();
  const scalars = source.getPointData().getScalars();
  const dataRange = [].concat(scalars ? scalars.getRange() : [0, 1]);

  // --------------------------------------------------------------------
  // Color handling
  // --------------------------------------------------------------------

  function applyPreset() {
    const preset = vtkColorMaps.getPresetByName(presetSelector.value);
    lookupTable.applyColorMap(preset);
    lookupTable.setMappingRange(dataRange[0], dataRange[1]);
    lookupTable.updateRange();
  }
  applyPreset();
  presetSelector.addEventListener('change', applyPreset);

  // --------------------------------------------------------------------
  // Representation handling
  // --------------------------------------------------------------------

  function updateRepresentation(event) {
    const [
      visibility,
      representation,
      edgeVisibility,
    ] = event.target.value.split(':').map(Number);
    actor.getProperty().set({ representation, edgeVisibility });
    actor.setVisibility(!!visibility);
    renderWindow.render();
  }
  representationSelector.addEventListener('change', updateRepresentation);

  // --------------------------------------------------------------------
  // Opacity handling
  // --------------------------------------------------------------------

  function updateOpacity(event) {
    const opacity = Number(event.target.value) / 100;
    actor.getProperty().setOpacity(opacity);
    renderWindow.render();
  }

  opacitySelector.addEventListener('input', updateOpacity);

  // --------------------------------------------------------------------
  // ColorBy handling
  // --------------------------------------------------------------------

  const colorByOptions = [{ value: ':', label: 'Solid color' }].concat(
    source
      .getPointData()
      .getArrays()
      .map((a) => ({
        label: `(p) ${a.getName()}`,
        value: `PointData:${a.getName()}`,
      })),
    source
      .getCellData()
      .getArrays()
      .map((a) => ({
        label: `(c) ${a.getName()}`,
        value: `CellData:${a.getName()}`,
      }))
  );
  colorBySelector.innerHTML = colorByOptions
    .map(
      ({ label, value }) =>
        `<option value="${value}" ${
          field === value ? 'selected="selected"' : ''
        }>${label}</option>`
    )
    .join('');

  function updateColorBy(event) {
    const [location, colorByArrayName] = event.target.value.split(':');
    const interpolateScalarsBeforeMapping = location === 'PointData';
    let colorMode = ColorMode.DEFAULT;
    let scalarMode = ScalarMode.DEFAULT;
    const scalarVisibility = location.length > 0;
    if (scalarVisibility) {
      const activeArray = source[`get${location}`]().getArrayByName(
        colorByArrayName
      );
      const newDataRange = activeArray.getRange();
      dataRange[0] = newDataRange[0];
      dataRange[1] = newDataRange[1];
      colorMode = ColorMode.MAP_SCALARS;
      scalarMode =
        location === 'PointData'
          ? ScalarMode.USE_POINT_FIELD_DATA
          : ScalarMode.USE_CELL_FIELD_DATA;

      const numberOfComponents = activeArray.getNumberOfComponents();
      if (numberOfComponents > 1) {
        // always start on magnitude setting
        if (mapper.getLookupTable()) {
          const lut = mapper.getLookupTable();
          lut.setVectorModeToMagnitude();
        }
        componentSelector.style.display = 'block';
        const compOpts = ['Magnitude'];
        while (compOpts.length <= numberOfComponents) {
          compOpts.push(`Component ${compOpts.length}`);
        }
        componentSelector.innerHTML = compOpts
          .map((t, index) => `<option value="${index - 1}">${t}</option>`)
          .join('');
      } else {
        componentSelector.style.display = 'none';
      }
    } else {
      componentSelector.style.display = 'none';
    }
    mapper.set({
      colorByArrayName,
      colorMode,
      interpolateScalarsBeforeMapping,
      scalarMode,
      scalarVisibility,
    });
    applyPreset();
  }
  colorBySelector.addEventListener('change', updateColorBy);
  updateColorBy({ target: colorBySelector });

  function updateColorByComponent(event) {
    if (mapper.getLookupTable()) {
      const lut = mapper.getLookupTable();
      if (event.target.value === -1) {
        lut.setVectorModeToMagnitude();
      } else {
        lut.setVectorModeToComponent();
        lut.setVectorComponent(Number(event.target.value));
      }
      renderWindow.render();
    }
  }
  componentSelector.addEventListener('change', updateColorByComponent);

  // --------------------------------------------------------------------
  // Pipeline handling
  // --------------------------------------------------------------------

  actor.setMapper(mapper);
  mapper.setInputData(source);
  renderer.addActor(actor);

  // Manage update when lookupTable change
  lookupTable.onModified(() => {
    renderWindow.render();
  });

  // First render
  renderer.resetCamera();
  renderWindow.render();

  global.pipeline[fileName] = {
    actor,
    mapper,
    source,
    lookupTable,
    renderer,
    renderWindow,
  };

  // Update stats
  fpsMonitor.update();
}

// ----------------------------------------------------------------------------

function loadFile(file) {
  const reader = new FileReader();
  reader.onload = function onLoad(e) {
    createPipeline(file.name, reader.result);
  };
  reader.readAsArrayBuffer(file);
}

// ----------------------------------------------------------------------------

export function load(container, options) {
  autoInit = false;
  emptyContainer(container);

  if (options.files) {
    createViewer(container);
    let count = options.files.length;
    while (count--) {
      loadFile(options.files[count]);
    }
    updateCamera(renderer.getActiveCamera());
  } else if (options.fileURL) {
    const progressContainer = document.createElement('div');
    progressContainer.setAttribute('class', style.progress);
    container.appendChild(progressContainer);

    const progressCallback = (progressEvent) => {
      const percent = Math.floor(
        100 * progressEvent.loaded / progressEvent.total
      );
      progressContainer.innerHTML = `Loading ${percent}%`;
    };

    HttpDataAccessHelper.fetchBinary(options.fileURL, {
      progressCallback,
    }).then((binary) => {
      container.removeChild(progressContainer);
      createViewer(container);
      createPipeline(defaultName, binary);
      updateCamera(renderer.getActiveCamera());
    });
  }
}

export function initLocalFileLoader(container) {
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = container || exampleContainer || rootBody;

  if (myContainer !== container) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  } else {
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const fileContainer = document.createElement('div');
  fileContainer.innerHTML = `<div class="${
    style.bigFileDrop
  }"/><input type="file" multiple accept=".vtp" style="display: none;"/>`;
  myContainer.appendChild(fileContainer);

  const fileInput = fileContainer.querySelector('input');

  function handleFile(e) {
    preventDefaults(e);
    const dataTransfer = e.dataTransfer;
    const files = e.target.files || dataTransfer.files;
    if (files.length > 0) {
      myContainer.removeChild(fileContainer);
      load(myContainer, { files });
    }
  }

  fileInput.addEventListener('change', handleFile);
  fileContainer.addEventListener('drop', handleFile);
  fileContainer.addEventListener('click', (e) => fileInput.click());
  fileContainer.addEventListener('dragover', preventDefaults);
}

// Look at URL an see if we should load a file
// ?fileURL=https://data.kitware.com/api/v1/item/59cdbb588d777f31ac63de08/download
if (userParams.url || userParams.fileURL) {
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = exampleContainer || rootBody;

  if (myContainer) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  load(myContainer, userParams);
}

// Auto setup if no method get called within 100ms
setTimeout(() => {
  if (autoInit) {
    initLocalFileLoader();
  }
}, 100);
<commit_msg>doc(GeometryViewer): Update example for better fps control<commit_after>/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-extraneous-dependencies */

import 'vtk.js/Sources/favicon';

import HttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkColorMaps from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction/ColorMaps';
import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract';
import vtkXMLPolyDataReader from 'vtk.js/Sources/IO/XML/XMLPolyDataReader';
import vtkFPSMonitor from 'vtk.js/Sources/Interaction/UI/FPSMonitor';

import {
  ColorMode,
  ScalarMode,
} from 'vtk.js/Sources/Rendering/Core/Mapper/Constants';

import style from './GeometryViewer.mcss';
import icon from '../../../Documentation/content/icon/favicon-96x96.png';

let autoInit = true;
let background = [0, 0, 0];
let renderWindow;
let renderer;

global.pipeline = {};

// Process arguments from URL
const userParams = vtkURLExtract.extractURLParameters();

// Background handling
if (userParams.background) {
  background = userParams.background.split(',').map((s) => Number(s));
}
const selectorClass =
  background.length === 3 && background.reduce((a, b) => a + b, 0) < 1.5
    ? style.dark
    : style.light;

// name
const defaultName = userParams.name || '';

// lut
const lutName = userParams.lut || 'erdc_rainbow_bright';

// field
const field = userParams.field || '';

// camera
function updateCamera(camera) {
  ['zoom', 'pitch', 'elevation', 'yaw', 'azimuth', 'roll', 'dolly'].forEach(
    (key) => {
      if (userParams[key]) {
        camera[key](userParams[key]);
      }
      renderWindow.render();
    }
  );
}

function preventDefaults(e) {
  e.preventDefault();
  e.stopPropagation();
}

// ----------------------------------------------------------------------------
// DOM containers for UI control
// ----------------------------------------------------------------------------

const rootControllerContainer = document.createElement('div');
rootControllerContainer.setAttribute('class', style.rootController);

const addDataSetButton = document.createElement('img');
addDataSetButton.setAttribute('class', style.button);
addDataSetButton.setAttribute('src', icon);
addDataSetButton.addEventListener('click', () => {
  const isVisible = rootControllerContainer.style.display !== 'none';
  rootControllerContainer.style.display = isVisible ? 'none' : 'flex';
});

const fpsMonitor = vtkFPSMonitor.newInstance();
const fpsElm = fpsMonitor.getFpsMonitorContainer();
fpsElm.classList.add(style.fpsMonitor);

// ----------------------------------------------------------------------------
// Add class to body if iOS device
// ----------------------------------------------------------------------------

const iOS = /iPad|iPhone|iPod/.test(window.navigator.platform);

if (iOS) {
  document.querySelector('body').classList.add('is-ios-device');
}

// ----------------------------------------------------------------------------

function emptyContainer(container) {
  fpsMonitor.setContainer(null);
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
}

// ----------------------------------------------------------------------------

function createViewer(container) {
  const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
    background,
    rootContainer: container,
    containerStyle: { height: '100%', width: '100%', position: 'absolute' },
  });
  renderer = fullScreenRenderer.getRenderer();
  renderWindow = fullScreenRenderer.getRenderWindow();
  renderWindow.getInteractor().setDesiredUpdateRate(15);

  container.appendChild(rootControllerContainer);
  container.appendChild(addDataSetButton);

  if (userParams.fps) {
    if (Array.isArray(userParams.fps)) {
      fpsMonitor.setMonitorVisibility(...userParams.fps);
      if (userParams.fps.length === 4) {
        fpsMonitor.setOrientation(userParams.fps[3]);
      }
    }
    fpsMonitor.setRenderWindow(renderWindow);
    fpsMonitor.setContainer(container);
    fullScreenRenderer.setResizeCallback(fpsMonitor.update);
  }
}

// ----------------------------------------------------------------------------

function createPipeline(fileName, fileContents) {
  // Create UI
  const presetSelector = document.createElement('select');
  presetSelector.setAttribute('class', selectorClass);
  presetSelector.innerHTML = vtkColorMaps.rgbPresetNames
    .map(
      (name) =>
        `<option value="${name}" ${
          lutName === name ? 'selected="selected"' : ''
        }>${name}</option>`
    )
    .join('');

  const representationSelector = document.createElement('select');
  representationSelector.setAttribute('class', selectorClass);
  representationSelector.innerHTML = [
    'Hidden',
    'Points',
    'Wireframe',
    'Surface',
    'Surface with Edge',
  ]
    .map(
      (name, idx) =>
        `<option value="${idx === 0 ? 0 : 1}:${idx < 4 ? idx - 1 : 2}:${
          idx === 4 ? 1 : 0
        }">${name}</option>`
    )
    .join('');
  representationSelector.value = '1:2:0';

  const colorBySelector = document.createElement('select');
  colorBySelector.setAttribute('class', selectorClass);

  const componentSelector = document.createElement('select');
  componentSelector.setAttribute('class', selectorClass);
  componentSelector.style.display = 'none';

  const opacitySelector = document.createElement('input');
  opacitySelector.setAttribute('class', selectorClass);
  opacitySelector.setAttribute('type', 'range');
  opacitySelector.setAttribute('value', '100');
  opacitySelector.setAttribute('max', '100');
  opacitySelector.setAttribute('min', '1');

  const labelSelector = document.createElement('label');
  labelSelector.setAttribute('class', selectorClass);
  labelSelector.innerHTML = fileName;

  const controlContainer = document.createElement('div');
  controlContainer.setAttribute('class', style.control);
  controlContainer.appendChild(labelSelector);
  controlContainer.appendChild(representationSelector);
  controlContainer.appendChild(presetSelector);
  controlContainer.appendChild(colorBySelector);
  controlContainer.appendChild(componentSelector);
  controlContainer.appendChild(opacitySelector);
  rootControllerContainer.appendChild(controlContainer);

  // VTK pipeline
  const vtpReader = vtkXMLPolyDataReader.newInstance();
  vtpReader.parseAsArrayBuffer(fileContents);

  const lookupTable = vtkColorTransferFunction.newInstance();
  const source = vtpReader.getOutputData(0);
  const mapper = vtkMapper.newInstance({
    interpolateScalarsBeforeMapping: false,
    useLookupTableScalarRange: true,
    lookupTable,
    scalarVisibility: false,
  });
  const actor = vtkActor.newInstance();
  const scalars = source.getPointData().getScalars();
  const dataRange = [].concat(scalars ? scalars.getRange() : [0, 1]);

  // --------------------------------------------------------------------
  // Color handling
  // --------------------------------------------------------------------

  function applyPreset() {
    const preset = vtkColorMaps.getPresetByName(presetSelector.value);
    lookupTable.applyColorMap(preset);
    lookupTable.setMappingRange(dataRange[0], dataRange[1]);
    lookupTable.updateRange();
  }
  applyPreset();
  presetSelector.addEventListener('change', applyPreset);

  // --------------------------------------------------------------------
  // Representation handling
  // --------------------------------------------------------------------

  function updateRepresentation(event) {
    const [
      visibility,
      representation,
      edgeVisibility,
    ] = event.target.value.split(':').map(Number);
    actor.getProperty().set({ representation, edgeVisibility });
    actor.setVisibility(!!visibility);
    renderWindow.render();
  }
  representationSelector.addEventListener('change', updateRepresentation);

  // --------------------------------------------------------------------
  // Opacity handling
  // --------------------------------------------------------------------

  function updateOpacity(event) {
    const opacity = Number(event.target.value) / 100;
    actor.getProperty().setOpacity(opacity);
    renderWindow.render();
  }

  opacitySelector.addEventListener('input', updateOpacity);

  // --------------------------------------------------------------------
  // ColorBy handling
  // --------------------------------------------------------------------

  const colorByOptions = [{ value: ':', label: 'Solid color' }].concat(
    source
      .getPointData()
      .getArrays()
      .map((a) => ({
        label: `(p) ${a.getName()}`,
        value: `PointData:${a.getName()}`,
      })),
    source
      .getCellData()
      .getArrays()
      .map((a) => ({
        label: `(c) ${a.getName()}`,
        value: `CellData:${a.getName()}`,
      }))
  );
  colorBySelector.innerHTML = colorByOptions
    .map(
      ({ label, value }) =>
        `<option value="${value}" ${
          field === value ? 'selected="selected"' : ''
        }>${label}</option>`
    )
    .join('');

  function updateColorBy(event) {
    const [location, colorByArrayName] = event.target.value.split(':');
    const interpolateScalarsBeforeMapping = location === 'PointData';
    let colorMode = ColorMode.DEFAULT;
    let scalarMode = ScalarMode.DEFAULT;
    const scalarVisibility = location.length > 0;
    if (scalarVisibility) {
      const activeArray = source[`get${location}`]().getArrayByName(
        colorByArrayName
      );
      const newDataRange = activeArray.getRange();
      dataRange[0] = newDataRange[0];
      dataRange[1] = newDataRange[1];
      colorMode = ColorMode.MAP_SCALARS;
      scalarMode =
        location === 'PointData'
          ? ScalarMode.USE_POINT_FIELD_DATA
          : ScalarMode.USE_CELL_FIELD_DATA;

      const numberOfComponents = activeArray.getNumberOfComponents();
      if (numberOfComponents > 1) {
        // always start on magnitude setting
        if (mapper.getLookupTable()) {
          const lut = mapper.getLookupTable();
          lut.setVectorModeToMagnitude();
        }
        componentSelector.style.display = 'block';
        const compOpts = ['Magnitude'];
        while (compOpts.length <= numberOfComponents) {
          compOpts.push(`Component ${compOpts.length}`);
        }
        componentSelector.innerHTML = compOpts
          .map((t, index) => `<option value="${index - 1}">${t}</option>`)
          .join('');
      } else {
        componentSelector.style.display = 'none';
      }
    } else {
      componentSelector.style.display = 'none';
    }
    mapper.set({
      colorByArrayName,
      colorMode,
      interpolateScalarsBeforeMapping,
      scalarMode,
      scalarVisibility,
    });
    applyPreset();
  }
  colorBySelector.addEventListener('change', updateColorBy);
  updateColorBy({ target: colorBySelector });

  function updateColorByComponent(event) {
    if (mapper.getLookupTable()) {
      const lut = mapper.getLookupTable();
      if (event.target.value === -1) {
        lut.setVectorModeToMagnitude();
      } else {
        lut.setVectorModeToComponent();
        lut.setVectorComponent(Number(event.target.value));
      }
      renderWindow.render();
    }
  }
  componentSelector.addEventListener('change', updateColorByComponent);

  // --------------------------------------------------------------------
  // Pipeline handling
  // --------------------------------------------------------------------

  actor.setMapper(mapper);
  mapper.setInputData(source);
  renderer.addActor(actor);

  // Manage update when lookupTable change
  lookupTable.onModified(() => {
    renderWindow.render();
  });

  // First render
  renderer.resetCamera();
  renderWindow.render();

  global.pipeline[fileName] = {
    actor,
    mapper,
    source,
    lookupTable,
    renderer,
    renderWindow,
  };

  // Update stats
  fpsMonitor.update();
}

// ----------------------------------------------------------------------------

function loadFile(file) {
  const reader = new FileReader();
  reader.onload = function onLoad(e) {
    createPipeline(file.name, reader.result);
  };
  reader.readAsArrayBuffer(file);
}

// ----------------------------------------------------------------------------

export function load(container, options) {
  autoInit = false;
  emptyContainer(container);

  if (options.files) {
    createViewer(container);
    let count = options.files.length;
    while (count--) {
      loadFile(options.files[count]);
    }
    updateCamera(renderer.getActiveCamera());
  } else if (options.fileURL) {
    const progressContainer = document.createElement('div');
    progressContainer.setAttribute('class', style.progress);
    container.appendChild(progressContainer);

    const progressCallback = (progressEvent) => {
      const percent = Math.floor(
        100 * progressEvent.loaded / progressEvent.total
      );
      progressContainer.innerHTML = `Loading ${percent}%`;
    };

    HttpDataAccessHelper.fetchBinary(options.fileURL, {
      progressCallback,
    }).then((binary) => {
      container.removeChild(progressContainer);
      createViewer(container);
      createPipeline(defaultName, binary);
      updateCamera(renderer.getActiveCamera());
    });
  }
}

export function initLocalFileLoader(container) {
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = container || exampleContainer || rootBody;

  if (myContainer !== container) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  } else {
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const fileContainer = document.createElement('div');
  fileContainer.innerHTML = `<div class="${
    style.bigFileDrop
  }"/><input type="file" multiple accept=".vtp" style="display: none;"/>`;
  myContainer.appendChild(fileContainer);

  const fileInput = fileContainer.querySelector('input');

  function handleFile(e) {
    preventDefaults(e);
    const dataTransfer = e.dataTransfer;
    const files = e.target.files || dataTransfer.files;
    if (files.length > 0) {
      myContainer.removeChild(fileContainer);
      load(myContainer, { files });
    }
  }

  fileInput.addEventListener('change', handleFile);
  fileContainer.addEventListener('drop', handleFile);
  fileContainer.addEventListener('click', (e) => fileInput.click());
  fileContainer.addEventListener('dragover', preventDefaults);
}

// Look at URL an see if we should load a file
// ?fileURL=https://data.kitware.com/api/v1/item/59cdbb588d777f31ac63de08/download
if (userParams.url || userParams.fileURL) {
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = exampleContainer || rootBody;

  if (myContainer) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  load(myContainer, userParams);
}

// Auto setup if no method get called within 100ms
setTimeout(() => {
  if (autoInit) {
    initLocalFileLoader();
  }
}, 100);
<|endoftext|>


<commit_before>var Actor = Vexr.Actor;
var Vector3 = Vexr.Vector3;
var Generate = Vexr.Generate;
var UUID = new RegExp("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
describe('Actor', function () {
    it("New Actor has initialized properties", function () {
        var actor = new Actor();
        assert.equal(actor.type, "Actor");
        assert.equal(actor.active, true);
        assert.equal(actor.visible, true);
        assert.equal(actor.dead, false);
        assert.equal(UUID.test(actor.id), true);
        assert.equal(actor.location instanceof Vector3, true);
        assert.equal(actor.velocity instanceof Vector3, true);
        assert.equal(actor.acceleration instanceof Vector3, true);
        assert.equal(actor.angle, 0);
        assert.equal(actor.maxSpeed, 15);
        assert.equal(actor.maxForce, 1);
    });
    it("Adding a force applies it to acceleration", function(){
        for(var i = 0; i < 1000; i++) {
            var actor = new Actor();
            var accel = Math.random() * 1000;
            var v = new Vector3(accel, accel, accel);
            actor.addForce(v);
            assert.equal(actor.acceleration.x, accel);
            assert.equal(actor.acceleration.y, accel);
            assert.equal(actor.acceleration.z, accel);
        }
    });
    it("Updating applies acceleration and resets", function(){
        for(var i = 0; i < 1000; i++) {
            var actor = new Actor();
            var accel = Math.random() * 1000;
            var v = new Vector3(accel, accel, accel);
            actor.addForce(v);
            actor.update(v);
            assert.equal(actor.velocity.x, accel);
            assert.equal(actor.velocity.y, accel);
            assert.equal(actor.velocity.z, accel);
            assert.equal(actor.location.x, accel);
            assert.equal(actor.location.y, accel);
            assert.equal(actor.location.z, accel);
            assert.equal(actor.acceleration.x, 0);
            assert.equal(actor.acceleration.y, 0);
            assert.equal(actor.acceleration.z, 0);
        }
    });
    it("Parameters get set", function(){
        for(var i = 0; i < 1000; i++) {
            var name = Generate.UUID();
            var accel = Math.random() * 1000;
            var actor = new Actor(name, new Vector3(accel, accel, accel));
            assert.equal(actor.location.x, accel);
            assert.equal(actor.location.y, accel);
            assert.equal(actor.location.z, accel);
            assert.equal(actor.type, name);
        }
    });
    it("Destroy Sets this.dead to true for self and all it's children", function(){
        for(var i = 0; i < 1000; i++) {
            var actor = new Actor();
            assert.equal(actor.dead, false);
            actor.destroy();
            assert.equal(actor.dead, true);
        }
    });
});<commit_msg>Updated Actor tests to take into account small precision inconsistencies.<commit_after>var Actor = Vexr.Actor;
var Vector3 = Vexr.Vector3;
var Generate = Vexr.Generate;
var UUID = new RegExp("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
describe('Actor', function () {
    it("New Actor has initialized properties", function () {
        var actor = new Actor();
        assert.equal(actor.type, "Actor");
        assert.equal(actor.active, true);
        assert.equal(actor.visible, true);
        assert.equal(actor.dead, false);
        assert.equal(UUID.test(actor.id), true);
        assert.equal(actor.location instanceof Vector3, true);
        assert.equal(actor.velocity instanceof Vector3, true);
        assert.equal(actor.acceleration instanceof Vector3, true);
        assert.equal(actor.angle, 0);
        assert.equal(actor.maxSpeed, 15);
        assert.equal(actor.maxForce, 1);
    });
    it("Adding a force applies it to acceleration", function () {
        for (var i = 0; i < 1000; i++) {
            var actor = new Actor();
            var accel = new Float32Array([Math.random() * 1000]);
            accel = accel[0];
            var v = new Vector3(accel, accel, accel);
            actor.addForce(v);
            assert.equal(Math.abs(actor.acceleration.x), Math.abs(accel));
            assert.equal(Math.abs(actor.acceleration.y), Math.abs(accel));
            assert.equal(Math.abs(actor.acceleration.z), Math.abs(accel));
        }
    });
    it("Updating applies acceleration and resets", function () {
        for (var i = 0; i < 1000; i++) {
            var actor = new Actor();
            var accel = Math.round(Math.random() * 1000);
            var v = new Vector3(accel, accel, accel);
            actor.addForce(v);
            actor.update(v);
            assert.equal(Math.abs(actor.velocity.x), Math.abs(accel));
            assert.equal(Math.abs(actor.velocity.y), Math.abs(accel));
            assert.equal(Math.abs(actor.velocity.z), Math.abs(accel));
            assert.equal(Math.abs(actor.location.x), Math.abs(accel));
            assert.equal(Math.abs(actor.location.y), Math.abs(accel));
            assert.equal(Math.abs(actor.location.z), Math.abs(accel));
            assert.equal(actor.acceleration.x, 0);
            assert.equal(actor.acceleration.y, 0);
            assert.equal(actor.acceleration.z, 0);
        }
    });
    it("Parameters get set", function () {
        for (var i = 0; i < 1000; i++) {
            var name = Generate.UUID();
            var accel = new Float32Array([Math.round(Math.random() * 1000)]);
            var actor = new Actor(name, new Vector3(accel[0], accel[0], accel[0]));
            assert.equal(actor.location.x, accel[0]);
            assert.equal(actor.location.y, accel[0]);
            assert.equal(actor.location.z, accel[0]);
            assert.equal(actor.type, name);
        }
    });
    it("Destroy Sets this.dead to true for self and all it's children", function () {
        for (var i = 0; i < 1000; i++) {
            var actor = new Actor();
            assert.equal(actor.dead, false);
            actor.destroy();
            assert.equal(actor.dead, true);
        }
    });
});<|endoftext|>