/*! DSFR v1.11.2 | SPDX-License-Identifier: MIT | License-Filename: LICENSE.md | restricted use (see terms and conditions) */

const config = {
  prefix: 'fr',
  namespace: 'dsfr',
  organisation: '@gouvfr',
  version: '1.11.2'
};

const api = window[config.namespace];

const patch = {
  namespace: 'a4e35ba2a938ba9d007689dbf3f46acbb9807869'
};

const Collection = {
  MANUAL: 'manual',
  LOAD: 'load',
  FULL: 'full',
  HASH: 'hash'
};

const key = '_EA_';
const DISABLED = `${key}disabled`;
const TOGGLE = `${key}toggle`;

class Opt {
  constructor () {
    this._configure();
  }

  _configure () {
    const scope = this;
    window[DISABLED] = () => scope.isDisabled;
    window[TOGGLE] = this.toggle.bind(this);
  }

  get isDisabled () {
    return localStorage.getItem(key);
  }

  toggle () {
    if (this.isDisabled) this.enable();
    else this.disable();
  }

  enable () {
    if (localStorage.getItem(key)) {
      localStorage.removeItem(key);
    }
  }

  disable () {
    localStorage.setItem(key, '1');
  }
}

const opt = new Opt();

const PUSH = 'EA_push';

class Init {
  constructor (domain) {
    this._domain = domain;
    this._isLoaded = false;
    this._promise = new Promise((resolve, reject) => {
      this._resolve = resolve;
      this._reject = reject;
    });
  }

  get id () {
    return this._id;
  }

  get store () {
    return this._store;
  }

  configure () {
    this.init();
    return this._promise;
  }

  init () {
    let bit = 5381;
    for (let i = this._domain.length - 1; i > 0; i--) bit = (bit * 33) ^ this._domain.charCodeAt(i);
    bit >>>= 0;
    this._id = `_EA_${bit}`;

    this._store = [];
    this._store.eah = this._domain;
    window[this._id] = this._store;

    if (!window[PUSH]) window[PUSH] = (...args) => this.store.push(args);

    if (opt.isDisabled) {
      api.inspector.warn('User opted out, eulerian is disabled');
      this._reject('User opted out, eulerian is disabled');
    } else this.load();
  }

  load () {
    const stamp = new Date() / 1E7 | 0;
    const offset = stamp % 26;
    const key = String.fromCharCode(97 + offset, 122 - offset, 65 + offset) + (stamp % 1E3);
    this._script = document.createElement('script');
    this._script.ea = this.id;
    this._script.async = true;
    this._script.addEventListener('load', this.loaded.bind(this));
    this._script.addEventListener('error', this.error.bind(this));
    this._script.src = `//${this._domain}/${key}.js?2`;
    const node = document.getElementsByTagName('script')[0];
    node.parentNode.insertBefore(this._script, node);
  }

  error () {
    api.inspector.error('unable to load Eulerian script file. the domain declared in your configuration must match the domain provided by the Eulerian interface (tag creation)');
    this._reject('eulerian script loading error');
  }

  loaded () {
    if (this._isLoaded) return;
    this._isLoaded = true;
    this._resolve();
  }
}

/*
(function(e, a) {
  var i = e.length,
    y = 5381,
    k = 'script',
    s = window,
    v = document,
    o = v.createElement(k);
  for (; i;) {
    i -= 1;
    y = (y * 33) ^ e.charCodeAt(i)
  }
  y = '_EA_' + (y >>>= 0);
  (function(e, a, s, y) {
    s[a] = s[a] || function() {
      (s[y] = s[y] || []).push(arguments);
      s[y].eah = e;
    };
  }(e, a, s, y));
  i = new Date / 1E7 | 0;
  o.ea = y;
  y = i % 26;
  o.async = 1;
  o.src = '//' + e + '/' + String.fromCharCode(97 + y, 122 - y, 65 + y) + (i % 1E3) + '.js?2';
  s = v.getElementsByTagName(k)[0];
  s.parentNode.insertBefore(o, s);
})
('mon.domainedetracking.com', 'EA_push');
*/

/*
(function(e, a) {
  var i = e.length,
    y = 5381,
    k = 'script',
    z = '_EA_',
    zd = z + 'disabled',
    s = window,
    v = document,
    o = v.createElement(k),
    l = s.localStorage;
  for (; i;) {
    i -= 1;
    y = (y * 33) ^ e.charCodeAt(i)
  }
  y = z + (y >>>= 0);
  (function(e, a, s, y, z, zd, l) {
    s[a] = s[a] || function() {
      (s[y] = s[y] || []).push(arguments);
      s[y].eah = e;
    };
    s[zd] = function() {
      return l.getItem(z);
    };
    s[z + 'toggle'] = function() {
      (s[zd]()) ? l.removeItem(z): l.setItem(z, 1);
    }
  }(e, a, s, y, z, zd, l));
  if (!s[zd]()) {
    i = new Date / 1E7 | 0;
    o.ea = y;
    y = i % 26;
    o.async = 1;
    o.src = '//' + e + '/' + String.fromCharCode(97 + y, 122 - y, 65 + y) + (i % 1E3) + '.js?2';
    s = v.getElementsByTagName(k)[0];
    s.parentNode.insertBefore(o, s);
  }
})('mon.domainedetracking.com', 'EA_push');
*/

const State = {
  UNKNOWN: -1,
  CONFIGURING: 0,
  CONFIGURED: 1,
  INITIATED: 2,
  READY: 3
};

class TarteAuCitronIntegration {
  constructor (config) {
    this._config = config;
    this._state = State.UNKNOWN;
    this._promise = new Promise((resolve, reject) => {
      this._resolve = resolve;
      this._reject = reject;
    });
  }

  configure () {
    if (this._state >= State.CONFIGURED) return this._promise;
    if (this._state === State.UNKNOWN) {
      api.inspector.info('analytics configures tarteaucitron');
      this._state = State.CONFIGURING;
    }

    const tarteaucitron = window.tarteaucitron;
    if (!tarteaucitron || !tarteaucitron.services) {
      window.requestAnimationFrame(this.configure.bind(this));
      return;
    }

    this._state = State.CONFIGURED;
    const init = this.init.bind(this);

    const data = {
      key: 'eulerian',
      type: 'analytic',
      name: 'Eulerian Analytics',
      needConsent: true,
      cookies: ['etuix'],
      uri: 'https://eulerian.com/vie-privee',
      js: init,
      fallback: () => { tarteaucitron.services.eulerian.js(); }
    };

    tarteaucitron.services.eulerian = data;
    if (!tarteaucitron.job) tarteaucitron.job = [];
    tarteaucitron.job.push('eulerian');

    return this._promise;
  }

  init () {
    if (this._state >= State.INITIATED) return;
    this._state = State.INITIATED;
    window.__eaGenericCmpApi = this.integrate.bind(this);
    const update = this.update.bind(this);
    window.addEventListener('tac.close_alert', update);
    window.addEventListener('tac.close_panel', update);
  }

  integrate (cmpApi) {
    if (this._state >= State.READY) return;
    this._state = State.READY;
    this._cmpApi = cmpApi;

    api.inspector.info('analytics has integrated tarteaucitron');

    this._resolve();
    this.update();
  }

  update () {
    if (this._state < State.READY) return;
    this._cmpApi('tac', window.tarteaucitron, 1);
  }
}

class ConsentManagerPlatform {
  constructor (config) {
    this._config = config;

    if (config) {
      switch (config.id) {
        case 'tarteaucitron':
          this.integrateTarteAuCitron();
          break;
      }
    }
  }

  integrateTarteAuCitron () {
    this._tac = new TarteAuCitronIntegration(this._config);
    return this._tac.configure();
  }

  optin () {

  }
}

const push = (type, layer) => {
  if (typeof window.EA_push !== 'function') {
    api.inspector.warn('Analytics datalayer not sent, Eulerian API isn\'t yet avalaible');
    return;
  }

  api.inspector.info('analytics', type, layer);

  window.EA_push(type, layer);
};

const PushType = {
  COLLECTOR: 'collector',
  ACTION: 'action',
  ACTION_PARAMETER: 'actionparam'
};

class Renderer {
  constructor () {
    this._renderables = [];
    this._rendering = this.render.bind(this);
    requestAnimationFrame(this._rendering);
  }

  add (renderable) {
    const index = this._renderables.indexOf(renderable);
    if (index === -1) this._renderables.push(renderable);
  }

  remove (renderable) {
    const index = this._renderables.indexOf(renderable);
    if (index > -1) this._renderables.splice(index, 1);
  }

  render () {
    this._renderables.forEach(renderable => renderable.render());
    requestAnimationFrame(this._rendering);
  }
}

const renderer = new Renderer();

const SLICE = 80;

class Queue {
  constructor () {
    this._startingActions = [];
    this._endingActions = [];
    this._handlingVisibilityChange = this._handleVisibilityChange.bind(this);
    this._handlingEnd = this._handleEnd.bind(this);
    this._isStarted = false;
    this._isListening = false;
    this.reset();
  }

  setCollector (collector) {
    this._collector = collector;
  }

  reset (ending = false) {
    this._type = PushType.ACTION;
    if (!ending) this._startingActions.length = 0;
    this._endingActions.length = 0;
    this._count = 0;
    this._delay = -1;
    this._isRequested = false;
    this._unlisten();
  }

  start () {
    if (this._isStarted) return;
    this._isStarted = true;
    renderer.add(this);
  }

  collect () {
    this._type = PushType.COLLECTOR;
    this._request();
  }

  appendStartingAction (action, data) {
    if (!this._collector.isActionEnabled && !action.isForced) return;
    if (!action || this._startingActions.some(queued => queued.test(action))) {
      api.inspector.log('appendStartingAction exists or null', action);
      return;
    }
    const queued = new QueuedAction(action, data);
    this._startingActions.push(queued);
    this._request();
  }

  appendEndingAction (action, data) {
    if (!this._collector.isActionEnabled && !action.isForced) return;
    if (!action || this._endingActions.some(queued => queued.test(action))) {
      api.inspector.log('appendEndingAction exists or null', action);
      return;
    }
    const queued = new QueuedAction(action, data);
    this._endingActions.push(queued);
    this._request();
  }

  _request () {
    this._listen();
    this._isRequested = true;
    this._delay = 4;
  }

  _listen () {
    if (this._isListening) return;
    this._isListening = true;
    document.addEventListener('visibilitychange', this._handlingVisibilityChange);
    document.addEventListener('unload', this._handlingEnd);
    document.addEventListener('beforeunload', this._handlingEnd);
    document.addEventListener('pagehide', this._handlingEnd);
  }

  _unlisten () {
    if (!this._isListening) return;
    this._isListening = false;
    document.removeEventListener('visibilitychange', this._handlingVisibilityChange);
    document.removeEventListener('unload', this._handlingEnd);
    document.removeEventListener('beforeunload', this._handlingEnd);
    document.removeEventListener('pagehide', this._handlingEnd);
  }

  _handleVisibilityChange (e) {
    if (document.visibilityState === 'hidden') this.send();
  }

  _handleEnd () {
    this.send();
  }

  render () {
    if (this._delay <= -1) return;
    this._delay--;
    this._count++;
    switch (true) {
      case this._count > 20:
      case this._delay === 0:
        this.send();
        break;
    }
  }

  send (ending = false) {
    if (!this._isRequested) return;
    const actionLayers = [];
    if (!ending) actionLayers.push(...this._startingActions.map(queued => queued.start()).filter(layer => layer.length > 0));
    actionLayers.push(...this._endingActions.map(queued => queued.end()).filter(layer => layer.length > 0));

    const length = ((actionLayers.length / SLICE) + 1) | 0;
    const slices = [];
    for (let i = 0; i < length; i++) {
      const slice = actionLayers.slice(i * SLICE, (i + 1) * SLICE);
      slices.push(slice.flat());
    }

    if (this._type === PushType.COLLECTOR && this._collector.isCollecting) {
      const layer = this._collector.layer;
      if (slices.length > 0) {
        const slice = slices.splice(0, 1)[0];
        if (slice.length > 0) layer.push.apply(layer, slice);
      }
      layer.flat();
      if (layer.length > 0) push(PushType.COLLECTOR, layer);
    }

    if (slices.length > 0) {
      for (let i = 0; i < slices.length; i++) {
        const slice = slices[i];
        if (slice.length > 0) push(PushType.ACTION, slice);
      }
    }

    this.reset(ending);
  }
}

class QueuedAction {
  constructor (action, data) {
    this._action = action;
    this._data = data;
  }

  test (action) {
    return this._action === action;
  }

  start () {
    return this._action.start(this._data);
  }

  end () {
    return this._action.end(this._data);
  }
}

const queue = new Queue();

class Debug {
  get debugger () {
    return window._oEa;
  }

  get isActive () {
    if (!this.debugger) return false;
    return this.debugger._dbg === '1';
  }

  set isActive (value) {
    if (!this.debugger || this.isActive === value) return;
    this.debugger.debug(value ? 1 : 0);
  }
}

const debug = new Debug();

const Status = {
  CONNECTED: {
    id: 'connected',
    value: 'connecté',
    isConnected: true,
    isDefault: true
  },
  ANONYMOUS: {
    id: 'anonymous',
    value: 'anonyme',
    isConnected: false,
    isDefault: true
  },
  GUEST: {
    id: 'guest',
    value: 'invité',
    isConnected: false
  }
};

