Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiosmosis <diosmosis@users.noreply.github.com>2022-03-31 00:55:55 +0300
committerdiosmosis <diosmosis@users.noreply.github.com>2022-03-31 00:55:55 +0300
commit774a4c2c72ae197924ac51266fab091ea64b7168 (patch)
treedbb817fc8dbb0e52ae2a6bc7ce27584bf6b9cdc7
parent09e1412dcd0e142c760eb5447af254a817b7b056 (diff)
migrate location-provider-selection directive to vue componentvue-location-provider-controller
-rw-r--r--plugins/UserCountry/UserCountry.php15
-rw-r--r--plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js72
-rw-r--r--plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js33
-rw-r--r--plugins/UserCountry/templates/adminIndex.twig101
-rw-r--r--plugins/UserCountry/vue/dist/UserCountry.umd.js464
-rw-r--r--plugins/UserCountry/vue/dist/UserCountry.umd.min.js8
-rw-r--r--plugins/UserCountry/vue/dist/umd.metadata.json6
-rw-r--r--plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue248
-rw-r--r--plugins/UserCountry/vue/src/index.ts8
9 files changed, 757 insertions, 198 deletions
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index 4fea13b899..119c429722 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -24,6 +24,7 @@ class UserCountry extends \Piwik\Plugin
public function registerEvents()
{
return array(
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Tracker.setTrackerCacheGeneral' => 'setTrackerCacheGeneral',
@@ -31,6 +32,18 @@ class UserCountry extends \Piwik\Plugin
);
}
+ public function getClientSideTranslationKeys(&$translations)
+ {
+ $translations[] = 'General_InfoFor';
+ $translations[] = 'General_NotInstalled';
+ $translations[] = 'General_Installed';
+ $translations[] = 'General_Broken';
+ $translations[] = 'UserCountry_CurrentLocationIntro';
+ $translations[] = 'General_Refresh';
+ $translations[] = 'UserCountry_CannotLocalizeLocalIP';
+ $translations[] = 'UserCountry_NoProviders';
+ }
+
public function addReportToInsightsOverview(&$reports)
{
$reports['UserCountry_getCountry'] = array();
@@ -48,8 +61,6 @@ class UserCountry extends \Piwik\Plugin
public function getJsFiles(&$jsFiles)
{
- $jsFiles[] = "plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js";
- $jsFiles[] = "plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js";
}
/**
diff --git a/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js b/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js
deleted file mode 100644
index a415e15686..0000000000
--- a/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-(function () {
- angular.module('piwikApp').controller('LocationProviderSelectionController', LocationProviderSelectionController);
-
- LocationProviderSelectionController.$inject = ['piwikApi'];
-
- function LocationProviderSelectionController(piwikApi) {
- var self = this;
-
- this.isLoading = false;
- this.updateLoading = {};
-
- // handle 'refresh location' link click
- this.refreshProviderInfo = function (providerId) {
-
- this.updateLoading[providerId] = true;
-
- // this should not be in a controller... ideally we fetch this data always from client side and do not
- // prefill it server side
- var $locationNode = $('.provider' + providerId + ' .location');
- $locationNode.css('visibility', 'hidden');
-
- piwikApi.fetch({
- module: 'UserCountry',
- action: 'getLocationUsingProvider',
- id: providerId,
- format: 'html'
- }).then(function (response) {
- self.updateLoading[providerId] = false;
- $locationNode.html('<strong>' + response + '</strong>').css('visibility', 'visible');
- }, function () {
- self.updateLoading[providerId] = false;
- });
- };
-
- this.save = function () {
- if (!this.selectedProvider) {
- return;
- }
-
- this.isLoading = true;
-
- var parent = $(this).closest('p'),
- loading = $('.loadingPiwik', parent),
- ajaxSuccess = $('.success', parent);
-
- piwikApi.withTokenInUrl();
- piwikApi.fetch({
- method: 'UserCountry.setLocationProvider',
- providerId: this.selectedProvider
- }).then(function () {
- self.isLoading = false;
- var UI = require('piwik/UI');
- var notification = new UI.Notification();
- notification.show(_pk_translate('General_Done'), {
- context: 'success',
- noclear: true,
- type: 'toast',
- id: 'userCountryLocationProvider'
- });
- notification.scrollToNotification();
- }, function () {
- self.isLoading = false;
- });
- };
- }
-})(); \ No newline at end of file
diff --git a/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js b/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js
deleted file mode 100644
index e5bc4efb5b..0000000000
--- a/plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*!
- * Matomo - free/libre analytics platform
- *
- * @link https://matomo.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-/**
- * Usage:
- * <div piwik-location-provider-selection>
- */
-(function () {
- angular.module('piwikApp').directive('piwikLocationProviderSelection', piwikLocationProviderSelection);
-
- piwikLocationProviderSelection.$inject = ['piwik'];
-
- function piwikLocationProviderSelection(piwik){
-
- return {
- restrict: 'A',
- transclude: true,
- controller: 'LocationProviderSelectionController',
- controllerAs: 'locationSelector',
- template: '<div ng-transclude></div>',
- compile: function (element, attrs) {
-
- return function (scope, element, attrs, controller) {
- controller.selectedProvider = attrs.piwikLocationProviderSelection;
- };
- }
- };
- }
-})(); \ No newline at end of file
diff --git a/plugins/UserCountry/templates/adminIndex.twig b/plugins/UserCountry/templates/adminIndex.twig
index 20cc6deede..658bcc0b27 100644
--- a/plugins/UserCountry/templates/adminIndex.twig
+++ b/plugins/UserCountry/templates/adminIndex.twig
@@ -12,97 +12,16 @@
<p>{{ 'UserCountry_GeolocationPageDesc'|translate }}</p>
</div>
<div piwik-content-block content-title="{{ 'UserCountry_LocationProvider'|translate|e('html_attr') }}">
-<div piwik-location-provider-selection="{{ currentProviderId|e('html_attr') }}">
-
- {% if not isThereWorkingProvider %}
- {{ setUpGuides|raw }}
- {% endif %}
-
- <div class="row">
- <div class="col s12 push-m9 m3">{{ 'General_InfoFor'|translate(thisIP) }}</div>
- </div>
-
- {% for id,provider in locationProviders|filter(provider => provider.isVisible) %}
- <div class="row form-group provider{{ id|e('html_attr') }}">
- <div class="col s12 m4 l2">
- <p>
- <label>
- <input class="location-provider"
- name="location-provider"
- value="{{ id }}"
- type="radio"
- ng-model="locationSelector.selectedProvider"
- id="provider_input_{{ id }}" {% if provider.status != 1 %}disabled="disabled"{% endif %}/>
-
- <span>{{ provider.title|translate }}</span>
- </label>
- </p>
- <p class="loc-provider-status">
- {% if provider.status == 0 %}
- <span class="is-not-installed">{{ 'General_NotInstalled'|translate}}</span>
- {% elseif provider.status == 1 %}
- <span class="is-installed">{{ 'General_Installed'|translate }}</span>
- {% elseif provider.status == 2 %}
- <span class="is-broken">{{ 'General_Broken'|translate }}</span>
- {% endif %}
- </p>
- </div>
- <div class="col s12 m4 l6">
- <p>{{ provider.description|translate|raw }}</p>
- {% if provider.status != 1 and provider.install_docs is defined %}
- <p>{{ provider.install_docs|raw }}</p>
- {% endif %}
- </div>
- <div class="col s12 m4 l4">
- {% if provider.status == 1 %}
- <div class="form-help">
- {% if thisIP != '127.0.0.1' %}
- {{ 'UserCountry_CurrentLocationIntro'|translate }}:
- <div>
- <br/>
- <div style="position: absolute;"
- piwik-activity-indicator
- loading='locationSelector.updateLoading[{{ id|json_encode }}]'></div>
- <span class="location"><strong>{{ provider.location|raw }}</strong></span>
- </div>
- <div class="text-right">
- <a href="javascript:;"
- ng-click='locationSelector.refreshProviderInfo({{ id|json_encode }})'>{{ 'General_Refresh'|translate }}</a>
- </div>
- {% else %}
- {{ 'UserCountry_CannotLocalizeLocalIP'|translate(thisIP) }}
- {% endif %}
- </div>
- {% endif %}
- {% if provider.statusMessage is defined and provider.statusMessage %}
- <div class="form-help">
- {% if provider.status == 2 %}<strong>{{ 'General_Error'|translate }}:</strong> {% endif %}{{ provider.statusMessage|raw }}
- </div>
- {% endif %}
- {% if provider.extra_message is defined and provider.extra_message %}
- <div class="form-help">
- {{ provider.extra_message|raw }}
- </div>
- {% endif %}
- </div>
- </div>
- {% endfor %}
-
-
- {% if locationProviders|filter(provider => (
- provider.id != constant("Piwik\\Plugins\\UserCountry\\LocationProvider\\DefaultProvider::ID") and
- provider.id != constant("Piwik\\Plugins\\UserCountry\\LocationProvider\\DisabledProvider::ID")
- ))|length == 0 %}
- <div piwik-notification
- noclear="true"
- context="warning">
- {{ 'UserCountry_NoProviders'|translate('<a rel="noreferrer noopener" href="https://db-ip.com/?refid=mtm">','</a>')|raw }}
- </div>
- {% endif %}
-
- <div piwik-save-button onconfirm="locationSelector.save()" saving="locationSelector.isLoading"></div>
-
-</div>
+<div
+ vue-entry="UserCountry.LocationProviderSelection"
+ current-provider-id="{{ currentProviderId|json_encode|e('html_attr') }}"
+ is-there-working-provider="{{ isThereWorkingProvider|default(null)|json_encode|e('html_attr') }}"
+ set-up-guides="{{ setUpGuides|default(null)|json_encode|e('html_attr') }}"
+ this-ip="{{ thisIP|default(null)|json_encode|e('html_attr') }}"
+ location-providers="{{ locationProviders|default(null)|json_encode|e('html_attr') }}"
+ default-provider-id="{{ constant("Piwik\\Plugins\\UserCountry\\LocationProvider\\DefaultProvider::ID")|default(null)|json_encode|e('html_attr') }}"
+ disabled-provider-id="{{ constant("Piwik\\Plugins\\UserCountry\\LocationProvider\\DisabledProvider::ID")|default(null)|json_encode|e('html_attr') }}"
+></div>
</div>
{{ configurations|raw }}
diff --git a/plugins/UserCountry/vue/dist/UserCountry.umd.js b/plugins/UserCountry/vue/dist/UserCountry.umd.js
new file mode 100644
index 0000000000..921edd7007
--- /dev/null
+++ b/plugins/UserCountry/vue/dist/UserCountry.umd.js
@@ -0,0 +1,464 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin"));
+ else if(typeof define === 'function' && define.amd)
+ define(["CoreHome", , "CorePluginsAdmin"], factory);
+ else if(typeof exports === 'object')
+ exports["UserCountry"] = factory(require("CoreHome"), require("vue"), require("CorePluginsAdmin"));
+ else
+ root["UserCountry"] = factory(root["CoreHome"], root["Vue"], root["CorePluginsAdmin"]);
+})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__19dc__, __WEBPACK_EXTERNAL_MODULE__8bbf__, __WEBPACK_EXTERNAL_MODULE_a5a2__) {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId]) {
+/******/ return installedModules[moduleId].exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ i: moduleId,
+/******/ l: false,
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.l = true;
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+/******/
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+/******/
+/******/ // define getter function for harmony exports
+/******/ __webpack_require__.d = function(exports, name, getter) {
+/******/ if(!__webpack_require__.o(exports, name)) {
+/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
+/******/ }
+/******/ };
+/******/
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = function(exports) {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/
+/******/ // create a fake namespace object
+/******/ // mode & 1: value is a module id, require it
+/******/ // mode & 2: merge all properties of value into the ns
+/******/ // mode & 4: return value when already ns object
+/******/ // mode & 8|1: behave like require
+/******/ __webpack_require__.t = function(value, mode) {
+/******/ if(mode & 1) value = __webpack_require__(value);
+/******/ if(mode & 8) return value;
+/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
+/******/ var ns = Object.create(null);
+/******/ __webpack_require__.r(ns);
+/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
+/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
+/******/ return ns;
+/******/ };
+/******/
+/******/ // getDefaultExport function for compatibility with non-harmony modules
+/******/ __webpack_require__.n = function(module) {
+/******/ var getter = module && module.__esModule ?
+/******/ function getDefault() { return module['default']; } :
+/******/ function getModuleExports() { return module; };
+/******/ __webpack_require__.d(getter, 'a', getter);
+/******/ return getter;
+/******/ };
+/******/
+/******/ // Object.prototype.hasOwnProperty.call
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "plugins/UserCountry/vue/dist/";
+/******/
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(__webpack_require__.s = "fae3");
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ "19dc":
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE__19dc__;
+
+/***/ }),
+
+/***/ "8bbf":
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE__8bbf__;
+
+/***/ }),
+
+/***/ "a5a2":
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_a5a2__;
+
+/***/ }),
+
+/***/ "f95d":
+/***/ (function(module, exports) {
+
+
+
+/***/ }),
+
+/***/ "fae3":
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+// ESM COMPAT FLAG
+__webpack_require__.r(__webpack_exports__);
+
+// EXPORTS
+__webpack_require__.d(__webpack_exports__, "LocationProviderSelection", function() { return /* reexport */ LocationProviderSelection; });
+
+// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js
+// This file is imported into lib/wc client bundles.
+
+if (typeof window !== 'undefined') {
+ var currentScript = window.document.currentScript
+ if (false) { var getCurrentScript; }
+
+ var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/)
+ if (src) {
+ __webpack_require__.p = src[1] // eslint-disable-line
+ }
+}
+
+// Indicate to webpack that this file can be concatenated
+/* harmony default export */ var setPublicPath = (null);
+
+// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"}
+var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__("8bbf");
+
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/@vue/cli-plugin-babel/node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist/templateLoader.js??ref--6!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue?vue&type=template&id=daf9d97a
+
+var _hoisted_1 = ["innerHTML"];
+var _hoisted_2 = {
+ class: "row"
+};
+var _hoisted_3 = {
+ class: "col s12 push-m9 m3"
+};
+var _hoisted_4 = {
+ class: "col s12 m4 l2"
+};
+var _hoisted_5 = ["id", "disabled"];
+var _hoisted_6 = {
+ class: "loc-provider-status"
+};
+var _hoisted_7 = {
+ key: 0,
+ class: "is-not-installed"
+};
+var _hoisted_8 = {
+ key: 1,
+ class: "is-installed"
+};
+var _hoisted_9 = {
+ key: 2,
+ class: "is-broken"
+};
+var _hoisted_10 = {
+ class: "col s12 m4 l6"
+};
+var _hoisted_11 = ["innerHTML"];
+var _hoisted_12 = ["innerHTML"];
+var _hoisted_13 = {
+ class: "col s12 m4 l4"
+};
+var _hoisted_14 = {
+ key: 0,
+ class: "form-help"
+};
+var _hoisted_15 = {
+ key: 0
+};
+
+var _hoisted_16 = /*#__PURE__*/Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("br", null, null, -1);
+
+var _hoisted_17 = {
+ class: "location"
+};
+var _hoisted_18 = ["innerHTML"];
+var _hoisted_19 = {
+ class: "text-right"
+};
+var _hoisted_20 = ["onClick"];
+var _hoisted_21 = {
+ key: 1
+};
+var _hoisted_22 = {
+ key: 1,
+ class: "form-help"
+};
+var _hoisted_23 = {
+ key: 0
+};
+var _hoisted_24 = ["innerHTML"];
+var _hoisted_25 = ["innerHTML"];
+var _hoisted_26 = {
+ key: 1
+};
+var _hoisted_27 = ["innerHTML"];
+function render(_ctx, _cache, $props, $setup, $data, $options) {
+ var _component_ActivityIndicator = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("ActivityIndicator");
+
+ var _component_Notification = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("Notification");
+
+ var _component_SaveButton = Object(external_commonjs_vue_commonjs2_vue_root_Vue_["resolveComponent"])("SaveButton");
+
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", null, [!_ctx.isThereWorkingProvider ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
+ key: 0,
+ innerHTML: _ctx.$sanitize(_ctx.setUpGuides)
+ }, null, 8, _hoisted_1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_2, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_3, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_InfoFor', _ctx.thisIp)), 1)]), (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])(external_commonjs_vue_commonjs2_vue_root_Vue_["Fragment"], null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["renderList"])(_ctx.visibleLocationProviders, function (id, provider) {
+ return Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
+ key: id,
+ class: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["normalizeClass"])("row form-group provider".concat(id))
+ }, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_4, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("label", null, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("input", {
+ class: "location-provider",
+ name: "location-provider",
+ type: "radio",
+ id: "'provider_input_".concat(id, "'"),
+ disabled: provider.status !== 1,
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = function ($event) {
+ return _ctx.selectedProvider = $event;
+ })
+ }, null, 8, _hoisted_5), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vModelRadio"], _ctx.selectedProvider]]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", null, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate(provider.title)), 1)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", _hoisted_6, [provider.status === 0 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_7, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_NotInstalled')), 1)) : provider.status === 1 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_8, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Installed')), 1)) : provider.status === 2 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("span", _hoisted_9, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Broken')), 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_10, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("p", {
+ innerHTML: _ctx.$sanitize(_ctx.translate(provider.description))
+ }, null, 8, _hoisted_11), provider.status !== 1 && provider.install_docs ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("p", {
+ key: 0,
+ innerHTML: _ctx.$sanitize(provider.install_docs)
+ }, null, 8, _hoisted_12)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_13, [provider.status === 1 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_14, [_ctx.thisIp !== '127.0.0.1' ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_15, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createTextVNode"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('UserCountry_CurrentLocationIntro')) + ": ", 1), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", null, [_hoisted_16, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_ActivityIndicator, {
+ style: {
+ "position": "absolute"
+ },
+ loading: _ctx.updateLoading[id]
+ }, null, 8, ["loading"]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withDirectives"])(Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", _hoisted_17, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("strong", {
+ innerHTML: _ctx.$sanitize(_ctx.providerLocations[id])
+ }, null, 8, _hoisted_18)], 512), [[external_commonjs_vue_commonjs2_vue_root_Vue_["vShow"], _ctx.providerLocations[id]]])]), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("div", _hoisted_19, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("a", {
+ onClick: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withModifiers"])(function ($event) {
+ return _ctx.refreshProviderInfo(id);
+ }, ["prevent"])
+ }, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Refresh')), 9, _hoisted_20)])])) : (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_21, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('UserCountry_CannotLocalizeLocalIP', _ctx.thisIp)), 1))])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), provider.statusMessage ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_22, [provider.status === 2 ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("strong", _hoisted_23, Object(external_commonjs_vue_commonjs2_vue_root_Vue_["toDisplayString"])(_ctx.translate('General_Error')) + ":", 1)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
+ innerHTML: _ctx.$sanitize(provider.statusMessage)
+ }, null, 8, _hoisted_24)])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), provider.extra_message ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", {
+ key: 2,
+ class: "form-help",
+ innerHTML: _ctx.$sanitize(provider.extra_message)
+ }, null, 8, _hoisted_25)) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true)])], 2);
+ }), 128)), _ctx.locationProvidersNotDefaultOrDisabled.length ? (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["openBlock"])(), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementBlock"])("div", _hoisted_26, [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_Notification, {
+ noclear: true,
+ context: "warning"
+ }, {
+ default: Object(external_commonjs_vue_commonjs2_vue_root_Vue_["withCtx"])(function () {
+ return [Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createElementVNode"])("span", {
+ innerHTML: _ctx.$sanitize(_ctx.noProvidersText)
+ }, null, 8, _hoisted_27)];
+ }),
+ _: 1
+ })])) : Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createCommentVNode"])("", true), Object(external_commonjs_vue_commonjs2_vue_root_Vue_["createVNode"])(_component_SaveButton, {
+ onConfirm: _cache[1] || (_cache[1] = function ($event) {
+ return _ctx.save();
+ }),
+ saving: _ctx.isLoading
+ }, null, 8, ["saving"])]);
+}
+// CONCATENATED MODULE: ./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue?vue&type=template&id=daf9d97a
+
+// EXTERNAL MODULE: external "CoreHome"
+var external_CoreHome_ = __webpack_require__("19dc");
+
+// EXTERNAL MODULE: external "CorePluginsAdmin"
+var external_CorePluginsAdmin_ = __webpack_require__("a5a2");
+
+// CONCATENATED MODULE: ./node_modules/@vue/cli-plugin-typescript/node_modules/cache-loader/dist/cjs.js??ref--14-0!./node_modules/babel-loader/lib!./node_modules/@vue/cli-plugin-typescript/node_modules/ts-loader??ref--14-2!./node_modules/@vue/cli-service/node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/@vue/cli-service/node_modules/vue-loader-v16/dist??ref--0-1!./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue?vue&type=script&lang=ts
+function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
+
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
+
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+
+
+
+
+/* harmony default export */ var LocationProviderSelectionvue_type_script_lang_ts = (Object(external_commonjs_vue_commonjs2_vue_root_Vue_["defineComponent"])({
+ props: {
+ currentProviderId: {
+ type: String,
+ required: true
+ },
+ isThereWorkingProvider: Boolean,
+ setUpGuides: {
+ type: String,
+ required: true
+ },
+ thisIp: {
+ type: String,
+ required: true
+ },
+ locationProviders: {
+ type: Object,
+ required: true
+ },
+ defaultProviderId: {
+ type: String,
+ required: true
+ },
+ disabledProviderId: {
+ type: String,
+ required: true
+ }
+ },
+ components: {
+ ActivityIndicator: external_CoreHome_["ActivityIndicator"],
+ Notification: external_CoreHome_["Notification"],
+ SaveButton: external_CorePluginsAdmin_["SaveButton"]
+ },
+ data: function data() {
+ return {
+ isLoading: false,
+ updateLoading: {},
+ selectedProvider: this.currentProviderId,
+ providerLocations: Object.fromEntries(Object.entries(this.locationProviders).map(function (_ref) {
+ var _ref2 = _slicedToArray(_ref, 2),
+ k = _ref2[0],
+ p = _ref2[1];
+
+ return [k, p.location];
+ }))
+ };
+ },
+ methods: {
+ refreshProviderInfo: function refreshProviderInfo(providerId) {
+ var _this = this;
+
+ // this should not be in a controller... ideally we fetch this data always from client side
+ // and do not prefill it server side
+ this.updateLoading[providerId] = true;
+ delete this.providerLocations[providerId];
+ external_CoreHome_["AjaxHelper"].fetch({
+ module: 'UserCountry',
+ action: 'getLocationUsingProvider',
+ id: providerId,
+ format: 'html'
+ }).then(function (response) {
+ _this.providerLocations[providerId] = response;
+ }).finally(function () {
+ _this.updateLoading[providerId] = false;
+ });
+ },
+ save: function save() {
+ var _this2 = this;
+
+ if (!this.selectedProvider) {
+ return;
+ }
+
+ this.isLoading = true;
+ external_CoreHome_["AjaxHelper"].fetch({
+ method: 'UserCountry.setLocationProvider',
+ providerId: this.selectedProvider
+ }, {
+ withTokenInUrl: true
+ }).then(function () {
+ var notificationInstanceId = external_CoreHome_["NotificationsStore"].show({
+ message: Object(external_CoreHome_["translate"])('General_Done'),
+ context: 'success',
+ noclear: true,
+ type: 'toast',
+ id: 'userCountryLocationProvider'
+ });
+ external_CoreHome_["NotificationsStore"].scrollToNotification(notificationInstanceId);
+ }).finally(function () {
+ _this2.isLoading = false;
+ });
+ }
+ },
+ computed: {
+ visibleLocationProviders: function visibleLocationProviders() {
+ return Object.fromEntries(Object.entries(this.locationProviders).filter(function (_ref3) {
+ var _ref4 = _slicedToArray(_ref3, 2),
+ p = _ref4[1];
+
+ return p.isVisible;
+ }));
+ },
+ locationProvidersNotDefaultOrDisabled: function locationProvidersNotDefaultOrDisabled() {
+ var _this3 = this;
+
+ return Object.fromEntries(Object.entries(this.locationProviders).filter(function (_ref5) {
+ var _ref6 = _slicedToArray(_ref5, 2),
+ p = _ref6[1];
+
+ return p.id !== _this3.defaultProviderId && p.id !== _this3.disabledProviderId;
+ }));
+ },
+ noProvidersText: function noProvidersText() {
+ return Object(external_CoreHome_["translate"])('UserCountry_NoProviders', '<a rel="noreferrer noopener" href="https://db-ip.com/?refid=mtm">', '</a>');
+ }
+ }
+}));
+// CONCATENATED MODULE: ./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue?vue&type=script&lang=ts
+
+// EXTERNAL MODULE: ./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue?vue&type=custom&index=0&blockType=todo
+var LocationProviderSelectionvue_type_custom_index_0_blockType_todo = __webpack_require__("f95d");
+var LocationProviderSelectionvue_type_custom_index_0_blockType_todo_default = /*#__PURE__*/__webpack_require__.n(LocationProviderSelectionvue_type_custom_index_0_blockType_todo);
+
+// CONCATENATED MODULE: ./plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue
+
+
+
+LocationProviderSelectionvue_type_script_lang_ts.render = render
+/* custom blocks */
+
+if (typeof LocationProviderSelectionvue_type_custom_index_0_blockType_todo_default.a === 'function') LocationProviderSelectionvue_type_custom_index_0_blockType_todo_default()(LocationProviderSelectionvue_type_script_lang_ts)
+
+
+/* harmony default export */ var LocationProviderSelection = (LocationProviderSelectionvue_type_script_lang_ts);
+// CONCATENATED MODULE: ./plugins/UserCountry/vue/src/index.ts
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+// CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js
+
+
+
+
+/***/ })
+
+/******/ });
+});
+//# sourceMappingURL=UserCountry.umd.js.map \ No newline at end of file
diff --git a/plugins/UserCountry/vue/dist/UserCountry.umd.min.js b/plugins/UserCountry/vue/dist/UserCountry.umd.min.js
new file mode 100644
index 0000000000..856cb3564e
--- /dev/null
+++ b/plugins/UserCountry/vue/dist/UserCountry.umd.min.js
@@ -0,0 +1,8 @@
+(function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin")):"function"===typeof define&&define.amd?define(["CoreHome",,"CorePluginsAdmin"],t):"object"===typeof exports?exports["UserCountry"]=t(require("CoreHome"),require("vue"),require("CorePluginsAdmin")):e["UserCountry"]=t(e["CoreHome"],e["Vue"],e["CorePluginsAdmin"])})("undefined"!==typeof self?self:this,(function(e,t,r){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="plugins/UserCountry/vue/dist/",r(r.s="fae3")}({"19dc":function(t,r){t.exports=e},"8bbf":function(e,r){e.exports=t},a5a2:function(e,t){e.exports=r},f95d:function(e,t){},fae3:function(e,t,r){"use strict";if(r.r(t),r.d(t,"LocationProviderSelection",(function(){return F})),"undefined"!==typeof window){var n=window.document.currentScript,o=n&&n.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);o&&(r.p=o[1])}var i=r("8bbf"),c=["innerHTML"],a={class:"row"},l={class:"col s12 push-m9 m3"},s={class:"col s12 m4 l2"},d=["id","disabled"],u={class:"loc-provider-status"},b={key:0,class:"is-not-installed"},f={key:1,class:"is-installed"},p={key:2,class:"is-broken"},m={class:"col s12 m4 l6"},v=["innerHTML"],j=["innerHTML"],O={class:"col s12 m4 l4"},y={key:0,class:"form-help"},g={key:0},h=Object(i["createElementVNode"])("br",null,null,-1),k={class:"location"},N=["innerHTML"],P={class:"text-right"},E=["onClick"],C={key:1},L={key:1,class:"form-help"},B={key:0},V=["innerHTML"],S=["innerHTML"],I={key:1},x=["innerHTML"];function T(e,t,r,n,o,T){var M=Object(i["resolveComponent"])("ActivityIndicator"),_=Object(i["resolveComponent"])("Notification"),H=Object(i["resolveComponent"])("SaveButton");return Object(i["openBlock"])(),Object(i["createElementBlock"])("div",null,[e.isThereWorkingProvider?Object(i["createCommentVNode"])("",!0):(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",{key:0,innerHTML:e.$sanitize(e.setUpGuides)},null,8,c)),Object(i["createElementVNode"])("div",a,[Object(i["createElementVNode"])("div",l,Object(i["toDisplayString"])(e.translate("General_InfoFor",e.thisIp)),1)]),(Object(i["openBlock"])(!0),Object(i["createElementBlock"])(i["Fragment"],null,Object(i["renderList"])(e.visibleLocationProviders,(function(r,n){return Object(i["openBlock"])(),Object(i["createElementBlock"])("div",{key:r,class:Object(i["normalizeClass"])("row form-group provider".concat(r))},[Object(i["createElementVNode"])("div",s,[Object(i["createElementVNode"])("p",null,[Object(i["createElementVNode"])("label",null,[Object(i["withDirectives"])(Object(i["createElementVNode"])("input",{class:"location-provider",name:"location-provider",type:"radio",id:"'provider_input_".concat(r,"'"),disabled:1!==n.status,"onUpdate:modelValue":t[0]||(t[0]=function(t){return e.selectedProvider=t})},null,8,d),[[i["vModelRadio"],e.selectedProvider]]),Object(i["createElementVNode"])("span",null,Object(i["toDisplayString"])(e.translate(n.title)),1)])]),Object(i["createElementVNode"])("p",u,[0===n.status?(Object(i["openBlock"])(),Object(i["createElementBlock"])("span",b,Object(i["toDisplayString"])(e.translate("General_NotInstalled")),1)):1===n.status?(Object(i["openBlock"])(),Object(i["createElementBlock"])("span",f,Object(i["toDisplayString"])(e.translate("General_Installed")),1)):2===n.status?(Object(i["openBlock"])(),Object(i["createElementBlock"])("span",p,Object(i["toDisplayString"])(e.translate("General_Broken")),1)):Object(i["createCommentVNode"])("",!0)])]),Object(i["createElementVNode"])("div",m,[Object(i["createElementVNode"])("p",{innerHTML:e.$sanitize(e.translate(n.description))},null,8,v),1!==n.status&&n.install_docs?(Object(i["openBlock"])(),Object(i["createElementBlock"])("p",{key:0,innerHTML:e.$sanitize(n.install_docs)},null,8,j)):Object(i["createCommentVNode"])("",!0)]),Object(i["createElementVNode"])("div",O,[1===n.status?(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",y,["127.0.0.1"!==e.thisIp?(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",g,[Object(i["createTextVNode"])(Object(i["toDisplayString"])(e.translate("UserCountry_CurrentLocationIntro"))+": ",1),Object(i["createElementVNode"])("div",null,[h,Object(i["createVNode"])(M,{style:{position:"absolute"},loading:e.updateLoading[r]},null,8,["loading"]),Object(i["withDirectives"])(Object(i["createElementVNode"])("span",k,[Object(i["createElementVNode"])("strong",{innerHTML:e.$sanitize(e.providerLocations[r])},null,8,N)],512),[[i["vShow"],e.providerLocations[r]]])]),Object(i["createElementVNode"])("div",P,[Object(i["createElementVNode"])("a",{onClick:Object(i["withModifiers"])((function(t){return e.refreshProviderInfo(r)}),["prevent"])},Object(i["toDisplayString"])(e.translate("General_Refresh")),9,E)])])):(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",C,Object(i["toDisplayString"])(e.translate("UserCountry_CannotLocalizeLocalIP",e.thisIp)),1))])):Object(i["createCommentVNode"])("",!0),n.statusMessage?(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",L,[2===n.status?(Object(i["openBlock"])(),Object(i["createElementBlock"])("strong",B,Object(i["toDisplayString"])(e.translate("General_Error"))+":",1)):Object(i["createCommentVNode"])("",!0),Object(i["createElementVNode"])("span",{innerHTML:e.$sanitize(n.statusMessage)},null,8,V)])):Object(i["createCommentVNode"])("",!0),n.extra_message?(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",{key:2,class:"form-help",innerHTML:e.$sanitize(n.extra_message)},null,8,S)):Object(i["createCommentVNode"])("",!0)])],2)})),128)),e.locationProvidersNotDefaultOrDisabled.length?(Object(i["openBlock"])(),Object(i["createElementBlock"])("div",I,[Object(i["createVNode"])(_,{noclear:!0,context:"warning"},{default:Object(i["withCtx"])((function(){return[Object(i["createElementVNode"])("span",{innerHTML:e.$sanitize(e.noProvidersText)},null,8,x)]})),_:1})])):Object(i["createCommentVNode"])("",!0),Object(i["createVNode"])(H,{onConfirm:t[1]||(t[1]=function(t){return e.save()}),saving:e.isLoading},null,8,["saving"])])}var M=r("19dc"),_=r("a5a2");function H(e,t){return q(e)||U(e,t)||D(e,t)||w()}function w(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function D(e,t){if(e){if("string"===typeof e)return A(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?A(e,t):void 0}}function A(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function U(e,t){var r=null==e?null:"undefined"!==typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i=[],c=!0,a=!1;try{for(r=r.call(e);!(c=(n=r.next()).done);c=!0)if(i.push(n.value),t&&i.length===t)break}catch(l){a=!0,o=l}finally{try{c||null==r["return"]||r["return"]()}finally{if(a)throw o}}return i}}function q(e){if(Array.isArray(e))return e}var z=Object(i["defineComponent"])({props:{currentProviderId:{type:String,required:!0},isThereWorkingProvider:Boolean,setUpGuides:{type:String,required:!0},thisIp:{type:String,required:!0},locationProviders:{type:Object,required:!0},defaultProviderId:{type:String,required:!0},disabledProviderId:{type:String,required:!0}},components:{ActivityIndicator:M["ActivityIndicator"],Notification:M["Notification"],SaveButton:_["SaveButton"]},data:function(){return{isLoading:!1,updateLoading:{},selectedProvider:this.currentProviderId,providerLocations:Object.fromEntries(Object.entries(this.locationProviders).map((function(e){var t=H(e,2),r=t[0],n=t[1];return[r,n.location]})))}},methods:{refreshProviderInfo:function(e){var t=this;this.updateLoading[e]=!0,delete this.providerLocations[e],M["AjaxHelper"].fetch({module:"UserCountry",action:"getLocationUsingProvider",id:e,format:"html"}).then((function(r){t.providerLocations[e]=r})).finally((function(){t.updateLoading[e]=!1}))},save:function(){var e=this;this.selectedProvider&&(this.isLoading=!0,M["AjaxHelper"].fetch({method:"UserCountry.setLocationProvider",providerId:this.selectedProvider},{withTokenInUrl:!0}).then((function(){var e=M["NotificationsStore"].show({message:Object(M["translate"])("General_Done"),context:"success",noclear:!0,type:"toast",id:"userCountryLocationProvider"});M["NotificationsStore"].scrollToNotification(e)})).finally((function(){e.isLoading=!1})))}},computed:{visibleLocationProviders:function(){return Object.fromEntries(Object.entries(this.locationProviders).filter((function(e){var t=H(e,2),r=t[1];return r.isVisible})))},locationProvidersNotDefaultOrDisabled:function(){var e=this;return Object.fromEntries(Object.entries(this.locationProviders).filter((function(t){var r=H(t,2),n=r[1];return n.id!==e.defaultProviderId&&n.id!==e.disabledProviderId})))},noProvidersText:function(){return Object(M["translate"])("UserCountry_NoProviders",'<a rel="noreferrer noopener" href="https://db-ip.com/?refid=mtm">',"</a>")}}}),G=r("f95d"),$=r.n(G);z.render=T,"function"===typeof $.a&&$()(z);var F=z;
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */}})}));
+//# sourceMappingURL=UserCountry.umd.min.js.map \ No newline at end of file
diff --git a/plugins/UserCountry/vue/dist/umd.metadata.json b/plugins/UserCountry/vue/dist/umd.metadata.json
new file mode 100644
index 0000000000..dce4477a3c
--- /dev/null
+++ b/plugins/UserCountry/vue/dist/umd.metadata.json
@@ -0,0 +1,6 @@
+{
+ "dependsOn": [
+ "CoreHome",
+ "CorePluginsAdmin"
+ ]
+} \ No newline at end of file
diff --git a/plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue b/plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue
new file mode 100644
index 0000000000..225574a7e2
--- /dev/null
+++ b/plugins/UserCountry/vue/src/LocationProviderSelection/LocationProviderSelection.vue
@@ -0,0 +1,248 @@
+<!--
+ Matomo - free/libre analytics platform
+ @link https://matomo.org
+ @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+-->
+
+<todo>
+- test in UI
+- create PR
+</todo>
+
+<template>
+ <div>
+ <div v-if="!isThereWorkingProvider" v-html="$sanitize(setUpGuides)"></div>
+ <div class="row">
+ <div class="col s12 push-m9 m3">{{ translate('General_InfoFor', thisIp) }}</div>
+ </div>
+ <div
+ v-for="(id, provider) in visibleLocationProviders"
+ :key="id"
+ :class="`row form-group provider${id}`"
+ >
+ <div class="col s12 m4 l2">
+ <p>
+ <label>
+ <input
+ class="location-provider"
+ name="location-provider"
+ type="radio"
+ :id="`'provider_input_${id }'`"
+ :disabled="provider.status !== 1"
+ v-model="selectedProvider"
+ />
+ <span>{{ translate(provider.title) }}</span>
+ </label>
+ </p>
+ <p class="loc-provider-status">
+ <span v-if="provider.status === 0 " class="is-not-installed">
+ {{ translate('General_NotInstalled') }}
+ </span>
+ <span v-else-if="provider.status === 1" class="is-installed">
+ {{ translate('General_Installed') }}
+ </span>
+ <span v-else-if="provider.status === 2" class="is-broken">
+ {{ translate('General_Broken') }}
+ </span>
+ </p>
+ </div>
+ <div class="col s12 m4 l6">
+ <p v-html="$sanitize(translate(provider.description))"></p>
+ <p
+ v-if="provider.status !== 1 && provider.install_docs"
+ v-html="$sanitize(provider.install_docs)"
+ />
+ </div>
+ <div class="col s12 m4 l4">
+ <div class="form-help" v-if="provider.status === 1">
+ <div v-if="thisIp !== '127.0.0.1'">
+ {{ translate('UserCountry_CurrentLocationIntro') }}:
+ <div>
+ <br />
+ <ActivityIndicator
+ style="position: absolute;"
+ :loading="updateLoading[id]"
+ />
+ <span class="location" v-show="providerLocations[id]">
+ <strong v-html="$sanitize(providerLocations[id])"/>
+ </span>
+ </div>
+ <div class="text-right">
+ <a
+ @click.prevent="refreshProviderInfo(id)"
+ >{{ translate('General_Refresh') }}</a>
+ </div>
+ </div>
+ <div v-else>
+ {{ translate('UserCountry_CannotLocalizeLocalIP', thisIp) }}
+ </div>
+ </div>
+ <div class="form-help" v-if="provider.statusMessage">
+ <strong v-if="provider.status === 2">{{ translate('General_Error') }}:</strong>
+ <span v-html="$sanitize(provider.statusMessage)"/>
+ </div>
+ <div
+ class="form-help"
+ v-if="provider.extra_message"
+ v-html="$sanitize(provider.extra_message)"
+ >
+ </div>
+ </div>
+ </div>
+ <div v-if="locationProvidersNotDefaultOrDisabled.length">
+ <Notification
+ :noclear="true"
+ context="warning"
+ >
+ <span v-html="$sanitize(noProvidersText)"></span>
+ </Notification>
+ </div>
+ <SaveButton
+ @confirm="save()"
+ :saving="isLoading"
+ />
+ </div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import {
+ translate,
+ AjaxHelper,
+ NotificationsStore,
+ ActivityIndicator,
+ Notification,
+} from 'CoreHome';
+import { SaveButton } from 'CorePluginsAdmin';
+
+interface ProviderInfo {
+ id: string;
+ isVisible: boolean;
+ description: string;
+ status: number;
+ install_docs?: string;
+ extra_message?: string;
+ location?: string;
+}
+
+interface LocationProviderSelectionState {
+ isLoading: boolean;
+ updateLoading: Record<string, boolean>;
+ selectedProvider: string;
+ statusMessage?: string;
+ providerLocations: Record<string, string>;
+}
+
+export default defineComponent({
+ props: {
+ currentProviderId: {
+ type: String,
+ required: true,
+ },
+ isThereWorkingProvider: Boolean,
+ setUpGuides: {
+ type: String,
+ required: true,
+ },
+ thisIp: {
+ type: String,
+ required: true,
+ },
+ locationProviders: {
+ type: Object,
+ required: true,
+ },
+ defaultProviderId: {
+ type: String,
+ required: true,
+ },
+ disabledProviderId: {
+ type: String,
+ required: true,
+ },
+ },
+ components: {
+ ActivityIndicator,
+ Notification,
+ SaveButton,
+ },
+ data(): LocationProviderSelectionState {
+ return {
+ isLoading: false,
+ updateLoading: {},
+ selectedProvider: this.currentProviderId,
+ providerLocations: Object.fromEntries(
+ Object.entries(this.locationProviders).map(([k, p]) => [k, p.location]),
+ ),
+ };
+ },
+ methods: {
+ refreshProviderInfo(providerId: string) {
+ // this should not be in a controller... ideally we fetch this data always from client side
+ // and do not prefill it server side
+ this.updateLoading[providerId] = true;
+
+ delete this.providerLocations[providerId];
+
+ AjaxHelper.fetch({
+ module: 'UserCountry',
+ action: 'getLocationUsingProvider',
+ id: providerId,
+ format: 'html',
+ }).then((response) => {
+ this.providerLocations[providerId] = response;
+ }).finally(() => {
+ this.updateLoading[providerId] = false;
+ });
+ },
+ save() {
+ if (!this.selectedProvider) {
+ return;
+ }
+
+ this.isLoading = true;
+ AjaxHelper.fetch(
+ {
+ method: 'UserCountry.setLocationProvider',
+ providerId: this.selectedProvider,
+ },
+ {
+ withTokenInUrl: true,
+ },
+ ).then(() => {
+ const notificationInstanceId = NotificationsStore.show({
+ message: translate('General_Done'),
+ context: 'success',
+ noclear: true,
+ type: 'toast',
+ id: 'userCountryLocationProvider',
+ });
+ NotificationsStore.scrollToNotification(notificationInstanceId);
+ }).finally(() => {
+ this.isLoading = false;
+ });
+ },
+ },
+ computed: {
+ visibleLocationProviders() {
+ return Object.fromEntries(
+ Object.entries(this.locationProviders as ProviderInfo[]).filter(([, p]) => p.isVisible),
+ );
+ },
+ locationProvidersNotDefaultOrDisabled() {
+ return Object.fromEntries(
+ Object.entries(this.locationProviders as ProviderInfo[]).filter(
+ ([, p]) => p.id !== this.defaultProviderId && p.id !== this.disabledProviderId,
+ ),
+ );
+ },
+ noProvidersText() {
+ return translate(
+ 'UserCountry_NoProviders',
+ '<a rel="noreferrer noopener" href="https://db-ip.com/?refid=mtm">',
+ '</a>',
+ );
+ },
+ },
+});
+</script>
diff --git a/plugins/UserCountry/vue/src/index.ts b/plugins/UserCountry/vue/src/index.ts
new file mode 100644
index 0000000000..9f5cffa51d
--- /dev/null
+++ b/plugins/UserCountry/vue/src/index.ts
@@ -0,0 +1,8 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+export { default as LocationProviderSelection } from './LocationProviderSelection/LocationProviderSelection.vue';