/* global OC, result, _ */ /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-or-later */ (function(_, $, OC) { 'use strict'; /** * Construct a new FederationScopeMenu instance * @constructs FederationScopeMenu * @memberof OC.Settings * @param {object} options * @param {boolean} [options.showFederatedScope=false] whether show the * "v2-federated" scope or not * @param {boolean} [options.showPublishedScope=false] whether show the * "v2-published" scope or not */ var FederationSettingsView = OC.Backbone.View.extend({ _inputFields: undefined, /** @var Backbone.Model */ _config: undefined, initialize: function(options) { options = options || {}; if (options.config) { this._config = options.config; } else { this._config = new OC.Settings.UserSettings(); } this.showFederatedScope = !!options.showFederatedScope; this.showPublishedScope = !!options.showPublishedScope; this._inputFields = [ 'displayname', 'phone', 'email', 'website', 'twitter', 'address', 'avatar' ]; var self = this; _.each(this._inputFields, function(field) { var scopeOnly = field === 'avatar'; // Initialize config model if (!scopeOnly) { self._config.set(field, $('#' + field).val()); } self._config.set(field + 'Scope', $('#' + field + 'scope').val()); // Set inputs whenever model values change if (!scopeOnly) { self.listenTo(self._config, 'change:' + field, function() { self.$('#' + field).val(self._config.get(field)); }); } self.listenTo(self._config, 'change:' + field + 'Scope', function() { self._setFieldScopeIcon(field, self._config.get(field + 'Scope')); }); }); this._registerEvents(); }, render: function() { var self = this; var fieldsWithV2Private = [ 'avatar', 'phone', 'twitter', 'website', 'address', ]; _.each(this._inputFields, function(field) { var $icon = self.$('#' + field + 'form .headerbar-label > .federation-menu'); var excludedScopes = [] if (fieldsWithV2Private.indexOf(field) === -1) { excludedScopes.push('v2-private'); } if (!self.showFederatedScope) { excludedScopes.push('v2-federated'); } if (!self.showPublishedScope) { excludedScopes.push('v2-published'); } var scopeMenu = new OC.Settings.FederationScopeMenu({ field: field, excludedScopes: excludedScopes, }); self.listenTo(scopeMenu, 'select:scope', function(scope) { self._onScopeChanged(field, scope); }); $icon.append(scopeMenu.$el); $icon.attr('aria-expanded', 'false'); $icon.on('click', _.bind(scopeMenu.show, scopeMenu)); $icon.on('keydown', function(e) { if (e.keyCode === 32) { // Open the menu when the user presses the space bar e.preventDefault(); scopeMenu.show(e); } else if (e.keyCode === 27) { // Close the menu again if opened OC.hideMenus(); } }.bind(this)); // Restore initial state self._setFieldScopeIcon(field, self._config.get(field + 'Scope')); }); }, _registerEvents: function() { var self = this; _.each(this._inputFields, function(field) { if ( field === 'avatar' || field === 'email' || field === 'displayname' || field === 'twitter' || field === 'address' || field === 'website' || field === 'phone' ) { return; } self.$('#' + field).keyUpDelayedOrEnter(_.bind(self._onInputChanged, self), true); }); }, _onInputChanged: function(e) { var self = this; var $dialog = $('.oc-dialog:visible'); if (OC.PasswordConfirmation.requiresPasswordConfirmation()) { if($dialog.length === 0) { OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this._onInputChanged, this, e)); } return; } var $target = $(e.target); var value = $target.val(); var field = $target.attr('id'); this._config.set(field, value); var savingData = this._config.save({ error: function(jqXHR) { OC.msg.finishedSaving('#personal-settings-container .msg', jqXHR); } }); $.when(savingData).done(function(data) { if (data.status === "success") { self._showInputChangeSuccess(field); } else { self._showInputChangeFail(field); } }); }, _onScopeChanged: function(field, scope) { var $dialog = $('.oc-dialog:visible'); if (OC.PasswordConfirmation.requiresPasswordConfirmation()) { if($dialog.length === 0) { OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this._onScopeChanged, this, field, scope)); } return; } this._config.set(field + 'Scope', scope); $('#' + field + 'scope').val(scope); // TODO: user loading/success feedback this._config.save(); this._setFieldScopeIcon(field, scope); this._updateVerifyButton(field, scope); }, _updateVerifyButton: function(field, scope) { // show verification button if the value is set and the scope is 'public' if (field === 'twitter' || field === 'website'|| field === 'email') { var verify = this.$('#' + field + 'form > .verify'); var scope = this.$('#' + field + 'scope').val(); var value = this.$('#' + field).val(); if (scope === 'public' && value !== '') { verify.removeClass('hidden'); return true; } else { verify.addClass('hidden'); } } return false; }, _showInputChangeSuccess: function(field) { var $icon = this.$('#' + field + 'form > .icon-checkmark'); $icon.fadeIn(200); setTimeout(function() { $icon.fadeOut(300); }, 2000); var scope = this.$('#' + field + 'scope').val(); var verifyAvailable = this._updateVerifyButton(field, scope); // change verification buttons from 'verify' to 'verifying...' on value change if (verifyAvailable) { if (field === 'twitter' || field === 'website') { var verifyStatus = this.$('#' + field + 'form > .verify > #verify-' + field); verifyStatus.attr('data-origin-title', t('settings', 'Verify')); verifyStatus.attr('src', OC.imagePath('core', 'actions/verify.svg')); verifyStatus.data('status', '0'); verifyStatus.addClass('verify-action'); } else if (field === 'email') { var verifyStatus = this.$('#' + field + 'form > .verify > #verify-' + field); verifyStatus.attr('data-origin-title', t('settings', 'Verifying …')); verifyStatus.data('status', '1'); verifyStatus.attr('src', OC.imagePath('core', 'actions/verifying.svg')); } } }, _showInputChangeFail: function(field) { var $icon = this.$('#' + field + 'form > .icon-error'); $icon.fadeIn(200); setTimeout(function() { $icon.fadeOut(300); }, 2000); }, _setFieldScopeIcon: function(field, scope) { var $icon = this.$('#' + field + 'form > .headerbar-label .icon-federation-menu'); $icon.removeClass('icon-phone'); $icon.removeClass('icon-password'); $icon.removeClass('icon-contacts-dark'); $icon.removeClass('icon-link'); $icon.addClass('hidden'); switch (scope) { case 'v2-private': $icon.addClass('icon-phone'); $icon.removeClass('hidden'); break; case 'v2-local': $icon.addClass('icon-password'); $icon.removeClass('hidden'); break; case 'v2-federated': $icon.addClass('icon-contacts-dark'); $icon.removeClass('hidden'); break; case 'v2-published': $icon.addClass('icon-link'); $icon.removeClass('hidden'); break; } } }); OC.Settings = OC.Settings || {}; OC.Settings.FederationSettingsView = FederationSettingsView; })(_, $, OC);