const Type$2 = {
  INDIVIDUAL: {
    id: 'individual',
    value: 'part'
  },
  PROFESSIONNAL: {
    id: 'professionnal',
    value: 'pro'
  }
};

/*  '["\'<>*$&~`|\\\\?^~]'; */
var RESTRICTED = {
  '0x0022': '＂',
  '0x0024': '＄',
  '0x0026': '＆',
  '0x0027': '＇',
  '0x002a': '＊',
  '0x002c': '，',
  '0x003c': '＜',
  '0x003e': '＞',
  '0x003f': '？',
  '0x005c': '＼',
  '0x005e': '＾',
  '0x0060': '｀',
  '0x007c': '｜',
  '0x007e': '～'
};

// import TABLE from './unicode-table';

const charCodeHex = (char) => {
  const code = char.charCodeAt(0).toString(16);
  return '0x0000'.slice(0, -code.length) + code;
};

const normalize = (text) => {
  if (!text) return text;
  // text = [...text].map(char => TABLE[charCodeHex(char)] || char).join('');
  text = [...text].map(char => RESTRICTED[charCodeHex(char)] || char).join('');
  text = text.replace(/\s+/g, ' ').replace(/\s/g, '_');
  text = text.toLowerCase();
  return text;
};

const validateString = (value, name, allowNull = true) => {
  switch (true) {
    case typeof value === 'number':
      return `${value}`;

    case typeof value === 'string':
      return value;

    case value === undefined && allowNull:
    case value === null && allowNull:
      return '';
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting a String`);
  return null;
};

const validateNumber = (value, name, allowNull = true) => {
  switch (true) {
    case !isNaN(value):
      return value;

    case typeof value === 'string' && !isNaN(Number(value)):
      return Number(value);

    case value === undefined && allowNull:
    case value === null && allowNull:
      return -1;
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting a Number`);
  return null;
};

const validateBoolean = (value, name) => {
  switch (true) {
    case typeof value === 'boolean':
      return value;

    case typeof value === 'string' && value.toLowerCase() === 'true':
    case value === '1':
    case value === 1:
      return true;

    case typeof value === 'string' && value.toLowerCase() === 'false':
    case value === '0':
    case value === 0:
      return false;

    case value === undefined:
    case value === null:
      return value;
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting a Boolean`);
  return null;
};

const validateLang = (value, name, allowNull = true) => {
  switch (true) {
    case typeof value === 'string' && /^[A-Za-z]{2}$|^[A-Za-z]{2}[-_]/.test(value):
      return value.split(/[-_]/)[0].toLowerCase();

    case value === undefined && allowNull:
    case value === null && allowNull:
      return '';
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting language as a String following ISO 639-1 format`);
  return null;
};

