diff --git a/Extension/src/background/filter/antibanner.js b/Extension/src/background/filter/antibanner.js index 2c42d233a41..3717f5ab294 100644 --- a/Extension/src/background/filter/antibanner.js +++ b/Extension/src/background/filter/antibanner.js @@ -642,6 +642,10 @@ export const antiBannerService = (() => { log.debug('Saving {0} rules to filter {1}', converted.length, filterId); await rulesStorage.write(filterId, converted); + // notify that user rules were saved, to update saving button on options page + if (Number(filterId) === utils.filters.USER_FILTER_ID) { + listeners.notifyListeners(listeners.USER_FILTER_UPDATED); + } } /** diff --git a/Extension/src/background/message-handler.js b/Extension/src/background/message-handler.js index 2039bcfbcd3..e29188af3a0 100644 --- a/Extension/src/background/message-handler.js +++ b/Extension/src/background/message-handler.js @@ -308,7 +308,7 @@ const createMessageHandler = () => { // We are waiting until request filter is updated return new Promise((resolve) => { const listenerId = listeners.addListener((event) => { - if (event === listeners.REQUEST_FILTER_UPDATED) { + if (event === listeners.USER_FILTER_UPDATED) { listeners.removeListener(listenerId); resolve(); } diff --git a/Extension/src/common/constants.js b/Extension/src/common/constants.js index 063e909468b..5d17553a3e6 100644 --- a/Extension/src/common/constants.js +++ b/Extension/src/common/constants.js @@ -130,7 +130,7 @@ export const NOTIFIER_TYPES = { APPLICATION_UPDATED: 'event.application.updated', CHANGE_PREFS: 'event.change.prefs', UPDATE_FILTERS_SHOW_POPUP: 'event.update.filters.show.popup', - UPDATE_USER_FILTER_RULES: 'event.update.user.filter.rules', + USER_FILTER_UPDATED: 'event.user.filter.updated', UPDATE_ALLOWLIST_FILTER_RULES: 'event.update.allowlist.filter.rules', SETTING_UPDATED: 'event.update.setting.value', FILTERS_UPDATE_CHECK_READY: 'event.update.filters.check', diff --git a/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditor.jsx b/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditor.jsx index b24c98075dd..dd5c9664edf 100644 --- a/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditor.jsx +++ b/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditor.jsx @@ -1,5 +1,4 @@ import React, { useContext, useEffect, useRef } from 'react'; -import throttle from 'lodash/throttle'; import { observer } from 'mobx-react'; import { Range } from 'ace-builds'; import { SimpleRegex } from '@adguard/tsurlfilter/dist/es/simple-regex'; @@ -28,19 +27,22 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { // Get initial data and set to the editor useEffect(() => { (async () => { - const resultsArray = await Promise.all([ - messenger.getEditorStorageContent(), - messenger.sendMessage(MESSAGE_TYPES.GET_USER_RULES_EDITOR_DATA) - ]); - - let editorContent = resultsArray[0]; - const { userRules } = resultsArray[1]; + let editorContent = await messenger.getEditorStorageContent(); + // clear editor content from storage after reading it + await messenger.setEditorStorageContent(null); + let resetInfoThatContentChanged = false; if (!editorContent) { - editorContent = userRules; + const { content } = await messenger.getUserRules(); + editorContent = content; + resetInfoThatContentChanged = true; + } + + editorRef.current.editor.setValue(editorContent, 1); + editorRef.current.editor.session.getUndoManager().reset(); + if (resetInfoThatContentChanged) { + store.setUserRulesEditorContentChangedState(false); } - store.setUserRules(userRules); - editorRef.current.editor.session.setValue(editorContent); })(); }, []); @@ -49,14 +51,15 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { * may be adding user rules from other places like assistant and others * @return {Promise} */ - const handleRequestFilterUpdate = async () => { - const userRulesEditorData = await messenger.sendMessage( + const handleUserFilterUpdated = async () => { + const { userRules } = await messenger.sendMessage( MESSAGE_TYPES.GET_USER_RULES_EDITOR_DATA, ); - const { userRules } = userRulesEditorData; - const { session } = editorRef.current.editor; - if (userRules !== session.getValue()) { - session.setValue(userRules); + + if (!store.userRulesEditorContentChanged) { + editorRef.current.editor.setValue(userRules, 1); + store.setUserRulesEditorContentChangedState(false); + await messenger.setEditorStorageContent(null); } }; @@ -68,7 +71,7 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { // Subscribe to events of request filter update // to have actual user rules in the editor const events = [ - NOTIFIER_TYPES.REQUEST_FILTER_UPDATED, + NOTIFIER_TYPES.USER_FILTER_UPDATED, ]; removeListenerCallback = await messenger.createEventListener( @@ -77,8 +80,8 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { const { type } = message; switch (type) { - case NOTIFIER_TYPES.REQUEST_FILTER_UPDATED: { - await handleRequestFilterUpdate(); + case NOTIFIER_TYPES.USER_FILTER_UPDATED: { + await handleUserFilterUpdated(); break; } default: { @@ -95,19 +98,27 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { }; }, []); + // save editor content to the storage after close of fullscreen + useEffect(() => { + if (fullscreen) { + const beforeUnloadListener = async () => { + if (store.userRulesEditorContentChanged) { + // send content to the storage only before switching editors + const content = editorRef.current.editor.session.getValue(); + await messenger.setEditorStorageContent(content); + } + }; + window.addEventListener('beforeunload', beforeUnloadListener); + } + }, [store.userRulesEditorContentChanged]); + // subscribe to editor changes, to update editor storage content useEffect(() => { - const { session } = editorRef.current.editor; - const UPDATE_STORAGE_THROTTLE_TIMEOUT_MS = 500; - const changeHandler = throttle(async () => { - const content = session.getValue(); - await messenger.setEditorStorageContent(content); - if (content !== store.userRules) { - store.setUserRulesEditorContentChangedState(true); - } - }, UPDATE_STORAGE_THROTTLE_TIMEOUT_MS); + const changeHandler = () => { + store.setUserRulesEditorContentChangedState(true); + }; - session.on('change', changeHandler); + editorRef.current.editor.session.on('change', changeHandler); }, []); // set initial wrap mode @@ -120,9 +131,12 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { const file = event.target.files[0]; try { - const content = await uploadFile(file, 'txt'); - editorRef.current.editor.setValue(content, 1); - await store.saveUserRules(content); + const newRules = await uploadFile(file, 'txt'); + const oldRules = editorRef.current.editor.getValue(); + const unionRules = `${oldRules}\n${newRules}`.split('\n'); + const uniqRules = Array.from(new Set(unionRules)).join('\n'); + editorRef.current.editor.setValue(uniqRules, 1); + await store.saveUserRules(uniqRules); } catch (e) { log.debug(e.message); if (uiStore?.addNotification) { @@ -199,10 +213,22 @@ export const UserRulesEditor = observer(({ fullscreen, uiStore }) => { }; const openEditorFullscreen = async () => { + // send dirty content to the storage only before switching editors + if (store.userRulesEditorContentChanged) { + const content = editorRef.current.editor.session.getValue(); + await messenger.setEditorStorageContent(content); + } + await messenger.sendMessage(MESSAGE_TYPES.OPEN_FULLSCREEN_USER_RULES); }; const closeEditorFullscreen = async () => { + // send dirty content to the storage only before switching editors + if (store.userRulesEditorContentChanged) { + const content = editorRef.current.editor.session.getValue(); + await messenger.setEditorStorageContent(content); + } + window.close(); }; diff --git a/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditorStore.js b/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditorStore.js index 69dbe3d1886..3698a65d821 100644 --- a/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditorStore.js +++ b/Extension/src/pages/common/components/UserRulesEditor/UserRulesEditorStore.js @@ -7,7 +7,6 @@ import { makeObservable, } from 'mobx'; -import { MESSAGE_TYPES } from '../../../../common/constants'; import { messenger } from '../../../services/messenger'; import { optionsStorage } from '../../../options/options-storage'; import { createSavingService, EVENTS as SAVING_FSM_EVENTS, STATES } from '../Editor/savingFSM'; @@ -20,8 +19,6 @@ const savingService = createSavingService({ }); class UserRulesEditorStore { - @observable userRules = ''; - @observable userRulesEditorContentChanged = false; @observable userRulesEditorWrap = null; @@ -41,19 +38,6 @@ class UserRulesEditorStore { }); } - @action - setUserRules = (userrules) => { - this.userRules = userrules; - }; - - getUserRulesEditorData = async () => { - const { userRules } = await messenger.sendMessage( - MESSAGE_TYPES.GET_USER_RULES_EDITOR_DATA, - ); - - this.setUserRules(userRules); - }; - @action setUserRulesEditorContentChangedState = (state) => { this.userRulesEditorContentChanged = state; @@ -78,9 +62,8 @@ class UserRulesEditorStore { return this.userRulesEditorWrap; } - @action + // eslint-disable-next-line class-methods-use-this async saveUserRules(value) { - this.userRules = value; savingService.send(SAVING_FSM_EVENTS.SAVE, { value }); } }