Commit e31850dc authored by Alexandre Dias's avatar Alexandre Dias
Browse files

Issue #3279207: Add support for onlyCountries

parent c4af1e8d
Loading
Loading
Loading
Loading
+24 −15
Original line number Diff line number Diff line
@@ -4,54 +4,63 @@ phone_international:
  mapping:
    geolocation:
      type: boolean
      label: 'Geolocation'
      label: 'Enable Geolocation'
    initial_country:
      type: string
      label: 'Initial Country'
      label: 'Default country'
    exclude_countries:
      type: sequence
      label: 'Exclude Countries'
      label: 'List of countries'
    preferred_countries:
      type: sequence
      label: 'Preferred Countries'
      label: 'Top list countries'
    countries:
      type: string
      label: 'Choose countries to include/exclude from the list'

field.formatter.settings.phone_international_formatter:
  type: mapping
  label: 'Telephone format settings'
  label: 'Phone International format settings'
  mapping:
    geolocation:
      type: boolean
      label: 'Geolocation'
      label: 'Enable Geolocation'
    initial_country:
      type: string
      label: 'Initial Country'
      label: 'Default country'
    exclude_countries:
      type: sequence
      label: 'Exclude Countries'
      label: 'List of countries'
    preferred_countries:
      type: sequence
      label: 'Preferred Countries'
      label: 'Top list countries'
    countries:
      type: string
      label: 'Choose countries to include/exclude from the list'

field.widget.settings.phone_international_widget:
  type: mapping
  label: 'Telephone default format settings'
  label: 'Phone International default format settings'
  mapping:
    geolocation:
      type: boolean
      label: 'Geolocation'
      label: 'Enable Geolocation'
    initial_country:
      type: string
      label: 'Initial Country'
      label: 'Default country'
    exclude_countries:
      type: sequence
      label: 'Exclude Countries'
      label: 'List of countries'
    preferred_countries:
      type: sequence
      label: 'Preferred Countries'
      label: 'Top list countries'
    countries:
      type: string
      label: 'Choose countries to include/exclude from the list'

field.value.phone_international:
  type: mapping
  label: 'Telephone default format settings'
  label: 'Phone International default format settings'
  mapping:
    value:
      type: string

js/aja.min.js

deleted100644 → 0
+0 −8
Original line number Diff line number Diff line
/**
 * aja http://krampstudio.github.io/aja.js/
 *
 * @version <=%pkg.version%>
 * @author Bertrand Chevrier <chevrier.bertrand@gmail.com> © 2015
 * @license MIT
 **/