const validateGeography = (value, name, allowNull = true) => {
  switch (true) {
    case typeof value === 'string':
      if (!/^FR-[A-Z0-9]{2,3}$/.test(value)) api.inspector.warn(`value '${value}' set at analytics.${name} with wrong format. Geographic location should be a String following ISO 3166-2:FR format`);
      return value;

    case value === undefined && allowNull:
    case value === null && allowNull:
      return '';
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting geographic location as a String following ISO 3166-2:FR format`);
  return null;
};

const normaliseISODate = (date) => date.toISOString().split('T')[0];

const validateDate = (value, name, allowNull = true) => {
  switch (true) {
    case value instanceof Date:
      return normaliseISODate(value);

    case typeof value === 'string': {
      const date = new Date(value);
      if (date.toString() !== 'Invalid Date') return normaliseISODate(date);
      break;
    }

    case value === undefined && allowNull:
    case value === null && allowNull:
      return null;
  }

  api.inspector.warn(`unexpected value '${value}' set at analytics.${name}. Expecting a Date`);
  return null;
};

class User {
  constructor (config) {
    this._config = config || {};
  }

  reset (clear = false) {
    this._isConnected = false;
    this.status = Status.ANONYMOUS;
    if (!clear && this._config.connect) this.connect(this._config.connect.uid, this._config.connect.email, this._config.connect.isNew);
    else {
      this._uid = undefined;
      this._email = undefined;
      this._isNew = false;
    }
    this.profile = clear ? undefined : this._config.profile;
    this.language = clear ? undefined : this._config.language;
    this.type = clear ? undefined : this._config.type;
  }

  connect (uid, email, isNew = false) {
    this._uid = validateString(uid, 'user.uid');
    if (/^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]{2,}@[a-zA-Z0-9-]{2,}\.[a-zA-Z]{2,}$/.test(email)) api.inspector.warn('Please check analytics.user.email is properly encrypted ');
    this._email = validateString(email, 'user.email');
    this._isNew = validateBoolean(isNew);
    this._isConnected = true;
    this.status = Status.CONNECTED;
  }

  get uid () {
    return this._uid;
  }

  get email () {
    return this._email;
  }

  get isNew () {
    return this._isNew;
  }

  set status (id) {
    const stati = Object.values(Status).filter(status => status.isConnected === this._isConnected);
    this._status = stati.filter(status => status.id === id || status.value === id)[0] || stati.filter(status => status.isDefault)[0];
  }

  get status () {
    return this._status.id;
  }

  set profile (value) {
    const valid = validateString(value, 'user.profile');
    if (valid !== null) this._profile = valid;
  }

  get profile () {
    return this._profile.id;
  }

  set language (value) {
    const valid = validateLang(value, 'user.language');
    if (valid !== null) this._language = valid;
  }

  get language () {
    return this._language || navigator.language;
  }

  set type (id) {
    this._type = Object.values(Type$2).filter(type => type.id === id || type.value === id)[0];
  }

  get type () {
    return this._type.id;
  }

  get layer () {
    const layer = [];
    if (this.uid) layer.push('uid', normalize(this.uid));
    if (this.email) layer.push('email', normalize(this.email));
    if (this.isNew) layer.push('newcustomer', '1');
    if (this.language) layer.push('user_language', this.language);
    layer.push('user_login_status', this._status.value);
    if (this._profile) layer.push('profile', this._profile);
    if (this._type) layer.push('user_type', this._type.value);
    return layer;
  }
}

User.Status = Status;
User.Type = Type$2;

const Environment = {
  DEVELOPMENT: {
    id: 'development',
    value: 'dev'
  },
  STAGE: {
    id: 'stage',
    value: 'stage'
  },
  PRODUCTION: {
    id: 'production',
    value: 'prod'
  }
};

class Site {
  constructor (config) {
    this._config = config || {};
  }

  reset (clear = false) {
    this.environment = clear ? Environment.DEVELOPMENT.id : this._config.environment;
    this.entity = clear ? undefined : this._config.entity;
    this.language = clear ? undefined : this._config.language;
    this.target = clear ? undefined : this._config.target;
    this.type = clear ? undefined : this._config.type;
    this.region = clear ? undefined : this._config.region;
    this.department = clear ? undefined : this._config.department;
    this.version = clear ? undefined : this._config.version;
    this._api = api.version;
  }

  set environment (value) {
    switch (value) {
      case Environment.PRODUCTION.id:
      case Environment.PRODUCTION.value:
        this._environment = Environment.PRODUCTION;
        break;

      case Environment.STAGE.id:
      case Environment.STAGE.value:
        this._environment = Environment.STAGE;
        break;

      case Environment.DEVELOPMENT.id:
      case Environment.DEVELOPMENT.value:
        this._environment = Environment.DEVELOPMENT;
        break;

      default:
        this._environment = Environment.DEVELOPMENT;
    }
  }

  get environment () {
    return this._environment ? this._environment.id : Environment.DEVELOPMENT.id;
  }

  set entity (value) {
    const valid = validateString(value, 'site.entity');
    if (valid !== null) this._entity = valid;
  }

  get entity () {
    return this._entity;
  }

  set language (value) {
    const valid = validateLang(value, 'site.language');
    if (valid !== null) this._language = valid;
  }

  get language () {
    return this._language || document.documentElement.lang;
  }

  set target (value) {
    const valid = validateString(value, 'site.target');
    if (valid !== null) this._target = valid;
  }

  get target () {
    return this._target;
  }

  set type (value) {
    const valid = validateString(value, 'site.type');
    if (valid !== null) this._type = valid;
  }

  get type () {
    return this._type;
  }

  set region (value) {
    const valid = validateGeography(value, 'site.region');
    if (valid !== null) this._region = valid;
  }

  get region () {
    return this._region;
  }

  set department (value) {
    const valid = validateGeography(value, 'site.department');
    if (valid !== null) this._department = valid;
  }

  get department () {
    return this._department;
  }

  set version (value) {
    const valid = validateString(value, 'site.version');
    if (valid !== null) this._version = valid;
  }

  get version () {
    return this._version;
  }

  get api () {
    return this._api;
  }

  get layer () {
    const layer = [];
    layer.push('site_environment', this._environment.value);
    if (this.entity) layer.push('site_entity', normalize(this.entity));
    else api.inspector.warn('entity is required in analytics.site');
    if (this.language) layer.push('site_language', this.language);
    if (this.target) layer.push('site_target', normalize(this.target));
    if (this.type) layer.push('site_type', normalize(this.type));
    if (this.region) layer.push('site_region', this.region);
    if (this.department) layer.push('site_department', this.department);
    if (this.version) layer.push('site_version', this.version);
    if (this.api) layer.push('api_version', this.api);
    return layer;
  }
}

Site.Environment = Environment;

const Inventory = {
  accordion: api.internals.ns.selector('accordion'),
  alert: api.internals.ns.selector('alert'),
  badge: api.internals.ns.selector('badge'),
  breadcrumb: api.internals.ns.selector('breadcrumb'),
  button: api.internals.ns.selector('btn'),
  callout: api.internals.ns.selector('callout'),
  card: api.internals.ns.selector('card'),
  checkbox: api.internals.ns.selector('checkbox-group'),
  connect: api.internals.ns.selector('connect'),
  consent: api.internals.ns.selector('consent-banner'),
  content: api.internals.ns.selector('content-media'),
  download: api.internals.ns.selector('download'),
  follow: api.internals.ns.selector('follow'),
  footer: api.internals.ns.selector('footer'),
  header: api.internals.ns.selector('header'),
  highlight: api.internals.ns.selector('highlight'),
  input: api.internals.ns.selector('input-group'),
  link: api.internals.ns.selector('link'),
  modal: api.internals.ns.selector('modal'),
  navigation: api.internals.ns.selector('nav'),
  notice: api.internals.ns.selector('notice'),
  pagination: api.internals.ns.selector('pagination'),
  quote: api.internals.ns.selector('quote'),
  radio: api.internals.ns.selector('radio-group'),
  search: api.internals.ns.selector('search-bar'),
  select: api.internals.ns.selector('select'),
  share: api.internals.ns.selector('share'),
  sidemenu: api.internals.ns.selector('sidemenu'),
  stepper: api.internals.ns.selector('stepper'),
  summary: api.internals.ns.selector('summary'),
  tab: api.internals.ns.selector('tabs'),
  table: api.internals.ns.selector('table'),
  tag: api.internals.ns.selector('tag'),
  tile: api.internals.ns.selector('tile'),
  toggle: api.internals.ns.selector('toggle'),
  tooltip: api.internals.ns.selector('tooltip'),
  transcription: api.internals.ns.selector('transcription'),
  translate: api.internals.ns.selector('translate'),
  upload: api.internals.ns.selector('upload-group')
};

const CollectionState = {
  COLLECTABLE: 'collectable',
  COLLECTING: 'collecting',
  COLLECTED: 'collected'
};

class Page {
  constructor (config) {
    this._config = config || {};
    this._state = CollectionState.COLLECTABLE;
  }

  reset (clear = false) {
    this.path = clear ? '' : this._config.path;
    this.referrer = clear ? '' : this._config.referrer;
    this.title = clear ? '' : this._config.title;
    this.name = clear ? '' : this._config.name;
    this.id = clear ? '' : this._config.id;
    this.author = clear ? '' : this._config.author;
    this.date = clear ? '' : this._config.date;
    this._labels = clear || !this._config.labels ? ['', '', '', '', ''] : this._config.labels;
    this._labels.length = 5;
    this._tags = clear || !this._config.tags ? [] : this._config.tags;
    this._categories = clear || !this._config.categories ? ['', '', ''] : this._config.categories;
    this.isError = !clear && this._config.isError;
    this.template = clear ? '' : this._config.template;
    this.group = clear ? '' : this._config.group;
    this.segment = clear ? '' : this._config.segment;
    this.subtemplate = clear ? '' : this._config.subtemplate;
    this.theme = clear ? '' : this._config.theme;
    this.subtheme = clear ? '' : this._config.subtheme;
    this.related = clear ? '' : this._config.related;
    this.depth = clear || isNaN(this._config.depth) ? 0 : this._config.depth;
    this.current = clear || isNaN(this._config.current) ? -1 : this._config.current;
    this.total = clear || isNaN(this._config.total) ? -1 : this._config.total;
    this._filters = clear || !this._config.filters ? [] : this._config.filters;
  }

  collecting () {
    if (this._state !== CollectionState.COLLECTABLE) {
      api.inspector.warn(`current path '${this.path}' was already collected`);
      return false;
    }
    this._state = CollectionState.COLLECTING;
    return true;
  }

  get isCollecting () {
    return this._state === CollectionState.COLLECTING;
  }

  set path (value) {
    const valid = validateString(value, 'page.path');
    if (valid !== null) {
      this._path = valid;
      this._state = CollectionState.COLLECTABLE;
    }
  }

  get path () {
    return this._path || `${document.location.pathname}${document.location.search}`;
  }

  set referrer (value) {
    const valid = validateString(value, 'page.referrer');
    if (valid !== null) this._referrer = valid;
  }

  get referrer () {
    return this._referrer;
  }

  set title (value) {
    const valid = validateString(value, 'page.title');
    if (valid !== null) this._title = valid;
  }

  get title () {
    return this._title || document.title;
  }

  set id (value) {
    const valid = validateString(value, 'page.id');
    if (valid !== null) this._id = valid;
  }

  get id () {
    return this._id;
  }

  set author (value) {
    const valid = validateString(value, 'page.author');
    if (valid !== null) this._author = valid;
  }

  get author () {
    return this._author;
  }

  set date (value) {
    const valid = validateDate(value, 'page.date');
    if (valid !== null) this._date = valid;
  }

  get date () {
    return this._date;
  }

  get tags () {
    return this._tags;
  }

  set name (value) {
    const valid = validateString(value, 'page.name');
    if (valid !== null) this._name = valid;
  }

  get name () {
    return this._name || this.title;
  }

  get labels () {
    return this._labels;
  }

  get categories () {
    return this._categories;
  }

  set isError (value) {
    const valid = validateBoolean(value, 'page.isError');
    if (valid !== null) this._isError = valid;
  }

  get isError () {
    return this._isError;
  }

  set template (value) {
    const valid = validateString(value, 'page.template');
    if (valid !== null) this._template = valid;
  }

  get template () {
    return this._template || 'autres';
  }

  set segment (value) {
    const valid = validateString(value, 'page.segment');
    if (valid !== null) this._segment = valid;
  }

  get segment () {
    return this._segment || this.template;
  }

  set group (value) {
    const valid = validateString(value, 'page.group');
    if (valid !== null) this._group = valid;
  }

  get group () {
    return this._group || this.template;
  }

  set subtemplate (value) {
    const valid = validateString(value, 'page.subtemplate');
    if (valid !== null) this._subtemplate = valid;
  }

  get subtemplate () {
    return this._subtemplate;
  }

  set theme (value) {
    const valid = validateString(value, 'page.theme');
    if (valid !== null) this._theme = valid;
  }

  get theme () {
    return this._theme;
  }

  set subtheme (value) {
    const valid = validateString(value, 'page.subtheme');
    if (valid !== null) this._subtheme = valid;
  }

  get subtheme () {
    return this._subtheme;
  }

  set related (value) {
    const valid = validateString(value, 'page.related');
    if (valid !== null) this._related = valid;
  }

  get related () {
    return this._related;
  }

  set depth (value) {
    const valid = validateNumber(value, 'page.depth');
    if (valid !== null) this._depth = valid;
  }

  get depth () {
    return this._depth;
  }

  set current (value) {
    const valid = validateNumber(value, 'page.current');
    if (valid !== null) this._current = valid;
  }

  get current () {
    return this._current;
  }

  set total (value) {
    const valid = validateNumber(value, 'page.total');
    if (valid !== null) this._total = valid;
  }

  get total () {
    return this._total;
  }

  get filters () {
    return this._filters;
  }

  get layer () {
    this._state = CollectionState.COLLECTED;
    const layer = [];
    if (this.path) layer.push('path', normalize(this.path));
    if (this.referrer) layer.push('referrer', normalize(this.referrer));
    if (this.title) layer.push('page_title', normalize(this.title));
    if (this.name) layer.push('page_name', normalize(this.name));
    if (this.id) layer.push('page_id', normalize(this.id));
    if (this.author) layer.push('page_author', normalize(this.author));
    if (this.date) layer.push('page_date', normalize(this.date));

    const components = Object.keys(Inventory).map(id => document.querySelector(Inventory[id]) !== null ? id : null).filter(id => id !== null).join(',');
    if (components) layer.push('page_components', components);

    const labels = this._labels.slice(0, 5);
    labels.length = 5;
    if (labels.some(label => label)) layer.push('pagelabel', labels.map(label => typeof label === 'string' ? normalize(label) : '').join(','));

    const tags = this._tags;
    if (tags.some(tag => tag)) layer.push('pagetag', tags.map(tag => typeof tag === 'string' ? normalize(tag) : '').join(','));

    this._categories.forEach((category, index) => {
      if (category) layer.push(`page_category${index + 1}`, category);
    });

    if (this._isError) layer.push('error', '1');

    layer.push('page_template', normalize(this.template));
    layer.push('pagegroup', normalize(this.group));
    layer.push('site-segment', normalize(this.segment));

    if (this.subtemplate) layer.push('page_subtemplate', normalize(this.subtemplate));
    if (this.theme) layer.push('page_theme', normalize(this.theme));
    if (this.subtheme) layer.push('page_subtheme', normalize(this.subtheme));
    if (this.related) layer.push('page_related', normalize(this.related));
    if (!isNaN(this.depth)) layer.push('page_depth', this.depth);

    if (!isNaN(this.current) && this.current > -1) {
      let pagination = `${this.current}`;
      if (!isNaN(this.total) && this.total > -1) pagination += `/${this.total}`;
      layer.push('page_pagination', pagination);
    }

    if (this.filters.length && this.filters.some(label => label)) {
      const filters = this.filters.map(filter => typeof filter === 'string' ? normalize(filter) : '');
      layer.push('page_filters', filters.join(','));
    }
    return layer;
  }
}

const Method = {
  STANDARD: {
    id: 'standard',
    value: 'standard',
    isDefault: true
  },
  AUTOCOMPLETE: {
    id: 'autocomplete',
    value: 'autocompletion'
  }
};

class Search {
  constructor (config) {
    this._config = config || {};
  }

  reset (clear = false) {
    this.engine = clear ? undefined : this._config.engine;
    this.results = clear || isNaN(this._config.results) ? -1 : this._config.results;
    this.terms = clear ? undefined : this._config.terms;
    this.category = clear ? undefined : this._config.category;
    this.theme = clear ? undefined : this._config.theme;
    this.type = clear ? undefined : this._config.type;
    this.method = clear ? undefined : this._config.method;
  }

  set engine (value) {
    const valid = validateString(value, 'search.engine');
    if (valid !== null) this._engine = valid;
  }

  get engine () {
    return this._engine;
  }

  set results (value) {
    const valid = validateNumber(value, 'search.results');
    if (valid !== null) this._results = valid;
  }

  get results () {
    return this._results;
  }

  set terms (value) {
    const valid = validateString(value, 'search.terms');
    if (valid !== null) this._terms = valid;
  }

  get terms () {
    return this._terms;
  }

  set category (value) {
    const valid = validateString(value, 'search.category');
    if (valid !== null) this._category = valid;
  }

  get category () {
    return this._category;
  }

  set theme (value) {
    const valid = validateString(value, 'search.theme');
    if (valid !== null) this._theme = valid;
  }

  get theme () {
    return this._theme;
  }

  set type (value) {
    const valid = validateString(value, 'search.type');
    if (valid !== null) this._type = valid;
    this._type = value;
  }

  get type () {
    return this._type;
  }

  set method (id) {
    const methods = Object.values(Method);
    this._method = methods.filter(method => method.id === id || method.value === id)[0] || methods.filter(method => method.isDefault)[0];
  }

  get method () {
    return this._method;
  }

  get layer () {
    const layer = [];
    if (this.engine) layer.push('isearchengine', normalize(this.engine));
    if (this.results > -1) layer.push('isearchresults', this.results);
    if (this.terms) layer.push('isearchkey', 'search_terms', 'isearchdata', normalize(this.terms));
    if (this.category) layer.push('isearchkey', 'search_category', 'isearchdata', normalize(this.category));
    if (this.theme) layer.push('isearchkey', 'search_theme', 'isearchdata', normalize(this.theme));
    if (this.type) layer.push('isearchkey', 'search_type', 'isearchdata', normalize(this.type));
    if (this._method && layer.length) layer.push('isearchkey', 'search_method', 'isearchdata', this._method.value);
    return layer;
  }
}

Search.Method = Method;

class Funnel {
  constructor (config) {
    this._config = config || {};
  }

  reset (clear = false) {
    this.id = clear ? undefined : this._config.id;
    this.type = clear ? undefined : this._config.type;
    this.name = clear ? undefined : this._config.name;
    this.step = clear ? undefined : this._config.step;
    this.current = clear || isNaN(this._config.current) ? -1 : this._config.current;
    this.total = clear || isNaN(this._config.total) ? -1 : this._config.total;
    this.objective = clear ? undefined : this._config.objective;
    this.error = clear ? undefined : this._config.error;
  }

  set id (value) {
    const valid = validateString(value, 'funnel.id');
    if (valid !== null) this._id = valid;
  }

  get id () {
    return this._id;
  }

  set type (value) {
    const valid = validateString(value, 'funnel.type');
    if (valid !== null) this._type = valid;
  }

  get type () {
    return this._type;
  }

  set name (value) {
    const valid = validateString(value, 'funnel.name');
    if (valid !== null) this._name = valid;
  }

  get name () {
    return this._name;
  }

  set step (value) {
    const valid = validateString(value, 'funnel.step');
    if (valid !== null) this._step = valid;
  }

  get step () {
    return this._step;
  }

  set current (value) {
    const valid = validateNumber(value, 'funnel.current');
    if (valid !== null) this._current = valid;
  }

  get current () {
    return this._current;
  }

  set total (value) {
    const valid = validateNumber(value, 'funnel.total');
    if (valid !== null) this._total = valid;
  }

  get total () {
    return this._total;
  }

  set objective (value) {
    const valid = validateString(value, 'funnel.objective');
    if (valid !== null) this._objective = valid;
    this._objective = value;
  }

  get objective () {
    return this._objective;
  }

  set error (value) {
    const valid = validateString(value, 'funnel.error');
    if (valid !== null) this._error = valid;
    this._error = value;
  }

  get error () {
    return this._error;
  }

  get layer () {
    const layer = [];
    if (this.id) layer.push('funnel_id', normalize(this.id));
    if (this.type) layer.push('funnel_type', normalize(this.type));
    if (this.name) layer.push('funnel_name', normalize(this.name));
    if (this.step) layer.push('funnel_step_name', normalize(this.step));
    if (!isNaN(this.current) && this.current > -1) layer.push('funnel_step_number', this.current);
    if (!isNaN(this.total) && this.total > -1) layer.push('funnel_step_max', this.total);
    if (this.objective) layer.push('funnel_objective', normalize(this.objective));
    if (this.error) layer.push('funnel_error', normalize(this.error));
    return layer;
  }
}

const ActionMode = {
  IN: 'in',
  OUT: 'out',
  NONE: 'none'
};

const ActionStatus = {
  UNSTARTED: {
    id: 'unstarted',
    value: -1
  },
  STARTED: {
    id: 'started',
    value: 1
  },
  SINGULAR: {
    id: 'singular',
    value: 2
  },
  ENDED: {
    id: 'ended',
    value: 3
  }
};

const getParametersLayer = (data) => {
  return Object.entries(data).map(([key, value]) => ['actionpname', normalize(key), 'actionpvalue', normalize(value)]).flat();
};

class Action {
  constructor (name) {
    this._isMuted = false;
    this._isForced = false;
    this._name = name;
    this._status = ActionStatus.UNSTARTED;
    this._labels = [];
    this._parameters = {};
    this._sentData = [];
  }

  get isMuted () {
    return this._isMuted;
  }

  set isMuted (value) {
    this._isMuted = value;
  }

  get isForced () {
    return this._isForced;
  }

  set isForced (value) {
    this._isForced = value;
  }

  get isSingular () {
    return this._status === ActionStatus.SINGULAR;
  }

  get status () {
    return this._status;
  }

  get name () {
    return this._name;
  }

  get labels () {
    return this._labels;
  }

  get reference () {
    return this._reference;
  }

  get parameters () {
    return this._parameters;
  }

  get mode () {
    return this._mode;
  }

  singularize () {
    this._status = ActionStatus.SINGULAR;
  }

  rewind () {
    this._sentData = [];
    this._status = ActionStatus.UNSTARTED;
  }

  addParameter (key, value) {
    this._parameters[key] = value;
  }

  removeParameter (key) {
    delete this._parameters[key];
  }

  set reference (value) {
    const valid = validateString(value, `action ${this._name}`);
    if (valid !== null) this._reference = valid;
  }

  get _base () {
    return ['actionname', this._name];
  }

  _getLayer (data = {}) {
    if (this._isMuted) return [];

    if (this._mode !== ActionMode.IN) this._sentData.push(JSON.stringify(data));

    const layer = this._base;
    switch (this._mode) {
      case ActionMode.IN:
      case ActionMode.OUT:
        layer.push('actionmode', this._mode);
        break;
    }

    const labels = this._labels.slice(0, 5);
    labels.length = 5;
    if (labels.some(label => label)) layer.push('actionlabel', labels.map(label => typeof label === 'string' ? normalize(label) : '').join(','));

    if (this._reference) layer.push('actionref', this._reference);

    layer.push.apply(layer, getParametersLayer(Object.assign(this._parameters, data || {})));
    return layer;
  }

  start (data) {
    switch (this._status) {
      case ActionStatus.UNSTARTED:
        this._mode = ActionMode.IN;
        this._status = ActionStatus.STARTED;
        break;

      case ActionStatus.SINGULAR:
        this._mode = ActionMode.NONE;
        this._status = ActionStatus.ENDED;
        break;

      default:
        api.inspector.error(`unexpected start on action ${this._name} with status ${this._status.id}`);
        return [];
    }
    return this._getLayer(data);
  }

  end (data) {
    switch (this._status) {
      case ActionStatus.STARTED:
        this._mode = ActionMode.OUT;
        this._status = ActionStatus.ENDED;
        break;

      case ActionStatus.UNSTARTED:
        this._mode = ActionMode.NONE;
        this._status = ActionStatus.ENDED;
        break;

      case ActionStatus.SINGULAR:
        this._mode = ActionMode.NONE;
        this._status = ActionStatus.ENDED;
        break;

      case ActionStatus.ENDED:
        if (this._sentData.includes(JSON.stringify(data))) return [];
        this._mode = ActionMode.NONE;
        this._status = ActionStatus.ENDED;
        break;

      default:
        return [];
    }
    return this._getLayer(data);
  }

  resume (data) {
    if (this._isMuted) return [];
    if (this._status.value >= ActionStatus.ENDED.value) {
      api.inspector.error(`unexpected resuming on action ${this._name} with status ${this._status.id}`);
      return [];
    }
    const layer = this._base;
    if (data) layer.push.apply(layer, getParametersLayer(data));
    return layer;
  }
}

class Actions {
  constructor () {
    this._actions = [];
  }

  rewind () {
    this._actions.forEach(action => action.rewind());
  }

  getAction (name) {
    let action = this._actions.filter(action => action.name === name)[0];
    if (!action) {
      action = new Action(name);
      this._actions.push(action);
    }
    return action;
  }

  hasAction (name) {
    return this._actions.some(action => action.name === name);
  }

  remove (action) {
    const index = this._actions.indexOf(action);
    if (index === -1) return false;
    this._actions.splice(index, 1);
    return true;
  }
}

Actions.ActionMode = ActionMode;

const actions = new Actions();
Actions.instance = actions;

class Location {
  constructor (onRouteChange, isListeningHash = false) {
    this._onRouteChange = onRouteChange;
    this._isListeningHash = isListeningHash;
    this._update();
    renderer.add(this);
  }

  _update () {
    this._pathname = document.location.pathname;
    this._search = document.location.search;
    this._hash = document.location.hash;
    this._path = `${this._pathname}${this._search}`;
    if (this._isListeningHash) this._path += this._hash;
    this._hasTitle = this._title === document.title;
    this._title = document.title;
  }

  render () {
    if (this._pathname !== document.location.pathname || this._search !== document.location.search) this.change();
    if (this._isListeningHash && this._hash !== document.location.hash) this.change();
  }

  change () {
    this._referrer = this._path;
    this._update();
    this._onRouteChange();
  }

  get path () {
    return this._path;
  }

  get hasTitle () {
    return this._hasTitle;
  }

  get title () {
    return this._title;
  }

  get referrer () {
    return this._referrer;
  }
}

const CollectorEvent = {
  COLLECT: api.internals.ns.event('collect')
};

const ActioneeEmission = {
  REWIND: api.internals.ns.emission('analytics', 'rewind')
};

class Collector {
  constructor (config) {
    switch (config.collection) {
      case Collection.MANUAL:
      case Collection.LOAD:
      case Collection.FULL:
      case Collection.HASH:
        this._collection = config.collection;
        break;

      default:
        /* deprecated start */
        if (config.mode) {
          switch (config.mode) {
            case 'manual':
              this._collection = config.collection;
              break;
          }
        }
        /* deprecated end */

        switch (true) {
          /* deprecated */
          case config.mode === 'manual':
            this._collection = Collection.MANUAL;
            break;

          case api.mode === api.Modes.ANGULAR:
          case api.mode === api.Modes.REACT:
          case api.mode === api.Modes.VUE:
            this._collection = Collection.FULL;
            break;

          default:
            this._collection = Collection.LOAD;
        }
    }

    this._isActionEnabled = config.isActionEnabled === 'false' || config.isActionEnabled;

    this._user = new User(config.user);
    this._site = new Site(config.site);
    this._page = new Page(config.page);
    this._search = new Search(config.search);
    this._funnel = new Funnel(config.funnel);

    this._delay = -1;
    queue.setCollector(this);
  }

  get page () {
    return this._page;
  }

  get user () {
    return this._user;
  }

  get site () {
    return this._site;
  }

  get search () {
    return this._search;
  }

  get funnel () {
    return this._funnel;
  }

  start () {
    const handleRouteChange = this._handleRouteChange.bind(this);
    switch (this._collection) {
      case Collection.LOAD:
        this.collect();
        break;

      case Collection.FULL:
        this.collect();
        this._location = new Location(handleRouteChange);
        break;

      case Collection.HASH:
        this.collect();
        this._location = new Location(handleRouteChange, true);
        break;
    }
  }

  _handleRouteChange () {
    queue.send(true);
    this._delay = 6;
    renderer.add(this);
  }

  render () {
    this._delay--;
    if (this._delay < 0) {
      renderer.remove(this);
      this._routeChanged();
    }
  }

  _routeChanged () {
    actions.rewind();
    this._page.referrer = this._location.referrer;
    if (this._location.hasTitle) this._page.title = this._location.title;
    this._page.path = this._location.path;
    const event = new CustomEvent(CollectorEvent.COLLECT);
    document.documentElement.dispatchEvent(event);
    this.collect();
    if (api.internals && api.internals.stage && api.internals.stage.root) api.internals.stage.root.descend(ActioneeEmission.REWIND);
  }

  reset (clear = false) {
    this._user.reset(clear);
    this._site.reset(clear);
    this._page.reset(clear);
    this._search.reset(clear);
    this._funnel.reset(clear);
  }

  collect () {
    if (!this.page.collecting()) return;
    queue.collect();
  }

  get collection () {
    return this._collection;
  }

  get isCollecting () {
    return this._page.isCollecting;
  }

  get isActionEnabled () {
    return this._isActionEnabled;
  }

  set isActionEnabled (value) {
    this._isActionEnabled = value;
  }

  get layer () {
    return [
      ...this._user.layer,
      ...this._site.layer,
      ...this._page.layer,
      ...this._search.layer,
      ...this._funnel.layer
    ];
  }
}

class Analytics {
  constructor () {
    this._isReady = false;
    this._readiness = new Promise((resolve, reject) => {
      if (this._isReady) resolve();
      else {
        this._resolve = resolve;
        this._reject = reject;
      }
    });
    this._configure();
  }

  _configure () {
    switch (true) {
      case window[patch.namespace] !== undefined:
        this._config = window[patch.namespace].configuration.analytics;
        window[patch.namespace].promise.then(this._build.bind(this), () => {});
        break;

      case api.internals !== undefined && api.internals.configuration !== undefined && api.internals.configuration.analytics !== undefined && api.internals.configuration.analytics.domain !== undefined:
        this._config = api.internals.configuration.analytics;
        this._build();
        break;

      case api.analytics !== undefined && api.analytics.domain !== undefined:
        this._config = api.analytics;
        this._build();
        break;

      default:
        api.inspector.warn('analytics configuration is incorrect or missing (required : domain)');
    }
  }

  _build () {
    this._init = new Init(this._config.domain);
    this._init.configure().then(this._start.bind(this), (reason) => this._reject(reason));
  }

  get isReady () {
    return this._isReady;
  }

  get readiness () {
    return this._readiness;
  }

  _start () {
    if (this._isReady) return;

    this._cmp = new ConsentManagerPlatform(this._config.cmp);
    this._collector = new Collector(this._config);
    this._collector.reset();

    this._isReady = true;
    this._resolve();

    queue.start();
    this._collector.start();
  }

  get page () {
    return this._collector.page;
  }

  get user () {
    return this._collector.user;
  }

  get site () {
    return this._collector._site;
  }

  get search () {
    return this._collector.search;
  }

  get funnel () {
    return this._collector.funnel;
  }

  get cmp () {
    return this._cmp;
  }

  get opt () {
    return opt;
  }

  get collection () {
    return this._collector.collection;
  }

  get isActionEnabled () {
    return this._collector.isActionEnabled;
  }

  set isActionEnabled (value) {
    this._collector.isActionEnabled = value;
  }

  get isDebugging () {
    return debug.isActive;
  }

  set isDebugging (value) {
    debug.isActive = value;
  }

  push (type, layer) {
    push(type, layer);
  }

  reset (clear = false) {
    this._collector.reset();
  }

  collect () {
    this._collector.collect();
  }
}

const analytics = new Analytics();

analytics.Collection = Collection;
analytics.PushType = PushType;

/**
 * Copy properties from multiple sources including accessors.
 * source : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copier_des_accesseurs
 *
 * @param {object} [target] - Target object to copy into
 * @param {...objects} [sources] - Multiple objects
 * @return {object} A new object
 *
 * @example
 *
 *     const obj1 = {
 *        key: 'value'
 *     };
 *     const obj2 = {
 *        get function01 () {
 *          return a-value;
 *        }
 *        set function01 () {
 *          return a-value;
 *        }
 *     };
 *     completeAssign(obj1, obj2)
 */
const completeAssign = (target, ...sources) => {
  sources.forEach(source => {
    const descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});

    Object.getOwnPropertySymbols(source).forEach(sym => {
      const descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
};

api.analytics = completeAssign(analytics, {});

const Type$1 = {
  // impression
  IMPRESSION: {
    id: 'impression', // element appeared in the page
    isSingular: true,
    isBeginning: true,
    attributed: false,
    type: 'impression'
  },
  // interaction
  CLICK: {
    id: 'click', // generic click interaction
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'click',
    method: 'eventListener'
  },
  INTERNAL: {
    id: 'internal', // anchor click redirecting on an internal url
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'click',
    method: 'eventListener'
  },
  EXTERNAL: {
    id: 'external', // anchor click redirecting on an external url
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'click',
    method: 'eventListener'
  },
  DOWNLOAD: {
    id: 'download', // anchor click downloading a file
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'click',
    method: 'eventListener'
  },
  BUTTON: {
    id: 'button', // button click
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'click',
    method: 'eventListener'
  },
  DOUBLE_CLICK: {
    id: 'dblclick', // double click
    isBeginning: true,
    attributed: true,
    type: 'interaction',
    event: 'dblclick',
    method: 'eventListener'
  },
  // event
  OPEN: {
    id: 'open', // open event
    isSingular: true,
    attributed: false,
    type: 'event',
    method: 'eventListener'
  },
  COMPLETE: {
    id: 'complete', // complete event
    isSingular: true,
    attributed: false,
    type: 'event',
    method: 'eventListener'
  },
  FOCUS: {
    id: 'focus', // focus event
    isSingular: true,
    attributed: false,
    type: 'event',
    method: 'eventListener'
  },
  ERROR: {
    id: 'error', // error event
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  ADD: {
    id: 'add', // add event
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  REMOVE: {
    id: 'remove', // remove event
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  DISPLAY: {
    id: 'display', // display event
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  CHANGE: {
    id: 'change', // input event change
    isSingular: true,
    attributed: true,
    type: 'event',
    event: 'change',
    method: 'change'
  },
  PROGRESS: {
    id: 'progress', // video retention event with percent of the part reached
    isBeginning: true,
    attributed: true,
    type: 'event'
  },
  // component interaction
  SHARE: {
    id: 'share', // component share click (share)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  PRESS: {
    id: 'press', // component press click (pressable tag)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  RELEASE: {
    id: 'release', // component release click (pressable tag)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  DISMISS: {
    id: 'dismiss', // component dismiss click (dismissible tag)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  UPLOAD: {
    id: 'upload', // component upload click (upload)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  CHECK: {
    id: 'check', // component check click (checkbox, radio, toggle)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  UNCHECK: {
    id: 'uncheck', // component uncheck click (checkbox, radio, toggle)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  SELECT: {
    id: 'select', // component select change (select)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  SUBSCRIBE: {
    id: 'subscribe', // component subscribe click (follow)
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  // component event
  DISCLOSE: {
    id: 'disclose', // component disclose event (accordion, modal, tab)
    isBeginning: true,
    attributed: false,
    type: 'event'
  },
  SEARCH: {
    id: 'search', // component disclose event (accordion, modal, tab)
    isBeginning: true,
    attributed: false,
    type: 'event'
  },
  SHOW: {
    id: 'show', // component show event (tooltip)
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  HIDE: {
    id: 'hide', // component hide event (tooltip)
    isSingular: true,
    attributed: false,
    type: 'event'
  },
  // video
  AUTOPLAY: {
    id: 'autoplay', // video autoplay event
    isBeginning: true,
    attributed: false,
    type: 'event'
  },
  PLAY: {
    id: 'play', // video play click
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  PAUSE: {
    id: 'pause', // video pause click
    isBeginning: true,
    attributed: false,
    type: 'interaction'
  },
  END: {
    id: 'end', // video end event
    isBeginning: true,
    attributed: false,
    type: 'event'
  }
};

const Type = {
  UNDEFINED: 'undefined',
  HEADING: 'heading',
  COMPONENT: 'component',
  CONTENT: 'content'
};

const NODE_POSITION = Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINED_BY;

class Heading {
  constructor (heading) {
    this._label = heading.textContent.trim();
    this._level = Number(heading.tagName.charAt(1));
  }

  get level () {
    return this._level;
  }

  get label () {
    return this._label;
  }
}

class Member {
  constructor (node, target, level) {
    this._type = Type.UNDEFINED;
    this._node = node;
    this._target = target;
    this._level = level;
    this._label = '';
    this._component = '';
    this._isValid = true;
    this.analyse();
  }

  _parseHeadings () {
    const selector = Array.from({ length: this._level }, (v, i) => `h${i + 1}`).join(',');
    this._headings = Array.from(this._node.querySelectorAll(selector)).filter(heading => heading === this._node || heading.parentNode === this._node || (heading.parentNode != null && heading.parentNode.parentNode === this._node)).filter(heading => (this._target.compareDocumentPosition(heading) & NODE_POSITION) > 0).map(heading => new Heading(heading)).reverse();
  }

  _getComponent () {
    if (typeof api !== 'function') return false;
    const element = api(this._node);
    if (!element) return false;
    const instance = Object.values(element).filter(actionee => actionee.isActionee).sort((a, b) => b.priority - a.priority)[0];
    if (!instance) return false;

    this._type = Type.COMPONENT;
    this._isValid = instance.validate(this._target);
    const selector = Array.from({ length: 6 }, (v, i) => `h${i + 1}`).join(',');
    const top = Array.from(this._node.querySelectorAll(selector)).map(heading => new Heading(heading)).sort((a, b) => a.level - b.level)[0];
    if (top && top.level <= this._level) this._level = top.level - 1;

    const hx = this._node.closest(selector);
    if (hx) {
      const heading = new Heading(hx);
      if (heading.level <= this._level) this._level = heading.level - 1;
    }

    if (!isNaN(instance.level) && instance.level < this._level) this._level = instance.level;
    this._label = instance.label;
    this._component = instance.component;
    return true;
  }

  _getHeading () {
    if (!this._headings.length) return false;
    const labels = [];
    this._headings.forEach(heading => {
      if (heading.level <= this._level) {
        if (heading.level > 1) labels.unshift(heading.label);
        this._level = heading.level - 1;
      }
    });
    if (!labels.length) return false;
    this._type = Type.HEADING;
    this._label = labels.join(' › ');
    return true;
  }

  analyse () {
    this._parseHeadings();
    if (this._getComponent()) return;
    if (this._getHeading()) return;
    if (this._node !== this._target) return;

    const label = this._node.textContent.trim();
    if (!label) return;
    this._type = Type.CONTENT;
    this._label = label;
  }

  get type () {
    return this._type;
  }

  get level () {
    return this._level;
  }

  get label () {
    return this._label;
  }

  get component () {
    return this._component;
  }

  get node () {
    return this._node;
  }

  get target () {
    return this._target;
  }

  get isValid () {
    return this._isValid;
  }
}

class Hierarchy {
  constructor (node) {
    this._node = node;
    this._process();
  }

  _process () {
    // console.log('_______________ start ____________________');
    const member = new Member(this._node, this._node, 6);
    // console.log('- FIRST MEMBER', member);
    this._level = member.level;
    this._members = [member];

    let node = this._node.parentNode;

    while (document.documentElement.contains(node) && node !== document.documentElement && this._level > 0) {
      // console.log('MEMBERS ARRAY', this._members);
      // console.log('NODE ANALYSIS', node);
      const member = new Member(node, this._node, this._level);
      // console.log('NEW MEMBER', member);
      switch (true) {
        case member.type === Type.UNDEFINED:
          // console.log('****UNDEFINED');
          break;

        case !member.isValid:
          // console.log('****INVALID');
          break;

        case member.label === this._members[0].label && member.type === Type.HEADING && this._members[0].type === Type.COMPONENT:
          // console.log('***** SAME');
          // do nothing
          break;

        case member.label === this._members[0].label && member.type === Type.COMPONENT && this._members[0].type === Type.HEADING:
          // console.log('***** SAME INVERT');
          this._members.splice(0, 1, member);
          break;

        default:
          this._members.unshift(member);
          if (member.level < this._level) this._level = member.level;
      }

      node = node.parentNode;
    }

    this._label = normalize(this._members[this._members.length - 1].label);
    this._title = normalize(this._members.filter(member => member.label).map(member => member.label).join(' › '));
    const components = this._members.filter(member => member.component).map(member => member.component);
    this._component = normalize(components.join(' › '));
    this._localComponent = components[components.length - 1];
    this._globalComponent = components[0];

    // console.log('========= end ===========');
  }

  get localComponent () {
    return this._localComponent;
  }

  get globalComponent () {
    return this._globalComponent;
  }

  get label () {
    return this._label;
  }

  get title () {
    return this._title;
  }

  get component () {
    return this._component;
  }
}

class ActionElement {
  constructor (node, type, id, category = '', title = null, parameters = {}, isRating = false, isForced = false) {
    this._node = node;
    this._type = type;
    this._id = id || this._node.id;
    this._isMuted = false;
    this._title = title;
    this._category = category;
    this._parameters = parameters;
    this._isRating = isRating;
    this._isForced = isForced;
    this._hasBegun = false;

    // this._init();
    requestAnimationFrame(this._init.bind(this));
  }

  _init () {
    this._hierarchy = new Hierarchy(this._node);

    let id = '';
    let type = '';
    if (this._id) id = `_[${this._id}]`;
    else api.inspector.warn(`Analytics API requires an id to be set on tracked element. Missing on ${this._node.outerHTML}`);
    if (this._type) type = `(${this._type.id})_`;
    this._name = `${type}${this._title || this._hierarchy.title}${id}`;

    this._action = actions.getAction(this._name, this._type.status);
    if (this._type.isSingular) this._action.singularize();
    Object.keys(this._parameters).forEach(key => this._action.addParameter(key, this._parameters[key]));
    this._action.isMuted = this._isMuted;
    this._action.isForced = this._isForced;

    this._action.labels[0] = this._type.id;
    this._action.labels[1] = this._hierarchy.globalComponent;
    this._action.labels[2] = this._hierarchy.localComponent;
    this._action.labels[4] = this._category;

    if (this._hierarchy.label) this._action.addParameter('component_label', this._hierarchy.label);
    if (this._hierarchy.title) this._action.addParameter('heading_hierarchy', this._hierarchy.title);
    if (this._hierarchy.component) this._action.addParameter('component_hierarchy', this._hierarchy.component);

    this.begin();
  }

  get isMuted () {
    return this._action ? this._action.isMuted : this._isMuted;
  }

  set isMuted (value) {
    this._isMuted = value;
    if (this._action) this._action.isMuted = value;
  }

  get action () {
    return this._action;
  }

  rewind () {
    this._hasBegun = false;
    this.begin();
  }

  begin (data = {}) {
    if (this._hasBegun) return;
    this._hasBegun = true;
    if (this._type.isBeginning && (this._type.isSingular || this._isRating)) queue.appendStartingAction(this._action, data);
  }

  act (data = {}) {
    if (this._isMuted) return;
    if (!this._action) {
      requestAnimationFrame(() => this.act(data));
      return;
    }
    queue.appendEndingAction(this._action, data);
  }

  dispose () {
    actions.remove(this._action);
  }
}

const ActionAttributes = {
  RATING: api.internals.ns.attr('analytics-rating'),
  ACTION: api.internals.ns.attr('analytics-action')
};

class Actionee extends api.core.Instance {
  constructor (priority = -1, category = '', title = null, isForced = false) {
    super();
    this._type = null;
    this._priority = priority;
    this._category = category;
    this._title = title;
    this._parameters = {};
    this._data = {};
    this._isMuted = false;
    this._isForced = isForced;
  }

  static get instanceClassName () {
    return 'Actionee';
  }

  get proxy () {
    const scope = this;

    const proxy = {
      validate: (target, members) => scope.validate(target, members)
    };

    const proxyAccessors = {
      get isActionee () {
        return true;
      },
      get label () {
        return scope.label;
      },
      get priority () {
        return scope.priority;
      },
      get level () {
        return scope.level;
      },
      get node () {
        return scope.node; // TODO: remove in v2
      }
    };

    return api.internals.property.completeAssign(super.proxy, proxy, proxyAccessors);
  }

  get data () {
    return this._data;
  }

  _config (element, registration) {
    super._config(element, registration);

    if (this._type === null) {
      this._sort(element);
      this._isMuted = true;
      return;
    }

    this._actionElement = new ActionElement(this.node, this._type, this.id, this._category, this.getAttribute(ActionAttributes.ACTION) || this._title, this._parameters, this.hasAttribute(ActionAttributes.RATING), this.hasAttribute(ActionAttributes.ACTION) || this._isForced);
    if (this._isMuted) this._actionElement.isMuted = true;

    this.addDescent(ActioneeEmission.REWIND, this.rewind.bind(this));

    this._sort(element);
  }

  _sort (element) {
    const actionees = element.instances.filter(instance => instance.isActionee).sort((a, b) => b.priority - a.priority);
    if (actionees.length <= 1) return;
    actionees.forEach((actionee, index) => { actionee.isMuted = index > 0; });
  }

  get isMuted () {
    return this._actionElement ? this._actionElement.isMuted : this._isMuted;
  }

  set isMuted (value) {
    this._isMuted = value;
    if (this._actionElement) this._actionElement.isMuted = value;
  }

  get priority () {
    return this._priority;
  }

  setPriority (value) {
    this._priority = value;
  }

  get isInteractive () {
    return this.node.tagName === 'A' || this.node.tagName === 'BUTTON';
  }

  detectInteractionType (node) {
    if (!node) node = this.node;
    const tag = node.tagName;
    const href = node.getAttribute('href');
    const isDownload = node.hasAttribute('download');
    const hostname = node.hostname;

    switch (true) {
      case tag !== 'A':
        this._type = Type$1.CLICK;
        break;

      case isDownload:
        this._type = Type$1.DOWNLOAD;
        this.value = href;
        break;

      case hostname === location.hostname :
        this._type = Type$1.INTERNAL;
        this.value = href;
        break;

      case hostname.length > 0 :
        this._type = Type$1.EXTERNAL;
        this.value = href;
        break;

      default:
        this._type = Type$1.CLICK;
        break;
    }
  }

  setClickType () {
    this._type = Type$1.CLICK;
  }

  listenActionClick (target) {
    if (target) {
      this._clickTarget = target;
      this._clickTarget.addEventListener('click', this._handlingClick, { capture: true });
    } else this.listenClick({ capture: true });
  }

  handleClick () {
    this.act();
  }

  setImpressionType () {
    this._type = Type$1.IMPRESSION;
  }

  rewind () {
    if (this._actionElement) this._actionElement.rewind();
  }

  act (data = {}) {
    if (this._actionElement !== undefined) {
      this._data.component_value = this.value;
      this._actionElement.act(Object.assign(this._data, data));
    }
  }

  getFirstText (node) {
    if (!node) node = this.node;
    if (node.childNodes && node.childNodes.length > 0) {
      for (let i = 0; i < node.childNodes.length; i++) {
        if (node.childNodes[i].nodeType === Node.TEXT_NODE) {
          const text = node.childNodes[i].textContent.trim();
          if (text) {
            return this.cropText(text);
          }
        }
      }

      for (let i = 0; i < node.childNodes.length; i++) {
        const text = this.getFirstText(node.childNodes[i]);
        if (text) {
          return this.cropText(text);
        }
      }
    }
    return '';
  }

  cropText (text, length = 50) {
    return text.length > 50 ? `${text.substring(0, 50).trim()}[...]` : text;
  }

  getInteractionLabel () {
    const title = this.getAttribute('title');
    if (title) return this.cropText(title);

    const text = this.getFirstText();
    if (text) return text;

    const img = this.node.querySelector('img');
    if (img) {
      const alt = img.getAttribute('alt');
      if (alt) return this.cropText(alt);
    }

    return null;
  }

  getHeadingLabel (length = 6) {
    const selector = Array.from({ length: length }, (v, i) => `h${i + 1}`).join(',');
    const headings = Array.from(this.querySelectorAll(selector)).filter(heading => (this.node.compareDocumentPosition(heading) & Node.DOCUMENT_POSITION_CONTAINED_BY) > 0);
    if (headings.length) {
      for (const heading of headings) {
        const text = this.getFirstText(heading);
        if (text) return text;
      }
    }
  }

  detectLevel (node) {
    if (!node) node = this.node;
    const selector = Array.from({ length: 6 }, (v, i) => `h${i + 1}`).join(',');
    const levels = Array.from(node.querySelectorAll(selector)).map(heading => Number(heading.tagName.charAt(1)));
    if (levels.length) this._level = Math.min.apply(null, levels) - 1;
  }

  validate (target) {
    return true;
  }

  get actionElement () {
    return this._actionElement;
  }

  get label () {
    return null;
  }

  get value () {
    return this._value || this.label;
  }

  set value (value) {
    this._value = value;
  }

  get isActionee () {
    return true;
  }

  get level () {
    return this._level;
  }

  get type () {
    return this._type;
  }

  dispose () {
    if (this._clickTarget) {
      this._clickTarget.removeEventListener('click', this._handlingClick);
    }
    super.dispose();
  }
}

class AttributeActionee extends Actionee {
  constructor () {
    super(100, '', null, true);
  }

  static get instanceClassName () {
    return 'AttributeActionee';
  }

  init () {
    this._attribute = this.registration.selector.replace(/[[\]]/g, '');
    const id = this._attribute.split('-').pop();
    this._type = Object.values(Type$1).filter(type => type.id === id)[0];
    this._title = this.getAttribute(this._attribute);
    if (this._type === Type$1.CLICK) this.detectInteractionType();

    switch (this._type.method) {
      case 'eventListener':
        this.listen(this._type.event, this.handleEvent.bind(this));
        break;

      case 'change':
        this.listen(this._type.event, this.handleChange.bind(this));
        break;
    }
  }

  handleEvent (e) {
    this._actionElement.act();
  }

  handleChange (e) {
    this._actionElement.act({ change_value: e.target.value });
  }

  dispose () {
    this._actionElement.dispose();
    super.dispose();
  }
}

const integrateAttributes = () => {
  Object.values(Type$1)
    .filter(type => type.attributed)
    .forEach(type => api.internals.register(api.internals.ns.attr.selector(`analytics-${type.id}`), AttributeActionee));
};

const ButtonEmission = {
  CLICK: api.internals.ns.emission('button', 'click')
};

class ComponentActionee extends Actionee {
  constructor (priority = -1) {
    super(priority, 'dsfr_component');
  }

  static get instanceClassName () {
    return 'ComponentActionee';
  }

  get proxy () {
    const scope = this;

    const proxyAccessors = {
      get component () {
        return scope.component;
      }
    };

    return api.internals.property.completeAssign(super.proxy, proxyAccessors);
  }

  setDiscloseType () {
    this._type = Type$1.DISCLOSE;
  }

  listenDisclose () {
    this.listen(api.core.DisclosureEvent.DISCLOSE, this._handleDisclose.bind(this), { capture: true });
  }

  _handleDisclose () {
    this.act();
  }

  setChangeType () {
    this._type = Type$1.CHANGE;
  }

  listenChange () {
    this.listen('change', this._handleChange.bind(this), { capture: true });
  }

  _handleChange (e) {
    if (e.target && e.target.value) {
      this.setChangeValue(e);
      this.act();
    }
  }

  setChangeValue (e) {
    this.value = e.target.value;
  }

  listenInputValidation (node, type = Type$1.CLICK, isSendingInputValue = false) {
    if (!node) node = this.node;
    this._type = type;
    this._isSendingInputValue = isSendingInputValue;
    this.addAscent(ButtonEmission.CLICK, this._actValidatedInput.bind(this));
    const button = this.element.getDescendantInstances('ButtonActionee', null, true)[0];
    if (button) button.isMuted = true;
    this._validatedInput = node.querySelector('input');
    this._handlingInputValidation = this._handleInputValidation.bind(this);
    if (this._validatedInput) this._validatedInput.addEventListener('keydown', this._handlingInputValidation);
  }

  _handleInputValidation (e) {
    if (e.keyCode === 13) this._actValidatedInput();
  }

  _actValidatedInput () {
    if (this._isActingValidatedInput) return;
    this._isActingValidatedInput = true;
    if (this._isSendingInputValue) this.value = this._validatedInput.value.trim();
    this.act();
    this.request(this._actedValidatedInput.bind(this));
  }

  _actedValidatedInput () {
    this._isActingValidatedInput = false;
  }

  setCheckType () {
    this._type = Type$1.CHECK;
  }

  detectCheckableType () {
    const isChecked = this.node.checked;
    this._type = isChecked ? Type$1.UNCHECK : Type$1.CHECK;
  }

  listenCheckable () {
    this.listen('change', this._handleCheckable.bind(this), { capture: true });
  }

  _handleCheckable (e) {
    if (e.target && e.target.value !== 'on') {
      this.value = e.target.value;
    }

    switch (true) {
      case this._type === Type$1.CHECK && e.target.checked:
      case this._type === Type$1.UNCHECK && !e.target.checked:
        this.act();
        break;
    }
  }

  detectPressableType () {
    const isPressable = this.node.hasAttribute('aria-pressed');
    if (isPressable) {
      const isPressed = this.node.getAttribute('aria-pressed') === 'true';
      this._type = isPressed ? Type$1.RELEASE : Type$1.PRESS;
    }
    return isPressable;
  }

  listenPressable () {
    this.listen('click', this._handlePressable.bind(this), { capture: true });
  }

  _handlePressable (e) {
    switch (true) {
      case this._type === Type$1.PRESS && e.target.getAttribute('aria-pressed') === 'false':
      case this._type === Type$1.RELEASE && e.target.getAttribute('aria-pressed') === 'true':
        this.act();
        break;
    }
  }

  setDismissType () {
    this._type = Type$1.DISMISS;
  }

  get component () {
    return null;
  }

  dispose () {
    if (this._validatedInput) {
      this._validatedInput.removeEventListener('keydown', this._handlingInputValidation);
    }

    super.dispose();
  }
}

const AccordionSelector = {
  ACCORDION: api.internals.ns.selector('accordion'),
  TITLE: api.internals.ns.selector('accordion__title')
};

const ID$x = 'accordion';

class AccordionButtonActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'AccordionButtonActionee';
  }

  init () {
    this.isMuted = true;
  }

  get button () {
    return this.element.getInstance('CollapseButton');
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;

    return 'bouton d\'accordéon';
  }

  get component () {
    return ID$x;
  }
}

class AccordionActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'AccordionActionee';
  }

  init () {
    this.setDiscloseType();
    this.wrapper = this.node.closest(AccordionSelector.ACCORDION);
    this.detectLevel(this.wrapper);
    this.register(`[aria-controls="${this.id}"]`, AccordionButtonActionee);
    this.listenDisclose();
  }

  get label () {
    if (this.wrapper) {
      const title = this.wrapper.querySelector(AccordionSelector.TITLE);
      if (title) {
        const text = this.getFirstText(title);
        if (text) return text;
      }
    }
    const instance = this.element.getInstance('Collapse');
    if (instance) {
      const button = instance.buttons.filter(button => button.isPrimary)[0];
      if (button) {
        const text = this.getFirstText(button);
        if (text) return text;
      }
    }
    return 'accordéon';
  }

  get component () {
    return ID$x;
  }

  dispose () {
    super.dispose();
  }
}

const integrateAccordion = () => {
  if (api.accordion) {
    api.internals.register(api.accordion.AccordionSelector.COLLAPSE, AccordionActionee);
  }
};

const AlertSelector = {
  ALERT: api.internals.ns.selector('alert'),
  TITLE: api.internals.ns.selector('alert__title')
};

const ID$w = 'alert';

class AlertActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'AlertActionee';
  }

  get label () {
    const alertTitle = this.node.querySelector(AlertSelector.TITLE);
    if (alertTitle) {
      const text = this.getFirstText(alertTitle);
      if (text) return text;
    }
    return 'alerte';
  }

  get component () {
    return ID$w;
  }
}

const integrateAlert = () => {
  api.internals.register(AlertSelector.ALERT, AlertActionee);
};

const BreadcrumbSelector = {
  LINK: `${api.internals.ns.selector('breadcrumb__link')}:not([aria-current])`,
  COLLAPSE: `${api.internals.ns.selector('breadcrumb')} ${api.internals.ns.selector('collapse')}`
};

const ID$v = 'breadcrumb';

class BreadcrumbActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'BreadcrumbActionee';
  }

  get label () {
    return 'fil d\'ariane';
  }

  get component () {
    return ID$v;
  }
}

class BreadcrumbLinkActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'BreadcrumbLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  handleClick () {
    this.act();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;
    return 'lien fil d\'ariane';
  }

  get component () {
    return null;
  }
}

const integrateBreadcrumb = () => {
  if (api.breadcrumb) {
    api.internals.register(BreadcrumbSelector.COLLAPSE, BreadcrumbActionee);
    api.internals.register(BreadcrumbSelector.LINK, BreadcrumbLinkActionee);
  }
};

const ButtonSelector = {
  BUTTON: `${api.internals.ns.selector('btn')}:not(${api.internals.ns.selector('btn--close')})`
};

const ID$u = 'button';

class ButtonActionee extends ComponentActionee {
  constructor () {
    super(1);
    this._data = {};
  }

  static get instanceClassName () {
    return 'ButtonActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  handleClick () {
    this.ascend(ButtonEmission.CLICK);
    this.act();
  }

  get label () {
    if (this.node.tagName === 'input') {
      switch (this.node.type) {
        case 'button':
        case 'submit':
          if (this.hasAttribute('value')) return this.getAttribute('value');
      }
    }
    const firstText = this.getFirstText();
    if (firstText) return firstText;
    return 'bouton';
  }

  get component () {
    return ID$u;
  }
}

const integrateButton = () => {
  api.internals.register(ButtonSelector.BUTTON, ButtonActionee);
};

const CalloutSelector = {
  CALLOUT: api.internals.ns.selector('callout'),
  TITLE: api.internals.ns.selector('callout__title')
};

const ID$t = 'callout';

class CalloutActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'CalloutActionee';
  }

  get label () {
    const calloutTitle = this.node.querySelector(CalloutSelector.TITLE);
    if (calloutTitle) {
      const text = this.getFirstText(calloutTitle);
      if (text) return text;
    }

    return 'mise en avant';
  }

  get component () {
    return ID$t;
  }
}

const integrateCallout = () => {
  api.internals.register(CalloutSelector.CALLOUT, CalloutActionee);
};

const CardSelector = {
  CARD: api.internals.ns.selector('card'),
  LINK: `${api.internals.ns.selector('card__title')} a, ${api.internals.ns.selector('card__title')} button`,
  TITLE: api.internals.ns.selector('card__title')
};

const ID$s = 'card';

class CardActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'CardActionee';
  }

  init () {
    const link = this.node.querySelector(CardSelector.LINK);
    if (link) {
      this.link = link;
      this.detectInteractionType(link);
      this.listenActionClick(link);
    }
  }

  get label () {
    const cardTitle = this.node.querySelector(CardSelector.TITLE);
    if (cardTitle) {
      const text = this.getFirstText(cardTitle);
      if (text) return text;
    }

    const heading = this.getHeadingLabel();
    if (heading) return heading;

    return 'carte';
  }

  get component () {
    return ID$s;
  }
}

const integrateCard = () => {
  api.internals.register(CardSelector.CARD, CardActionee);
};

const CheckboxSelector = {
  INPUT: api.internals.ns.selector('checkbox-group [type="checkbox"]')
};

const ID$r = 'checkbox';

class CheckboxActionee extends ComponentActionee {
  constructor () {
    super(1);
    this._data = {};
  }

  static get instanceClassName () {
    return 'CheckboxActionee';
  }

  init () {
    this.detectCheckableType();
    this.listenCheckable();
  }

  get label () {
    const label = this.node.parentNode.querySelector(api.internals.ns.selector('label'));
    if (label) {
      const text = this.getFirstText(label);
      if (text) return text;
    }
    return 'case à cocher';
  }

  get component () {
    return ID$r;
  }
}

const integrateCheckbox = () => {
  api.internals.register(CheckboxSelector.INPUT, CheckboxActionee);
};

const ConnectSelector = {
  CONNECT: api.internals.ns.selector('connect'),
  LINK: api.internals.ns.selector('connect + * a, connect + a')
};

const ID$q = 'connect';

class ConnectActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'ConnectActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    if (this.node.classList.contains('fr-connect--plus')) return 'FranceConnect+';
    return 'FranceConnect';
  }

  get component () {
    return ID$q;
  }
}

class ConnectLinkActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'ConnectLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    return this.getFirstText() || 'qu\'est-ce que FranceConnect ?';
  }

  get component () {
    return ID$q;
  }
}

const integrateConnect = () => {
  api.internals.register(ConnectSelector.CONNECT, ConnectActionee);
  api.internals.register(ConnectSelector.LINK, ConnectLinkActionee);
};

const ConsentSelector = {
  BANNER: api.internals.ns.selector('consent-banner')
};

const ID$p = 'consent';

class ConsentActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'ConsentActionee';
  }

  get label () {
    return 'gestionnaire de consentement';
  }

  get component () {
    return ID$p;
  }
}

const integrateConsent = () => {
  api.internals.register(ConsentSelector.BANNER, ConsentActionee);
};

const DownloadSelector = {
  LINK: api.internals.ns.selector('download__link')
};

const ID$o = 'download';

class DownloadActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'DownloadActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const text = this.getFirstText();
    if (text) return text;
    return 'téléchargement';
  }

  get component () {
    return ID$o;
  }
}

const integrateDownload = () => {
  api.internals.register(DownloadSelector.LINK, DownloadActionee);
};

const FollowSelector = {
  FOLLOW: api.internals.ns.selector('follow'),
  NEWSLETTER_INPUT_GROUP: api.internals.ns.selector('follow__newsletter') + ' ' + api.internals.ns.selector('input-group')
};

const ID$n = 'follow';

class FollowActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'FollowActionee';
  }

  init () {
    this._inputGroup = this.querySelector(FollowSelector.NEWSLETTER_INPUT_GROUP);
    if (this._inputGroup) {
      this.listenInputValidation(this._inputGroup, Type$1.SUBSCRIBE);
      const input = this.element.getDescendantInstances('InputActionee', null, true)[0];
      if (input) input.isMuted = true;
    }
  }

  get label () {
    return 'lettre d\'information et réseaux sociaux';
  }

  get component () {
    return ID$n;
  }
}

const integrateFollow = () => {
  api.internals.register(FollowSelector.FOLLOW, FollowActionee);
};

const FooterSelector = {
  FOOTER: api.internals.ns.selector('footer'),
  FOOTER_LINKS: `${api.internals.ns.selector('footer')} a[href], ${api.internals.ns.selector('footer')} button`
};

const ID$m = 'footer';

class FooterActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'FooterActionee';
  }

  get label () {
    return 'pied de page';
  }

  get component () {
    return ID$m;
  }
}

class FooterLinkActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'FooterLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const label = this.getInteractionLabel();
    if (label) return label;

    return 'lien pied de page';
  }
}

const integrateFooter = () => {
  api.internals.register(FooterSelector.FOOTER, FooterActionee);
  api.internals.register(FooterSelector.FOOTER_LINKS, FooterLinkActionee);
};

const ID$l = 'header';

class HeaderActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'HeaderActionee';
  }

  get label () {
    return 'en-tête';
  }

  get component () {
    return ID$l;
  }
}

class HeaderModalButtonActionee extends ComponentActionee {
  constructor () {
    super(4);
  }

  static get instanceClassName () {
    return 'HeaderModalButtonActionee';
  }
}

class HeaderModalActionee extends ComponentActionee {
  constructor () {
    super(0);
  }

  static get instanceClassName () {
    return 'HeaderModalActionee';
  }

  init () {
    if (this.isBreakpoint(api.core.Breakpoints.LG)) {
      this.setPriority(4);
      this.register(`[aria-controls="${this.id}"]`, HeaderModalButtonActionee);
    }
  }
}

const HeaderSelector = {
  TOOLS_BUTTON: `${api.internals.ns.selector('header__tools-links')} ${api.internals.ns.selector('btns-group')} ${api.internals.ns.selector('btn')}`,
  MENU_BUTTON: `${api.internals.ns.selector('header__menu-links')} ${api.internals.ns.selector('btns-group')} ${api.internals.ns.selector('btn')}`
};

class HeaderToolsButtonActionee extends ComponentActionee {
  constructor () {
    super(4);
  }

  static get instanceClassName () {
    return 'HeaderToolsButtonActionee';
  }

  init () {
    if (this.isBreakpoint(api.core.Breakpoints.LG)) this._priority = -1;
  }
}

class HeaderMenuButtonActionee extends ComponentActionee {
  static get instanceClassName () {
    return 'HeaderMenuButtonActionee';
  }

  init () {
    if (this.isBreakpoint(api.core.Breakpoints.LG)) this.setPriority(4);
  }
}

const integrateHeader = () => {
  if (api.header) {
    api.internals.register(api.header.HeaderSelector.HEADER, HeaderActionee);
    api.internals.register(api.header.HeaderSelector.MODALS, HeaderModalActionee);
    api.internals.register(HeaderSelector.TOOLS_BUTTON, HeaderToolsButtonActionee);
    api.internals.register(HeaderSelector.MENU_BUTTON, HeaderMenuButtonActionee);
  }
};

const HighlightSelector = {
  HIGHLIGHT: api.internals.ns.selector('highlight')
};

const ID$k = 'highlight';

class HighlightActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'HighlightActionee';
  }

  get label () {
    return 'mise en exergue';
  }

  get component () {
    return ID$k;
  }
}

const integrateHighlight = () => {
  api.internals.register(HighlightSelector.HIGHLIGHT, HighlightActionee);
};

const LinkSelector = {
  LINK: api.internals.ns.selector('link')
};

const ID$j = 'link';

class LinkActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'LinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;

    return 'lien';
  }

  get component () {
    return ID$j;
  }
}

const integrateLink = () => {
  api.internals.register(LinkSelector.LINK, LinkActionee);
};

const InputSelector = {
  INPUT: api.internals.ns.selector('input-group')
};

const ID$i = 'input';

class InputActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'InputActionee';
  }

  init () {
    this._input = this.querySelector(api.internals.ns.selector('input'));
    this._label = this.querySelector(api.internals.ns.selector('label'));
    this._inputWrap = this.querySelector(api.internals.ns.selector('input-wrap'));

    if (this._inputWrap) this.listenInputValidation(this._inputWrap);
  }

  get label () {
    if (this._label) {
      const text = this.getFirstText(this._label);
      if (text) return text;
    }

    return 'champ de saisie';
  }

  get component () {
    return ID$i;
  }
}

const integrateInput = () => {
  api.internals.register(InputSelector.INPUT, InputActionee);
};

const ModalSelector = {
  TITLE: api.internals.ns.selector('modal__title')
};

const ID$h = 'modal';

class ModalActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'ModalActionee';
  }

  init () {
    this.setDiscloseType();
    this.detectLevel();
    this.listenDisclose();
  }

  get label () {
    const title = this.node.querySelector(ModalSelector.TITLE);

    if (title) {
      const text = this.getFirstText(title);
      if (text) return text;
    }

    const heading = this.getHeadingLabel(2);
    if (heading) return heading;

    const instance = this.element.getInstance('Modal');
    if (instance) {
      const button = instance.buttons.filter(button => button.isPrimary)[0];
      if (button) {
        const text = this.getFirstText(button.node);
        if (text) return text;
      }
    }
    return 'modale';
  }

  get component () {
    return ID$h;
  }
}

const integrateModal = () => {
  if (api.modal) {
    api.internals.register(api.modal.ModalSelector.MODAL, ModalActionee);
  }
};

class NavigationActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'NavigationActionee';
  }

  get label () {
    return 'navigation';
  }
}

const NavigationSelector = {
  LINK: api.internals.ns.selector('nav__link'),
  BUTTON: api.internals.ns.selector('nav__btn')
};

const ID$g = 'navigation';

class NavigationLinkActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'NavigationLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;

    return 'lien de navigation';
  }

  get component () {
    return ID$g;
  }
}

class NavigationSectionActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'NavigationSectionActionee';
  }

  init () {
    this._wrapper = this.node.closest(api.navigation.NavigationSelector.ITEM);
  }

  get label () {
    if (this._wrapper) {
      const button = this._wrapper.querySelector(NavigationSelector.BUTTON);
      if (button) {
        const text = this.getFirstText(button);
        if (text) return text;
      }
    }

    const instance = this.element.getInstance('Collapse');
    if (instance) {
      const button = instance.buttons.filter(button => button.isPrimary)[0];
      if (button) {
        const text = this.getFirstText(button);
        if (text) return text;
      }
    }
    return 'section de navigation';
  }
}

const integrateNavigation = () => {
  if (api.navigation) {
    api.internals.register(api.navigation.NavigationSelector.NAVIGATION, NavigationActionee);
    api.internals.register(NavigationSelector.LINK, NavigationLinkActionee);
    api.internals.register(api.navigation.NavigationSelector.COLLAPSE, NavigationSectionActionee);
  }
};

const PaginationSelector = {
  PAGINATION: api.internals.ns.selector('pagination'),
  LINK: api.internals.ns.selector('pagination__link'),
  NEXT_LINK: api.internals.ns.selector('pagination__link--next'),
  LAST_LINK: api.internals.ns.selector('pagination__link--last'),
  ANALYTICS_TOTAL: api.internals.ns.attr('analytics-page-total'),
  CURRENT: '[aria-current="page"]'
};

const ID$f = 'pagination';

class PaginationActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'PaginationActionee';
  }

  init () {
    this.setPagination();
  }

  get label () {
    return 'pagination';
  }

  get component () {
    return ID$f;
  }

  setPagination () {
    const currentLink = this.node.querySelector(PaginationSelector.CURRENT);
    if (!currentLink) return;
    const currentLabel = this.getFirstText(currentLink);
    if (!currentLabel) return;
    const current = this.getInt(currentLabel);
    if (isNaN(current)) return;
    api.analytics.page.current = current;

    const total = this.getTotalPage();
    if (isNaN(total)) return;
    api.analytics.page.total = total;
  }

  getTotalPage () {
    const attr = parseInt(this.node.getAttribute(PaginationSelector.ANALYTICS_TOTAL));
    if (!isNaN(attr)) return attr;
    const links = this.node.querySelectorAll(`${PaginationSelector.LINK}:not(${PaginationSelector.NEXT_LINK}):not(${PaginationSelector.LAST_LINK})`);
    if (!links) return null;
    const totalLabel = this.getFirstText(links[links.length - 1]);
    if (!totalLabel) return null;
    return this.getInt(totalLabel);
  }

  getInt (val) {
    const ints = val.match(/\d+/);
    if (!ints || ints.length === 0) return null;
    return parseInt(ints[0]);
  }
}

class PaginationLinkActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'PaginationLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;
    return 'lien pagination';
  }

  get component () {
    return null;
  }
}

const integratePagination = () => {
  api.internals.register(PaginationSelector.PAGINATION, PaginationActionee);
  api.internals.register(PaginationSelector.LINK, PaginationLinkActionee);
};

const QuoteSelector = {
  QUOTE: api.internals.ns.selector('quote')
};

const ID$e = 'quote';

class QuoteActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'QuoteActionee';
  }

  get label () {
    const blockquote = this.node.querySelector('blockquote');
    if (blockquote) {
      const firstText = this.getFirstText(blockquote);
      if (firstText) {
        return firstText;
      }
    }
    return 'citation';
  }

  get component () {
    return ID$e;
  }
}

const integrateQuote = () => {
  api.internals.register(QuoteSelector.QUOTE, QuoteActionee);
};

const RadioSelector = {
  INPUT: api.internals.ns.selector('radio-group [type="radio"]')
};

const FormSelector = {
  LABEL: api.internals.ns.selector('label'),
  FIELDSET: api.internals.ns.selector('fieldset'),
  LEGEND: api.internals.ns.selector('fieldset__legend')
};

const ID$d = 'radio';

class RadioActionee extends ComponentActionee {
  constructor () {
    super(1);
    this._data = {};
  }

  static get instanceClassName () {
    return 'RadioActionee';
  }

  init () {
    this.setCheckType();
    this.listenCheckable();
  }

  get label () {
    const parts = [];
    const fieldset = this.node.closest(FormSelector.FIELDSET);
    if (fieldset) {
      const legend = fieldset.querySelector(FormSelector.LEGEND);
      if (legend) {
        const firstTextLegend = this.getFirstText(legend);
        if (firstTextLegend) parts.push(firstTextLegend);
      }
    }
    const label = this.node.parentNode.querySelector(api.internals.ns.selector('label'));
    if (label) {
      const firstTextLabel = this.getFirstText(label);
      if (firstTextLabel) parts.push(firstTextLabel);
    }
    return parts.join(' › ');
  }

  get component () {
    return ID$d;
  }
}

const integrateRadio = () => {
  api.internals.register(RadioSelector.INPUT, RadioActionee);
};

const SearchSelector = {
  SEARCH_BAR: api.internals.ns.selector('search-bar')
};

const ID$c = 'search';

class SearchActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'SearchActionee';
  }

  init () {
    this.listenInputValidation(this.node, Type$1.SEARCH, true);
  }

  get label () {
    return 'barre de recherche';
  }

  get component () {
    return ID$c;
  }
}

const integrateSearch = () => {
  api.internals.register(SearchSelector.SEARCH_BAR, SearchActionee);
};

const SelectSelector = {
  SELECT: api.internals.ns.selector('select')
};

const ID$b = 'select';

class SelectActionee extends ComponentActionee {
  constructor () {
    super(1);
    this._data = {};
  }

  static get instanceClassName () {
    return 'SelectActionee';
  }

  init () {
    this.setChangeType();
    this.listenChange();
  }

  setChangeValue (e) {
    if (!e.target || !e.target.selectedOptions) return;
    const value = Array.from(e.target.selectedOptions).map(option => option.text).join(' - ');
    if (value) this.value = value;
  }

  get label () {
    const label = this.node.parentNode.querySelector(api.internals.ns.selector('label'));
    if (label) {
      const firstText = this.getFirstText(label);
      if (firstText) return firstText;
    }

    return 'liste déroulante';
  }

  get component () {
    return ID$b;
  }
}

const integrateSelect = () => {
  api.internals.register(SelectSelector.SELECT, SelectActionee);
};

const ShareSelector = {
  SHARE: api.internals.ns.selector('share'),
  TITLE: api.internals.ns.selector('share__title')
};

const ID$a = 'share';

class ShareActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'ShareActionee';
  }

  get label () {
    const title = this.querySelector(ShareSelector.TITLE);
    if (title) {
      const firstText = this.getFirstText(title);
      if (firstText) return firstText;
    }
    return 'boutons de partage';
  }

  get component () {
    return ID$a;
  }
}

const integrateShare = () => {
  api.internals.register(ShareSelector.SHARE, ShareActionee);
};

const SidemenuSelector = {
  SIDEMENU: api.internals.ns.selector('sidemenu'),
  ITEM: api.internals.ns.selector('sidemenu__item'),
  LINK: api.internals.ns.selector('sidemenu__link'),
  BUTTON: api.internals.ns.selector('sidemenu__btn'),
  TITLE: api.internals.ns.selector('sidemenu__title')
};

class SidemenuActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'SidemenuActionee';
  }

  get label () {
    const sidemenu = this.node.closest(SidemenuSelector.SIDEMENU);
    if (sidemenu) {
      const title = sidemenu.querySelector(SidemenuSelector.TITLE);
      if (title) {
        const firstText = this.getFirstText(title);
        if (firstText) return firstText;
      }
    }

    return 'menu Latéral';
  }
}

const ID$9 = 'sidemenu';

class SidemenuLinkActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'SidemenuLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;

    return 'lien menu latéral';
  }

  get component () {
    return ID$9;
  }
}

class SidemenuSectionActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'SidemenuSectionActionee';
  }

  init () {
    this._wrapper = this.node.closest(SidemenuSelector.ITEM);
  }

  get label () {
    if (this._wrapper) {
      const button = this._wrapper.querySelector(SidemenuSelector.BUTTON);
      if (button) {
        const firstText = this.getFirstText(button);
        if (firstText) return firstText;
      }
    }
    const instance = this.element.getInstance('Collapse');
    if (instance) {
      const button = instance.buttons.filter(button => button.isPrimary)[0];
      if (button) {
        const firstTextBtn = this.getFirstText(button);
        if (firstTextBtn) return firstTextBtn;
      }
    }
    return 'section menu latéral';
  }
}

const integrateSidemenu = () => {
  if (api.sidemenu) {
    api.internals.register(SidemenuSelector.SIDEMENU, SidemenuActionee);
    api.internals.register(SidemenuSelector.LINK, SidemenuLinkActionee);
    api.internals.register(api.sidemenu.SidemenuSelector.COLLAPSE, SidemenuSectionActionee);
  }
};

const SummarySelector = {
  SUMMARY: api.internals.ns.selector('summary'),
  LINK: api.internals.ns.selector('summary__link'),
  TITLE: api.internals.ns.selector('summary__title'),
  ITEM: `${api.internals.ns.selector('summary')} li`
};

class SummaryActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'SummaryActionee';
  }

  get label () {
    const title = this.node.querySelector(SummarySelector.TITLE);
    if (title) {
      const firstText = this.getFirstText(title);
      if (firstText) return firstText;
    }
    return 'sommaire';
  }
}

const ID$8 = 'summary';

class SummaryLinkActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'SummaryLinkActionee';
  }

  init () {
    this.detectInteractionType();
    this.listenActionClick();
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;
    return 'lien sommaire';
  }

  get component () {
    return ID$8;
  }
}

class SummarySectionActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'SummarySectionActionee';
  }

  init () {
    this._link = this.querySelector(SummarySelector.LINK);
  }

  validate (target) {
    return this._link !== target;
  }

  get label () {
    if (!this._link) return null;
    const firstText = this.getFirstText(this._link);
    if (firstText) return firstText;
    return 'section sommaire';
  }
}

const integrateSummary = () => {
  api.internals.register(SummarySelector.SUMMARY, SummaryActionee);
  api.internals.register(SummarySelector.LINK, SummaryLinkActionee);
  api.internals.register(SummarySelector.ITEM, SummarySectionActionee);
};

const ID$7 = 'tab';

class TabButtonActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TabButtonActionee';
  }

  init () {
    this.isMuted = true;
  }

  get label () {
    const text = this.getFirstText();
    if (text) return text;
    return 'bouton onglet';
  }

  get component () {
    return ID$7;
  }
}

class TabActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TabActionee';
  }

  init () {
    this.setDiscloseType();
    this.register(`[aria-controls="${this.id}"]`, TabButtonActionee);
    this._instance = this.element.getInstance('TabPanel');
    this.listenDisclose();
  }

  get label () {
    const tabs = this.node.closest(api.tab.TabSelector.GROUP);
    if (tabs) {
      const tab = tabs.querySelector(`${api.tab.TabSelector.LIST} [aria-controls="${this.id}"]${api.tab.TabSelector.TAB}`);
      if (tab) {
        const firstTextTab = this.getFirstText(tab);
        if (firstTextTab) return firstTextTab;
      }
    }

    const button = this._instance.buttons.filter(button => button.isPrimary)[0];
    if (button) {
      const firstTextBtn = this.getFirstText(button);
      if (firstTextBtn) return firstTextBtn;
    }
    return 'onglet';
  }

  get component () {
    return ID$7;
  }
}

const integrateTab = () => {
  if (api.tab) {
    api.internals.register(api.tab.TabSelector.PANEL, TabActionee);
  }
};

const TableSelector = {
  TABLE: api.internals.ns.selector('table')
};

const ID$6 = 'table';

class TableActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'TableActionee';
  }

  get label () {
    const caption = this.node.querySelector('caption');
    if (caption) {
      const firstText = this.getFirstText(caption);
      if (firstText) return firstText;
    }
    return 'tableau';
  }

  get component () {
    return ID$6;
  }
}

const integrateTable = () => {
  api.internals.register(TableSelector.TABLE, TableActionee);
};

const TagSelector = {
  TAG: api.internals.ns.selector('tag'),
  PRESSABLE: '[aria-pressed]',
  DISMISSIBLE: `${api.internals.ns.selector('tag--dismiss', '')}`
};

const ID$5 = 'tag';

class TagActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TagActionee';
  }

  init () {
    switch (true) {
      case this.detectPressableType():
        this.listenPressable();
        break;

      case this.isInteractive && this.node.classList.contains(TagSelector.DISMISSIBLE):
        this.setDismissType();
        this.listenActionClick();
        break;

      case this.isInteractive:
        this.detectInteractionType();
        this.listenActionClick();
        break;
    }
  }

  get label () {
    const firstText = this.getFirstText();
    if (firstText) return firstText;

    return 'tag';
  }

  get component () {
    return ID$5;
  }
}

const integrateTag = () => {
  api.internals.register(TagSelector.TAG, TagActionee);
};

const TileSelector = {
  TILE: api.internals.ns.selector('tile'),
  LINK: `${api.internals.ns.selector('tile__title')} a, ${api.internals.ns.selector('tile__title')} button`,
  TITLE: api.internals.ns.selector('tile__title')
};

const ID$4 = 'tile';

class TileActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'TileActionee';
  }

  init () {
    const link = this.node.querySelector(TileSelector.LINK);
    if (link) {
      this.link = link;
      this.detectInteractionType(link);
      this.listenActionClick(link);
    }
  }

  get label () {
    const tileTitle = this.node.querySelector(TileSelector.TITLE);
    if (tileTitle) return this.getFirstText(tileTitle);

    const heading = this.getHeadingLabel();
    if (heading) return heading;

    return 'tuile';
  }

  get component () {
    return ID$4;
  }
}

const integrateTile = () => {
  api.internals.register(TileSelector.TILE, TileActionee);
};

const ToggleSelector = {
  INPUT: api.internals.ns.selector('toggle [type="checkbox"]')
};

const ID$3 = 'toggle';

class ToggleActionee extends ComponentActionee {
  constructor () {
    super(1);
    this._data = {};
  }

  static get instanceClassName () {
    return 'ToggleActionee';
  }

  init () {
    this.detectCheckableType();
    this.listenCheckable();
  }

  get label () {
    const label = this.node.parentNode.querySelector(api.internals.ns.selector('toggle__label'));
    if (label) {
      const firstText = this.getFirstText(label);
      if (firstText) return firstText;
    }

    return 'interrupteur';
  }

  get component () {
    return ID$3;
  }
}

const integrateToggle = () => {
  api.internals.register(ToggleSelector.INPUT, ToggleActionee);
};

const TRANSCRIPTION = api.internals.ns.selector('transcription');
const COLLAPSE$1 = api.internals.ns.selector('collapse');

const TranscriptionSelector = {
  TRANSCRIPTION: TRANSCRIPTION,
  COLLAPSE: `${TRANSCRIPTION} > ${COLLAPSE$1}, ${TRANSCRIPTION} > *:not(${TRANSCRIPTION}):not(${COLLAPSE$1}) > ${COLLAPSE$1}, ${TRANSCRIPTION} > *:not(${TRANSCRIPTION}):not(${COLLAPSE$1}) > *:not(${TRANSCRIPTION}):not(${COLLAPSE$1}) > ${COLLAPSE$1}`,
  COLLAPSE_LEGACY: `${TRANSCRIPTION} ${COLLAPSE$1}`,
  TITLE: `${TRANSCRIPTION}__title`
};

const ID$2 = 'transcription';

class TranscriptionButtonActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TranscriptionButtonActionee';
  }

  init () {
    this.isMuted = true;
  }

  get button () {
    return this.element.getInstance('CollapseButton');
  }

  get label () {
    const text = this.getFirstText();
    if (text) return text;
    return 'bouton transcription';
  }

  get component () {
    return ID$2;
  }
}

class TranscriptionActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TranscriptionActionee';
  }

  init () {
    this.setDiscloseType();
    this.wrapper = this.node.closest(TranscriptionSelector.ACCORDION);
    this.detectLevel(this.wrapper);
    this.register(`[aria-controls="${this.id}"]`, TranscriptionButtonActionee);
    this.listenDisclose();
  }

  get label () {
    if (this.wrapper) {
      const title = this.wrapper.querySelector(TranscriptionSelector.TITLE);
      if (title) {
        const firstTextTitle = this.getFirstText(title);
        if (firstTextTitle) return firstTextTitle;
      }
    }
    const instance = this.element.getInstance('Collapse');
    if (instance) {
      const button = instance.buttons.filter(button => button.isPrimary)[0];
      if (button) {
        const firstTextBtn = this.getFirstText(button);
        if (firstTextBtn) return firstTextBtn;
      }
    }
    return 'transcription';
  }

  get component () {
    return ID$2;
  }
}

const integrateTranscription = () => {
  api.internals.register(TranscriptionSelector.COLLAPSE, TranscriptionActionee);
};

const TRANSLATE = api.internals.ns.selector('translate');
const COLLAPSE = api.internals.ns.selector('collapse');

const TranslateSelector = {
  BUTTON: `${TRANSLATE}__btn`,
  COLLAPSE: `${TRANSLATE} > ${COLLAPSE}, ${TRANSLATE} > *:not(${TRANSLATE}):not(${COLLAPSE}) > ${COLLAPSE}, ${TRANSLATE} > *:not(${TRANSLATE}):not(${COLLAPSE}) > *:not(${TRANSLATE}):not(${COLLAPSE}) > ${COLLAPSE}`,
  COLLAPSE_LEGACY: `${TRANSLATE} ${COLLAPSE}`
};

const ID$1 = 'translate';

class TranslateActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TranslateActionee';
  }

  get label () {
    const button = this.node.querySelector(TranslateSelector.BUTTON);
    if (button) {
      const title = button.getAttribute('title');
      if (title) return title;
    }

    return 'sélecteur de langue';
  }

  get component () {
    return ID$1;
  }
}

class TranslateButtonActionee extends ComponentActionee {
  constructor () {
    super(2);
  }

  static get instanceClassName () {
    return 'TranslateButtonActionee';
  }

  init () {
    this.isMuted = true;
  }

  get button () {
    return this.element.getInstance('CollapseButton');
  }

  get label () {
    const label = this.getInteractionLabel();
    if (label) return label;
    return 'bouton sélecteur de langue';
  }

  get component () {
    return ID$1;
  }
}

const integrateTranslate = () => {
  api.internals.register(TranslateSelector.COLLAPSE, TranslateActionee);
  api.internals.register(TranslateSelector.BUTTON, TranslateButtonActionee);
};

const UploadSelector = {
  UPLOAD: api.internals.ns.selector('upload')
};

const ID = 'upload';

class UploadActionee extends ComponentActionee {
  constructor () {
    super(1);
  }

  static get instanceClassName () {
    return 'UploadActionee';
  }

  init () {
    this.setChangeType();
    this._label = this.node.parentNode.querySelector(api.internals.ns.selector('label'));
    this.listenChange();
  }

  setChangeValue (e) {
    if (!e.target || !e.target.files) return;
    const value = Array.from(e.target.files).map(file => /(?:\.([^.]+))?$/.exec(file.name)[1]).filter((name, index, array) => array.indexOf(name) === index).join(' - ');
    if (value) this.value = value;
  }

  get label () {
    if (this._label) {
      const text = this.getFirstText(this._label);
      if (text) return text;
    }

    return 'ajout de fichier';
  }

  get component () {
    return ID;
  }
}

const integrateUpload = () => {
  api.internals.register(UploadSelector.UPLOAD, UploadActionee);
};

const integrateComponents = () => {
  integrateAccordion();
  integrateBreadcrumb();
  integrateAlert();
  // integrateBadge();
  integrateButton();
  integrateCallout();
  integrateConnect();
  integrateConsent();
  // integrateContent();
  integrateCard();
  integrateInput();
  integrateCheckbox();
  integrateDownload();
  integrateFooter();
  integrateFollow();
  integrateHeader();
  integrateHighlight();
  integrateLink();
  integrateModal();
  integrateNavigation();
  // integrateNotice();
  integratePagination();
  integrateQuote();
  integrateRadio();
  integrateSearch();
  integrateSelect();
  integrateShare();
  integrateSidemenu();
  // integrateStepper();
  integrateSummary();
  integrateTab();
  integrateTable();
  integrateTag();
  integrateTile();
  integrateToggle();
  // integrateTooltip();
  integrateTranscription();
  integrateTranslate();
  integrateUpload();
};

// import './core/core';

const integration = () => {
  integrateAttributes();
  integrateComponents();
};

api.analytics.readiness.then(() => integration(), () => {});
//# sourceMappingURL=analytics.module.js.map