!function(){"use strict";var a=["html","json","jsonp","script"],b=["connect","delete","get","head","options","patch","post","put","trace"],c=function f(){var a={},b={},c={url:function(a){return h.call(this,"url",a,d.string)},sync:function(a){return h.call(this,"sync",a,d.bool)},cache:function(a){return h.call(this,"cache",a,d.bool)},type:function(a){return h.call(this,"type",a,d.type)},header:function(b,c){return a.headers=a.headers||{},d.string(b),"undefined"!=typeof c?(d.string(c),a.headers[b]=c,this):a.headers[b]},auth:function(b,c){return d.string(b),d.string(c),a.auth={user:b,passwd:c},this},timeout:function(a){return h.call(this,"timeout",a,d.positiveInteger)},method:function(a){return h.call(this,"method",a,d.method)},queryString:function(a){return h.call(this,"queryString",a,d.queryString)},data:function(a){return h.call(this,"data",a,d.plainObject)},body:function(a){return h.call(this,"body",a,null,function(a){if("object"==typeof a){if(!(a instanceof FormData)){try{a=JSON.stringify(a)}catch(b){throw new TypeError("Unable to stringify body's content : "+b.name)}this.header("Content-Type","application/json")}}else a+="";return a})},into:function(a){return h.call(this,"into",a,d.selector,function(a){return"string"==typeof a?document.querySelectorAll(a):a instanceof HTMLElement?[a]:void 0})},jsonPaddingName:function(a){return h.call(this,"jsonPaddingName",a,d.string)},jsonPadding:function(a){return h.call(this,"jsonPadding",a,d.func)},on:function(a,c){return"function"==typeof c&&(b[a]=b[a]||[],b[a].push(c)),this},off:function(a){return b[a]=[],this},trigger:function(a,c){var d=this,e=function(a,c){b[a]instanceof Array&&b[a].forEach(function(a){a.call(d,c)})};if("undefined"!=typeof a){a+="";var f=/^([0-9])([0-9x])([0-9x])$/i,g=a.match(f);g&&g.length>3?Object.keys(b).forEach(function(a){var b=a.match(f);!(b&&b.length>3&&g[1]===b[1])||"x"!==b[2]&&g[2]!==b[2]||"x"!==b[3]&&g[3]!==b[3]||e(a,c)}):b[a]&&e(a,c)}return this},go:function(){var b=a.type||(a.into?"html":"json"),c=j();return"function"==typeof g[b]?g[b].call(this,c):void 0}},g={json:function(a){var b=this;g._xhr.call(this,a,function(a){if(a)try{a=JSON.parse(a)}catch(c){return b.trigger("error",c),null}return a})},html:function(b){g._xhr.call(this,b,function(b){return a.into&&a.into.length&&[].forEach.call(a.into,function(a){a.innerHTML=b}),b})},_xhr:function(b,c){var d,e,f,g,h,j=this,k=a.method||"get",l=a.sync!==!0,m=new XMLHttpRequest,n=a.data,o=a.body,p=(a.headers||{},this.header("Content-Type")),q=a.timeout;if(!p&&n&&i()&&(this.header("Content-Type","application/x-www-form-urlencoded;charset=utf-8"),p=this.header("Content-Type")),n&&i())if("string"!=typeof o&&(o=""),p.indexOf("json")>-1)try{o=JSON.stringify(n)}catch(r){throw new TypeError("Unable to stringify body's content : "+r.name)}else{g=p&&p.indexOf("x-www-form-urlencoded")>1;for(d in n)o+=g?encodeURIComponent(d)+"="+encodeURIComponent(n[d])+"&":d+"="+n[d]+"\n\r"}h=[k,b,l],a.auth&&(h.push(a.auth.user),h.push(a.auth.passwd)),m.open.apply(m,h);for(e in a.headers)m.setRequestHeader(e,a.headers[e]);m.onprogress=function(a){a.lengthComputable&&j.trigger("progress",a.loaded/a.total)},m.onload=function(){var a=m.responseText;f&&clearTimeout(f),this.status>=200&&this.status<300&&("function"==typeof c&&(a=c(a)),j.trigger("success",a)),j.trigger(this.status,a),j.trigger("end",a)},m.onerror=function(a){f&&clearTimeout(f),j.trigger("error",a,arguments)},q&&(f=setTimeout(function(){j.trigger("timeout",{type:"timeout",expiredAfter:q},m,arguments),m.abort()},q)),m.send(o)},jsonp:function(b){var c,d=this,g=document.querySelector("head"),h=a.sync!==!0,i=a.jsonPaddingName||"callback",j=a.jsonPadding||"_padd"+(new Date).getTime()+Math.floor(1e4*Math.random()),k={};if(f[j])throw new Error("Padding "+j+"  already exists. It must be unique.");/^ajajsonp_/.test(j)||(j="ajajsonp_"+j),window[j]=function(a){d.trigger("success",a),g.removeChild(c),window[j]=void 0},k[i]=j,b=e(b,k),c=document.createElement("script"),c.async=h,c.src=b,c.onerror=function(){d.trigger("error",arguments),g.removeChild(c),window[j]=void 0},g.appendChild(c)},script:function(b){var c,d=this,e=document.querySelector("head")||document.querySelector("body"),f=a.sync!==!0;if(!e)throw new Error("Ok, wait a second, you want to load a script, but you don't have at least a head or body tag...");c=document.createElement("script"),c.async=f,c.src=b,c.onerror=function(){d.trigger("error",arguments),e.removeChild(c)},c.onload=function(){d.trigger("success",arguments)},e.appendChild(c)}},h=function(b,c,e,f){if("undefined"!=typeof c){if("function"==typeof e)try{c=e.call(d,c)}catch(g){throw new TypeError("Failed to set "+b+" : "+g.message)}return"function"==typeof f?a[b]=f.call(this,c):a[b]=c,this}return"undefined"===a[b]?null:a[b]},i=function(){return["delete","patch","post","put"].indexOf(a.method)>-1},j=function(){var b=a.url,c="undefined"!=typeof a.cache?!!a.cache:!0,d=a.queryString||"",f=a.data;return c===!1&&(d+="&ajabuster="+(new Date).getTime()),b=e(b,d),f&&!i()&&(b=e(b,f)),b};return c},d={bool:function(a){return!!a},string:function(a){if("string"!=typeof a)throw new TypeError("a string is expected, but "+a+" ["+typeof a+"] given");return a},positiveInteger:function(a){if(parseInt(a)!==a||0>=a)throw new TypeError("an integer is expected, but "+a+" ["+typeof a+"] given");return a},plainObject:function(a){if("object"!=typeof a||a.constructor!==Object)throw new TypeError("an object is expected, but "+a+"  ["+typeof a+"] given");return a},type:function(b){if(b=this.string(b),a.indexOf(b.toLowerCase())<0)throw new TypeError("a type in ["+a.join(", ")+"] is expected, but "+b+" given");return b.toLowerCase()},method:function(a){if(a=this.string(a),b.indexOf(a.toLowerCase())<0)throw new TypeError("a method in ["+b.join(", ")+"] is expected, but "+a+" given");return a.toLowerCase()},queryString:function(a){var b={};return"string"==typeof a?a.replace("?","").split("&").forEach(function(a){var c=a.split("=");2===c.length&&(b[decodeURIComponent(c[0])]=decodeURIComponent(c[1]))}):b=a,this.plainObject(b)},selector:function(a){if("string"!=typeof a&&!(a instanceof HTMLElement))throw new TypeError("a selector or an HTMLElement is expected, "+a+" ["+typeof a+"] given");return a},func:function(a){if(a=this.string(a),!/^([a-zA-Z_])([a-zA-Z0-9_\-])+$/.test(a))throw new TypeError("a valid function name is expected, "+a+" ["+typeof a+"] given");return a}},e=function(a,b){var c;if(a=a||"",b)if(-1===a.indexOf("?")&&(a+="?"),"string"==typeof b)a+=b;else if("object"==typeof b)for(c in b)a+="&"+encodeURIComponent(c)+"="+encodeURIComponent(b[c]);return a};"function"==typeof define&&define.amd?define([],function(){return c}):"object"==typeof exports?module.exports=c:window.aja=window.aja||c}();
+59 −66
Original line number Diff line number Diff line
(function (Drupal) {
  'use strict';

(Drupal => {
  Drupal.behaviors.PhoneInternational = {
    attach: () => {
      once("phoneInternational", ".phone_international-number").forEach((field) => {

    /**
     * Allow to alter phone library options.
     *
     * @return void
     */
    alterPhoneLibraryOptions: function(field, options) {},

    attach: function (context, settings) {
        const country = field.getAttribute("data-country");
        const geolocation = parseInt(field.getAttribute("data-geo"));
        const exclude = field.getAttribute("data-exclude");
        const only = field.getAttribute("data-only");
        const preferred = field.getAttribute("data-preferred");

      // Do something like jquery.once. Be sure that this attach only runs once.
      var fields = document.querySelectorAll('.phone_international-number');
      if (fields.length) {
        // Loop each one and load the library.
        fields.forEach(function (field) {
          if (field.classList.contains('jsIntPhone')) {
            return;
        const options = {
          initialCountry: (geolocation === 1) ? "auto" : country,
          excludeCountries: exclude ? exclude.split("-") : [],
          onlyCountries: only ? only.split("-") : [],
          geoIpLookup: callback => {
            fetch(new Request("https://extreme-ip-lookup.com/json/"))
              .then(response => {
                if (response.status === 200) {
                  return response.json();
                }
          field.classList.add('jsIntPhone');
          // As we are using attach form, check first if its already loaded.
          var parent = field.parentElement;
          if (!parent.classList.contains('intl-tel-input')) {
            var country = field.getAttribute('data-country');
            var geolocation = field.getAttribute('data-geo');
            var exclude = field.getAttribute('data-exclude');
            var preferred = field.getAttribute('data-preferred');
            var options = {
              initialCountry: (geolocation > 0) ? 'auto' : country,
              excludeCountries: exclude ? exclude.split('-') : [],
              geoIpLookup: function (callback) {
                if (typeof aja === 'function') {
                  aja().url('https://extreme-ip-lookup.com/json/').data({}).on('success', function (resp) {
                    var countryCode = (resp && resp.countryCode) ? resp.countryCode : country;
              }).then(resp => {
                const countryCode = (resp && resp.countryCode) ? resp.countryCode : country;
                callback(countryCode);
                  }).go();
                }
              }).catch(error => {
                console.error(error);
              });
          },
              preferredCountries: preferred ? preferred.split('-') : [],
          preferredCountries: preferred ? preferred.split("-") : [],
          nationalMode: true,
              autoPlaceholder: 'aggressive',
          autoPlaceholder: "aggressive",
          formatOnDisplay: true,
          hiddenInput: "full_number",
              utilsScript: drupalSettings.phone_international.path + '/js/utils.js',
          utilsScript: drupalSettings.phone_international.path + "/js/utils.js",
        };

        Drupal.behaviors.PhoneInternational.alterPhoneLibraryOptions(field, options);

        // Initialize the phone library.
            var iti = window.intlTelInput(field, options);
        const iti = window.intlTelInput(field, options);

            // Set drupal selector and value for the hidden input and delete the one provided by form element.
            var drupal_selector = field.parentNode.nextElementSibling.getAttribute("data-drupal-selector");
            var value = field.parentNode.nextElementSibling.getAttribute("value");
        // Set drupal selector and value for the hidden input and delete the
        // one provided by form element.
        const drupal_selector = field.parentNode.nextElementSibling.getAttribute("data-drupal-selector");
        const value = field.parentNode.nextElementSibling.getAttribute("value");
        field.parentNode.nextElementSibling.remove();
        field.nextElementSibling.setAttribute("data-drupal-selector", drupal_selector);
        field.nextElementSibling.setAttribute("value", value);

            // Add event lister to update the hidden input value on keyup to make sure that the hidden input
            // value is set for all ajax request (the intl-tel-input library update the value on form submit only)
            field.addEventListener('keyup', function (e) {
              field.nextElementSibling.value = iti.getNumber();
            });

          }
        // Add event lister to update the hidden input value on keyup to make
        // sure that the hidden input value is set for all ajax request
        // (the intl-tel-input library update the value on form submit only).
        field.addEventListener("keyup", () => field.nextElementSibling.value = iti.getNumber());
      });

      }
    },
    /**
     * Allow to alter phone library options.
     *
     * @param {Object} field
     *   The field element.
     * @param {Object} options
     *   The list of options to init intlTelInput.
     *
     * @return void
     */
    alterPhoneLibraryOptions: (field, options) => {}
  }
  };

})(Drupal);
+21 −13
Original line number Diff line number Diff line
@@ -5,21 +5,26 @@
 * Contains update functions for Phone International module.
 */

use Drupal\Core\Asset\LibrariesDirectoryFileFinder;

/**
 * Implements hook_requirements().
 */
function phone_international_requirements($phase) {
function phone_international_requirements(): array  {
  $requirements = [];

  $path = 'libraries/intl-tel-input/index.js';

  if (\Drupal::hasService('library.libraries_directory_file_finder')) {
    /** @var LibrariesDirectoryFileFinder $library_file_finder */
    /** @var \Drupal\Core\Asset\LibrariesDirectoryFileFinder $library_file_finder */
    $path = \Drupal::service('library.libraries_directory_file_finder')->find('intl-tel-input/index.js');
  }

  $path = DRUPAL_ROOT . '/' . $path;

  $requirements['phone_international'] = [
    'title' => t('Phone International library'),
    'value' => t('Plugin intl-tel-input detected'),
    'severity' => REQUIREMENT_OK,
  ];

  if (!file_exists($path)) {
    $requirements['phone_international'] = [
      'title' => t('Phone International library is missing'),
@@ -31,13 +36,6 @@ function phone_international_requirements($phase) {
       (/libraries/intl-tel-input) or check README Install', [':link' => 'https://github.com/jackocnr/intl-tel-input']),
    ];
  }
  else {
    $requirements['phone_international'] = [
      'title' => t('Phone International library'),
      'value' => t('Plugin intl-tel-input detected'),
      'severity' => REQUIREMENT_OK,
    ];
  }

  return $requirements;
}
@@ -45,9 +43,19 @@ function phone_international_requirements($phase) {
/**
 * Set cdn config.
 */
function phone_international_update_8801() {
function phone_international_update_8801(): void {
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('phone_international.settings');
  $config->set('cdn', 0);
  $config->save(TRUE);
}

/**
 * Set cdn true instead of 0.
 */
function phone_international_update_8802(): void {
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('phone_international.settings');
  $config->set('cdn', (bool) $config->get('cdn'));
  $config->save(TRUE);
}
+1 −1
Original line number Diff line number Diff line
@@ -14,8 +14,8 @@ phone_international.general:
phone_international:
  version: VERSION
  js:
    js/aja.min.js: { minified: true }
    js/phone_international.js: {}
  dependencies:
    - core/drupal
    - core/once
    - phone_international/phone_international.general
Loading