From 45425944fe3cf44ed0e72b4ca5f617780f033986 Mon Sep 17 00:00:00 2001 From: Chris Taylor Date: Sun, 14 Jan 2024 21:35:05 +0000 Subject: [PATCH] Fix tests --- _locales/ar/messages.json | 4 + _locales/de/messages.json | 4 + _locales/en/messages.json | 4 + _locales/es/messages.json | 4 + _locales/hi/messages.json | 4 + _locales/ja/messages.json | 4 + _locales/ko/messages.json | 335 +++++++++++++++++++++++++++- _locales/pt_PT/messages.json | 335 +++++++++++++++++++++++++++- _locales/ru/messages.json | 4 + _locales/zh_CN/messages.json | 4 + assets/popup.html | 6 + src/background/storage.ts | 1 + src/constants.ts | 12 - src/cypress/e2e/searchreplace.cy.ts | 32 +-- src/popup.ts | 2 + src/searchreplace.ts | 246 ++++++-------------- src/types/types.ts | 24 +- src/util.ts | 2 - 18 files changed, 799 insertions(+), 228 deletions(-) diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index f948db9..219090a 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -75,6 +75,10 @@ "message": "تعبير منتظم (التعبيرات العادية)", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "استبدال الكل", "description": "checkbox replaceAll" diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 1a427ac..789dee9 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -75,6 +75,10 @@ "message": "Regulärer Ausdruck", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "Alle ersetzen", "description": "checkbox replaceAll" diff --git a/_locales/en/messages.json b/_locales/en/messages.json index f8e073a..80603c0 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -75,6 +75,10 @@ "message": "Regular expression", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "Replace all", "description": "checkbox replaceAll" diff --git a/_locales/es/messages.json b/_locales/es/messages.json index ace3cde..585c9bc 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -75,6 +75,10 @@ "message": "Expresión Regular", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "Reemplazar Todo", "description": "checkbox replaceAll" diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index d7726ff..7910c87 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -75,6 +75,10 @@ "message": "नियमित अभिव्यक्ति", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "सभी को बदलें", "description": "checkbox replaceAll" diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 0e1b0fe..c0c65ab 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -75,6 +75,10 @@ "message": "正規表現", "description": "チェックボックス 正規表現" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "すべて置換", "description": "チェックボックス すべて置換" diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index 764518d..b233f64 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -1 +1,334 @@ -{"ext_name":{"message":"검색 및 대체","description":"ext_name"},"ext_description":{"message":"웹 페이지에서 텍스트를 검색하고 다른 텍스트로 대체합니다.","description":"ext_description"},"options":{"message":"옵션","description":"options"},"saved_rules":{"message":"저장된 규칙","description":"Options Tab"},"select_language":{"message":"언어 선택:","description":"Options Tab"},"settings":{"message":"설정","description":"Settings"},"about":{"message":"정보","description":"about"},"version":{"message":"버전","description":"version"},"RuleID":{"message":"규칙 ID","description":"options"},"URLPattern":{"message":"URL 패턴","description":"options"},"SearchTerm":{"message":"검색 용어","description":"options"},"ReplaceTerm":{"message":"대체 용어","description":"options"},"Delete":{"message":"삭제","description":"options"},"Save":{"message":"저장","description":"options"},"matchCase":{"message":"대소문자 구분","description":"checkbox matchCase"},"inputFieldsOnly":{"message":"입력 필드만","description":"checkbox inputFieldsOnly"},"visibleOnly":{"message":"가시적인 콘텐츠만","description":"checkbox visibleOnly"},"wholeWord":{"message":"전체 단어 일치","description":"checkbox wholeWord"},"isRegex":{"message":"정규 표현식","description":"checkbox isRegex"},"replaceAll":{"message":"모두 대체","description":"checkbox replaceAll"},"saveApplyPageReload":{"message":"저장하고 페이지 다시로드 시 적용","description":"checkbox save"},"Searchfor":{"message":"검색 대상","description":"popup"},"Swap":{"message":"교체 ⇅","description":"popup"},"Replacewith":{"message":"다음과 교체","description":"popup"},"Matchcase":{"message":"대소문자 구분","description":"popup"},"Inputfields":{"message":"입력 필드만","description":"popup"},"Visiblecontent":{"message":"가시적인 콘텐츠만","description":"popup"},"Matchwhole":{"message":"전체 단어 일치","description":"popup"},"Regularexpression":{"message":"정규 표현식","description":"popup"},"Saveandapply":{"message":"모두 대체","description":"popup"},"ReplaceNext":{"message":"저장하고 페이지 다시로드 시 적용","description":"popup"},"ReplaceAll":{"message":"다음 찾기","description":"popup"},"History":{"message":"모두 교체","description":"popup"},"Clear":{"message":"기록","description":"popup"},"EditSettings":{"message":"지우기","description":"popup"},"Help":{"message":"설정 편집","description":""},"help_title":{"message":"도움말","description":"help"},"URL":{"message":"검색 및 대체 도움말 페이지","description":""},"Search":{"message":"URL","description":""},"Replace":{"message":"검색","description":""},"Priority":{"message":"대체","description":""},"Example":{"message":"우선순위","description":""},"applied_first":{"message":"예제","description":""},"applied_last":{"message":"첫 번째 적용","description":""},"next_vs_all":{"message":"마지막 적용","description":"Replace Next vs. Replace All"},"next_vs_all_p1":{"message":"다음 찾기 vs. 모두 교체","description":"Replace Next vs. Replace All"},"next_vs_all_p2":{"message":"검색 용어의 첫 번째 발견물을 교체하려면 다음 찾기를 누르십시오. 더 이상 일치하는 항목이 없을 때까지 해당 버튼을 계속 누를 수 있습니다.","description":"Replace Next vs. Replace All"},"next_vs_all_p3":{"message":"검색 용어의 모든 발견물을 교체하려면 모두 교체를 누르십시오.","description":"Replace Next vs. Replace All"},"replace_editors":{"message":"현재로서 취소 기능은 없습니다. 실수를 저지르면 페이지를 다시로드하여 원래 텍스트를 복원할 수 있지만, 텍스트 편집기 및 텍스트 입력 필드에서 저장하지 않은 모든 변경 내용을 잃게 됩니다.","description":"Explanation about replacing text in editors and text fields"},"replace_editors_p1":{"message":"편집기 및 텍스트 필드에서 텍스트 교체","description":"Explanation about replacing text in editors and text fields"},"replace_editors_p2":{"message":"텍스트 편집기 또는 입력 상자에서 텍스트를 교체하려면 입력 필드만? 확인란을 선택해야 합니다. 그렇지 않으면 검색 텍스트가 페이지 전체에 교체되어 페이지가 망가질 수 있습니다. 숨겨진 입력 필드를 변경하지 않으려면 가시적인 요소만? 확인란도 선택해야 합니다.","description":"Explanation about replacing text in editors and text fields"},"Setup":{"message":"텍스트 편집기 또는 입력 상자에서 텍스트를 교체하려면 입력 필드만? 확인란을 선택해야 합니다. 그렇지 않으면 검색 텍스트가 페이지 전체에 교체되어 페이지가 망가질 수 있습니다. 숨겨진 입력 필드를 변경하지 않으려면 가시적인 요소만? 확인란도 선택해야 합니다.","description":"help"},"Replacing_anywhere":{"message":"설정","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_p1":{"message":"페이지 어디서나 텍스트 교체","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_p2":{"message":"텍스트 편집기에 포함되지 않고 텍스트 필드에 포함되지 않은 텍스트를 교체하려면 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하지 않은 상태로 두어야 합니다.","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_warning":{"message":"텍스트 편집기에 포함되지 않고 텍스트 필드에 포함되지 않은 텍스트를 교체하려면 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하지 않은 상태로 두어야 합니다.","description":"Explanation about replacing text anywhere on the page"},"Matching_case":{"message":"경고: 이 설정은 페이지의 HTML을 변경하고 페이지를 망가뜨릴 수 있습니다. 페이지를 다시로드하여 페이지를 복원할 수 있지만 텍스트 편집기 및 텍스트 입력 필드에서 저장하지 않은 모든 변경 내용을 잃게 됩니다.","description":"Explanation about matching the case of text"},"Matching_case_p1":{"message":"텍스트의 대소문자 일치","description":"Explanation about matching the case of text"},"Matching_case_p2":{"message":"이렇게를 교체해야하지만 이렇게를 교체하지 않아야 하는 경우 대소문자 일치 옵션을 사용해야 합니다.","description":"Explanation about matching the case of text"},"Matching_whole":{"message":"다음 설정에서는 아파트를 일치시키지만 아파트를 일치시키지 않습니다. 페이지에서 보이는 텍스트 필드에서 아파트아파트로 교체합니다.","description":"Matching whole words"},"Matching_whole_p1":{"message":"전체 단어 일치","description":"Matching whole words"},"wildcards_and_regex":{"message":"부분 단어를 교체하지만 부분적으로를 교체하지 않아야 하는 경우 전체 단어 일치? 옵션을 사용해야 합니다.","description":"Explanation about wild cards and regular expressions"},"wildcards_and_regex_p1":{"message":"와일드 카드 및 정규 표현식","description":"Explanation about wild cards and regular expressions"},"Before":{"message":"일부 검색 용어와 일치하려면 정규 표현식 확인란을 선택하고 와일드 카드를 지정해야 합니다. 이 기능을 사용하려면 정규 표현식에 대한 매우 기본적인 지식이 필요합니다. 테스트를 위해 regexpal을 권장합니다.","description":""},"After":{"message":"이전","description":""},"Replacing_wordpress":{"message":"이후","description":""},"Replacing_wordpress_p1":{"message":"WordPress에서 텍스트 교체","description":""},"Replacing_wordpress_setup_w6":{"message":"2023년 3월 현재, WordPress는 버전 6.6에 해당합니다. 이 확장이 작성된 이후 게시글 편집기가 크게 변경되었으며 WordPress에서 텍스트를 교체하려면 새로운 설정이 필요합니다.","description":""},"Replacing_wordpress_setup_w5":{"message":"WordPress 6+를 위한 설정","description":""},"Save_apply":{"message":"WordPress 5 및 이하 버전을 위한 설정","description":"Save and apply on page reload"},"Save_apply_p1":{"message":"페이지 다시로드 시 저장 및 적용","description":"Save and apply on page reload"},"Save_apply_multi":{"message":"검색을 저장하고 페이지를 다시로드할 때 적용하려면 저장 및 페이지 다시로드 시 적용 확인란을 선택할 수 있습니다. 이러한 설정은 브라우저에서 유지되고 다시 열립니다.","description":"Multiple Matching Rules"},"Save_apply_multi_p1":{"message":"여러 규칙 일치","description":"Multiple Matching Rules"},"Save_apply_multi_p2":{"message":"같은 페이지에 여러 규칙이 적용되는 경우 규칙은 가장 구체적인 것부터 구체적인 것으로 순서대로 적용됩니다. 예를 들어:","description":"Multiple Matching Rules"},"Save_apply_multi_p3":{"message":"이것은 첫 번째 규칙에 의해 적용된 모든 변경 사항이 후속 규칙에 입력됨을 의미합니다. 위의 예에서 예제 텍스트는 http://www.example.com/a/deeper/nested/page와 일치하는 규칙에 의해 대체되었을 것입니다. 따라서 후속 규칙은 아무런 영향을 미치지 않을 것입니다.","description":"Multiple Matching Rules"},"ReportingIssues":{"message":"확장 팝업에서 규칙 편집 링크를 클릭하여 저장된 규칙을 편집할 수 있습니다. URL 패턴 필드는 여러 다른 웹 사이트에 동일한 규칙을 적용할 수 있도록 하는 정규 표현식입니다.","description":""},"ReportingIssuesWarning":{"message":"문제 보고","description":""},"ReportingIssuesInfo":{"message":"설치 후 텍스트를 교체하려는 페이지를 새로 고침해야 함을 기억하세요.","description":""},"ReportingIssues_p1":{"message":"확장을 사용한 후 페이지가 망가진 경우, 페이지를 다시로드하고 검색 및 교체를 수행하기 전에 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하십시오.","description":""},"Rate_on_store":{"message":"버그를 발견하면 Chrome 확장 스토어 또는 GitHub에서 자세한 보고서를 제공하십시오.","description":""},"no_saved_instances":{"message":"이 확장이 도움이 된다면 Chrome 스토어에서 ★★★★★로 평가해 주십시오!","description":"message to tell user that no rules were found"},"matches":{"message":"저장된 인스턴스 없음","description":"message to tell user how many instances of the search term were found"}} \ No newline at end of file +{ + "ext_name": { + "message": "검색 및 대체", + "description": "ext_name" + }, + "ext_description": { + "message": "웹 페이지에서 텍스트를 검색하고 다른 텍스트로 대체합니다.", + "description": "ext_description" + }, + "options": { + "message": "옵션", + "description": "options" + }, + "saved_rules": { + "message": "저장된 규칙", + "description": "Options Tab" + }, + "select_language": { + "message": "언어 선택:", + "description": "Options Tab" + }, + "settings": { + "message": "설정", + "description": "Settings" + }, + "about": { + "message": "정보", + "description": "about" + }, + "version": { + "message": "버전", + "description": "version" + }, + "RuleID": { + "message": "규칙 ID", + "description": "options" + }, + "URLPattern": { + "message": "URL 패턴", + "description": "options" + }, + "SearchTerm": { + "message": "검색 용어", + "description": "options" + }, + "ReplaceTerm": { + "message": "대체 용어", + "description": "options" + }, + "Delete": { + "message": "삭제", + "description": "options" + }, + "Save": { + "message": "저장", + "description": "options" + }, + "matchCase": { + "message": "대소문자 구분", + "description": "checkbox matchCase" + }, + "inputFieldsOnly": { + "message": "입력 필드만", + "description": "checkbox inputFieldsOnly" + }, + "visibleOnly": { + "message": "가시적인 콘텐츠만", + "description": "checkbox visibleOnly" + }, + "wholeWord": { + "message": "전체 단어 일치", + "description": "checkbox wholeWord" + }, + "isRegex": { + "message": "정규 표현식", + "description": "checkbox isRegex" + }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, + "replaceAll": { + "message": "모두 대체", + "description": "checkbox replaceAll" + }, + "saveApplyPageReload": { + "message": "저장하고 페이지 다시로드 시 적용", + "description": "checkbox save" + }, + "Searchfor": { + "message": "검색 대상", + "description": "popup" + }, + "Swap": { + "message": "교체 ⇅", + "description": "popup" + }, + "Replacewith": { + "message": "다음과 교체", + "description": "popup" + }, + "Matchcase": { + "message": "대소문자 구분", + "description": "popup" + }, + "Inputfields": { + "message": "입력 필드만", + "description": "popup" + }, + "Visiblecontent": { + "message": "가시적인 콘텐츠만", + "description": "popup" + }, + "Matchwhole": { + "message": "전체 단어 일치", + "description": "popup" + }, + "Regularexpression": { + "message": "정규 표현식", + "description": "popup" + }, + "Saveandapply": { + "message": "모두 대체", + "description": "popup" + }, + "ReplaceNext": { + "message": "저장하고 페이지 다시로드 시 적용", + "description": "popup" + }, + "ReplaceAll": { + "message": "다음 찾기", + "description": "popup" + }, + "History": { + "message": "모두 교체", + "description": "popup" + }, + "Clear": { + "message": "기록", + "description": "popup" + }, + "EditSettings": { + "message": "지우기", + "description": "popup" + }, + "Help": { + "message": "설정 편집", + "description": "" + }, + "help_title": { + "message": "도움말", + "description": "help" + }, + "URL": { + "message": "검색 및 대체 도움말 페이지", + "description": "" + }, + "Search": { + "message": "URL", + "description": "" + }, + "Replace": { + "message": "검색", + "description": "" + }, + "Priority": { + "message": "대체", + "description": "" + }, + "Example": { + "message": "우선순위", + "description": "" + }, + "applied_first": { + "message": "예제", + "description": "" + }, + "applied_last": { + "message": "첫 번째 적용", + "description": "" + }, + "next_vs_all": { + "message": "마지막 적용", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p1": { + "message": "다음 찾기 vs. 모두 교체", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p2": { + "message": "검색 용어의 첫 번째 발견물을 교체하려면 다음 찾기를 누르십시오. 더 이상 일치하는 항목이 없을 때까지 해당 버튼을 계속 누를 수 있습니다.", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p3": { + "message": "검색 용어의 모든 발견물을 교체하려면 모두 교체를 누르십시오.", + "description": "Replace Next vs. Replace All" + }, + "replace_editors": { + "message": "현재로서 취소 기능은 없습니다. 실수를 저지르면 페이지를 다시로드하여 원래 텍스트를 복원할 수 있지만, 텍스트 편집기 및 텍스트 입력 필드에서 저장하지 않은 모든 변경 내용을 잃게 됩니다.", + "description": "Explanation about replacing text in editors and text fields" + }, + "replace_editors_p1": { + "message": "편집기 및 텍스트 필드에서 텍스트 교체", + "description": "Explanation about replacing text in editors and text fields" + }, + "replace_editors_p2": { + "message": "텍스트 편집기 또는 입력 상자에서 텍스트를 교체하려면 입력 필드만? 확인란을 선택해야 합니다. 그렇지 않으면 검색 텍스트가 페이지 전체에 교체되어 페이지가 망가질 수 있습니다. 숨겨진 입력 필드를 변경하지 않으려면 가시적인 요소만? 확인란도 선택해야 합니다.", + "description": "Explanation about replacing text in editors and text fields" + }, + "Setup": { + "message": "텍스트 편집기 또는 입력 상자에서 텍스트를 교체하려면 입력 필드만? 확인란을 선택해야 합니다. 그렇지 않으면 검색 텍스트가 페이지 전체에 교체되어 페이지가 망가질 수 있습니다. 숨겨진 입력 필드를 변경하지 않으려면 가시적인 요소만? 확인란도 선택해야 합니다.", + "description": "help" + }, + "Replacing_anywhere": { + "message": "설정", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_p1": { + "message": "페이지 어디서나 텍스트 교체", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_p2": { + "message": "텍스트 편집기에 포함되지 않고 텍스트 필드에 포함되지 않은 텍스트를 교체하려면 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하지 않은 상태로 두어야 합니다.", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_warning": { + "message": "텍스트 편집기에 포함되지 않고 텍스트 필드에 포함되지 않은 텍스트를 교체하려면 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하지 않은 상태로 두어야 합니다.", + "description": "Explanation about replacing text anywhere on the page" + }, + "Matching_case": { + "message": "경고: 이 설정은 페이지의 HTML을 변경하고 페이지를 망가뜨릴 수 있습니다. 페이지를 다시로드하여 페이지를 복원할 수 있지만 텍스트 편집기 및 텍스트 입력 필드에서 저장하지 않은 모든 변경 내용을 잃게 됩니다.", + "description": "Explanation about matching the case of text" + }, + "Matching_case_p1": { + "message": "텍스트의 대소문자 일치", + "description": "Explanation about matching the case of text" + }, + "Matching_case_p2": { + "message": "이렇게를 교체해야하지만 이렇게를 교체하지 않아야 하는 경우 대소문자 일치 옵션을 사용해야 합니다.", + "description": "Explanation about matching the case of text" + }, + "Matching_whole": { + "message": "다음 설정에서는 아파트를 일치시키지만 아파트를 일치시키지 않습니다. 페이지에서 보이는 텍스트 필드에서 아파트아파트로 교체합니다.", + "description": "Matching whole words" + }, + "Matching_whole_p1": { + "message": "전체 단어 일치", + "description": "Matching whole words" + }, + "wildcards_and_regex": { + "message": "부분 단어를 교체하지만 부분적으로를 교체하지 않아야 하는 경우 전체 단어 일치? 옵션을 사용해야 합니다.", + "description": "Explanation about wild cards and regular expressions" + }, + "wildcards_and_regex_p1": { + "message": "와일드 카드 및 정규 표현식", + "description": "Explanation about wild cards and regular expressions" + }, + "Before": { + "message": "일부 검색 용어와 일치하려면 정규 표현식 확인란을 선택하고 와일드 카드를 지정해야 합니다. 이 기능을 사용하려면 정규 표현식에 대한 매우 기본적인 지식이 필요합니다. 테스트를 위해 regexpal을 권장합니다.", + "description": "" + }, + "After": { + "message": "이전", + "description": "" + }, + "Replacing_wordpress": { + "message": "이후", + "description": "" + }, + "Replacing_wordpress_p1": { + "message": "WordPress에서 텍스트 교체", + "description": "" + }, + "Replacing_wordpress_setup_w6": { + "message": "2023년 3월 현재, WordPress는 버전 6.6에 해당합니다. 이 확장이 작성된 이후 게시글 편집기가 크게 변경되었으며 WordPress에서 텍스트를 교체하려면 새로운 설정이 필요합니다.", + "description": "" + }, + "Replacing_wordpress_setup_w5": { + "message": "WordPress 6+를 위한 설정", + "description": "" + }, + "Save_apply": { + "message": "WordPress 5 및 이하 버전을 위한 설정", + "description": "Save and apply on page reload" + }, + "Save_apply_p1": { + "message": "페이지 다시로드 시 저장 및 적용", + "description": "Save and apply on page reload" + }, + "Save_apply_multi": { + "message": "검색을 저장하고 페이지를 다시로드할 때 적용하려면 저장 및 페이지 다시로드 시 적용 확인란을 선택할 수 있습니다. 이러한 설정은 브라우저에서 유지되고 다시 열립니다.", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p1": { + "message": "여러 규칙 일치", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p2": { + "message": "같은 페이지에 여러 규칙이 적용되는 경우 규칙은 가장 구체적인 것부터 구체적인 것으로 순서대로 적용됩니다. 예를 들어:", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p3": { + "message": "이것은 첫 번째 규칙에 의해 적용된 모든 변경 사항이 후속 규칙에 입력됨을 의미합니다. 위의 예에서 예제 텍스트는 http://www.example.com/a/deeper/nested/page와 일치하는 규칙에 의해 대체되었을 것입니다. 따라서 후속 규칙은 아무런 영향을 미치지 않을 것입니다.", + "description": "Multiple Matching Rules" + }, + "ReportingIssues": { + "message": "확장 팝업에서 규칙 편집 링크를 클릭하여 저장된 규칙을 편집할 수 있습니다. URL 패턴 필드는 여러 다른 웹 사이트에 동일한 규칙을 적용할 수 있도록 하는 정규 표현식입니다.", + "description": "" + }, + "ReportingIssuesWarning": { + "message": "문제 보고", + "description": "" + }, + "ReportingIssuesInfo": { + "message": "설치 후 텍스트를 교체하려는 페이지를 새로 고침해야 함을 기억하세요.", + "description": "" + }, + "ReportingIssues_p1": { + "message": "확장을 사용한 후 페이지가 망가진 경우, 페이지를 다시로드하고 검색 및 교체를 수행하기 전에 입력 필드만?가시적인 콘텐츠만? 확인란을 선택하십시오.", + "description": "" + }, + "Rate_on_store": { + "message": "버그를 발견하면 Chrome 확장 스토어 또는 GitHub에서 자세한 보고서를 제공하십시오.", + "description": "" + }, + "no_saved_instances": { + "message": "이 확장이 도움이 된다면 Chrome 스토어에서 ★★★★★로 평가해 주십시오!", + "description": "message to tell user that no rules were found" + }, + "matches": { + "message": "저장된 인스턴스 없음", + "description": "message to tell user how many instances of the search term were found" + } +} diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json index 993272f..3abec8e 100644 --- a/_locales/pt_PT/messages.json +++ b/_locales/pt_PT/messages.json @@ -1 +1,334 @@ -{"ext_name":{"message":"Pesquisar e Substituir","description":"ext_name"},"ext_description":{"message":"Pesquise texto em uma página da web e substitua-o por outro texto.","description":"ext_description"},"options":{"message":"Opções","description":"options"},"saved_rules":{"message":"Regras Salvas","description":"Options Tab"},"select_language":{"message":"Selecione um idioma:","description":"Options Tab"},"settings":{"message":"Configurações","description":"Settings"},"about":{"message":"Sobre","description":"about"},"version":{"message":"Versão","description":"version"},"RuleID":{"message":"ID da Regra","description":"options"},"URLPattern":{"message":"Padrão de URL","description":"options"},"SearchTerm":{"message":"Termo de Pesquisa","description":"options"},"ReplaceTerm":{"message":"Termo de Substituição","description":"options"},"Delete":{"message":"Excluir","description":"options"},"Save":{"message":"Salvar","description":"options"},"matchCase":{"message":"Diferenciar maiúsculas","description":"checkbox matchCase"},"inputFieldsOnly":{"message":"Apenas campos de entrada","description":"checkbox inputFieldsOnly"},"visibleOnly":{"message":"Apenas conteúdo visível","description":"checkbox visibleOnly"},"wholeWord":{"message":"Corresponder palavra inteira","description":"checkbox wholeWord"},"isRegex":{"message":"Expressão regular","description":"checkbox isRegex"},"replaceAll":{"message":"Substituir tudo","description":"checkbox replaceAll"},"saveApplyPageReload":{"message":"Salvar e aplicar na recarga da página","description":"checkbox save"},"Searchfor":{"message":"Pesquisar por","description":"popup"},"Swap":{"message":"Trocar ⇅","description":"popup"},"Replacewith":{"message":"Substituir por","description":"popup"},"Matchcase":{"message":"Diferenciar maiúsculas","description":"popup"},"Inputfields":{"message":"Apenas campos de entrada","description":"popup"},"Visiblecontent":{"message":"Apenas conteúdo visível","description":"popup"},"Matchwhole":{"message":"Corresponder palavra inteira","description":"popup"},"Regularexpression":{"message":"Expressão regular","description":"popup"},"Saveandapply":{"message":"Salvar e aplicar na recarga da página","description":"popup"},"ReplaceNext":{"message":"Substituir Próximo","description":"popup"},"ReplaceAll":{"message":"Substituir Tudo","description":"popup"},"History":{"message":"Histórico","description":"popup"},"Clear":{"message":"Limpar","description":"popup"},"EditSettings":{"message":"Editar Configurações","description":"popup"},"Help":{"message":"Ajuda","description":""},"help_title":{"message":"Página de Ajuda para Pesquisar e Substituir","description":"help"},"URL":{"message":"URL","description":""},"Search":{"message":"Pesquisar","description":""},"Replace":{"message":"Substituir","description":""},"Priority":{"message":"Prioridade","description":""},"Example":{"message":"Exemplo","description":""},"applied_first":{"message":"aplicado primeiro","description":""},"applied_last":{"message":"aplicado por último","description":""},"next_vs_all":{"message":"Substituir Próximo vs. Substituir Tudo","description":"Replace Next vs. Replace All"},"next_vs_all_p1":{"message":"Para substituir a primeira ocorrência do termo de pesquisa, pressione Substituir Próximo. Você pode continuar pressionando o botão até que não haja mais ocorrências.","description":"Replace Next vs. Replace All"},"next_vs_all_p2":{"message":"Para substituir todas as ocorrências do termo de pesquisa, pressione Substituir Tudo.","description":"Replace Next vs. Replace All"},"next_vs_all_p3":{"message":"Atualmente, não há função de desfazer. Se você cometer um erro, pode recarregar a página para restaurar o texto original. No entanto, você perderá quaisquer alterações não salvas nos editores de texto e nos campos de entrada de texto.","description":"Replace Next vs. Replace All"},"replace_editors":{"message":"Substituir texto em editores de texto e campos de entrada de texto","description":"Explanation about replacing text in editors and text fields"},"replace_editors_p1":{"message":"Para substituir texto em editores de texto ou caixas de entrada, você deve marcar a caixa Apenas campos de entrada?. Caso contrário, o texto de pesquisa será substituído em todo o HTML, o que pode quebrar a página. Para evitar a alteração de campos de entrada ocultos, você também deve marcar a caixa Apenas elementos visíveis?.","description":"Explanation about replacing text in editors and text fields"},"replace_editors_p2":{"message":"Para substituir texto em editores de texto ou caixas de entrada, você deve marcar a caixa Apenas campos de entrada?. Caso contrário, o texto de pesquisa será substituído em todo o HTML, o que pode quebrar a página. Para evitar a alteração de campos de entrada ocultos, você também deve marcar a caixa Apenas elementos visíveis?.","description":"Explanation about replacing text in editors and text fields"},"Setup":{"message":"Configuração","description":"help"},"Replacing_anywhere":{"message":"Substituir texto em qualquer lugar na página","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_p1":{"message":"Para substituir texto que não está contido em um editor de texto e não está contido em um campo de entrada de texto, deixe as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? não marcadas.","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_p2":{"message":"Para substituir texto que não está contido em um editor de texto e não está contido em um campo de entrada de texto, deixe as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? não marcadas.","description":"Explanation about replacing text anywhere on the page"},"Replacing_anywhere_warning":{"message":"AVISO: Esta configuração alterará o HTML da página e poderá quebrar a página. Você pode restaurar a página recarregando-a, mas perderá quaisquer alterações não salvas nos editores de texto e nos campos de entrada de texto.","description":"Explanation about replacing text anywhere on the page"},"Matching_case":{"message":"Correspondência de maiúsculas e minúsculas do texto","description":"Explanation about matching the case of text"},"Matching_case_p1":{"message":"Se você precisar substituir ISTO mas não Isto, deve usar a opção de correspondência de maiúsculas e minúsculas.","description":"Explanation about matching the case of text"},"Matching_case_p2":{"message":"A configuração a seguir corresponderá a Condomínio mas não condomínio. Ela substituirá Condomínio por apartamento em campos de texto que são visíveis na página.","description":"Explanation about matching the case of text"},"Matching_whole":{"message":"Correspondência de palavra inteira","description":"Matching whole words"},"Matching_whole_p1":{"message":"Se você precisar substituir a palavra parcial mas não parcialmente, deve usar a opção Corresponder palavra inteira?.","description":"Matching whole words"},"wildcards_and_regex":{"message":"Coringas e Expressões Regulares","description":"Explanation about wild cards and regular expressions"},"wildcards_and_regex_p1":{"message":"Se você precisar corresponder a uma parte do termo de pesquisa, deve marcar a caixa de seleção Expressões Regulares e especificar um caractere curinga. Você precisará de um conhecimento básico de expressões regulares para usar esse recurso. Recomenda-se o uso de regexpal para testes.","description":"Explanation about wild cards and regular expressions"},"Before":{"message":"Antes","description":""},"After":{"message":"Depois","description":""},"Replacing_wordpress":{"message":"Substituir texto no WordPress","description":""},"Replacing_wordpress_p1":{"message":"O WordPress está atualmente na versão 6.6, a partir de março de 2023. O editor de postagens mudou significativamente desde a criação desta extensão e é necessária uma nova configuração para substituir texto no WordPress.","description":""},"Replacing_wordpress_setup_w6":{"message":"Configuração para WordPress 6+","description":""},"Replacing_wordpress_setup_w5":{"message":"Configuração para WordPress 5 e versões anteriores","description":""},"Save_apply":{"message":"Salvar e aplicar na recarga da página","description":"Save and apply on page reload"},"Save_apply_p1":{"message":"Você pode marcar a caixa Salvar e aplicar na recarga da página para salvar sua pesquisa e aplicá-la nas recargas subsequentes da página. Isso será salvo e reaberto em seu navegador.","description":"Save and apply on page reload"},"Save_apply_multi":{"message":"Regras de Correspondência Múltipla","description":"Multiple Matching Rules"},"Save_apply_multi_p1":{"message":"Se várias regras se aplicarem à mesma página, as regras serão aplicadas em ordem do mais específico para o menos específico. Por exemplo:","description":"Multiple Matching Rules"},"Save_apply_multi_p2":{"message":"Isso significa que quaisquer alterações aplicadas pela primeira regra serão passadas para as regras subsequentes. No exemplo acima, o texto Exemplo teria sido substituído pela regra que corresponde a http://www.example.com/a/deeper/nested/page. Portanto, regras subsequentes não terão efeito.","description":"Multiple Matching Rules"},"Save_apply_multi_p3":{"message":"Você pode editar as regras salvas clicando no link Editar Regras na janela pop-up da extensão. O campo Padrão de URL é uma expressão regular, que permite que você aplique a mesma regra a muitos sites diferentes.","description":"Multiple Matching Rules"},"ReportingIssues":{"message":"Relatórios de Problemas","description":""},"ReportingIssuesWarning":{"message":"Lembre-se de ATUALIZAR a página na qual deseja substituir o texto após a instalação.","description":""},"ReportingIssuesInfo":{"message":"Se a página estiver quebrada após o uso da extensão, tente atualizar a página e, em seguida, marcar as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? antes de realizar uma pesquisa e substituição.","description":""},"ReportingIssues_p1":{"message":"Se você encontrar um erro, forneça um relatório detalhado na Chrome Extension Store ou no GitHub.","description":""},"Rate_on_store":{"message":"Por favor, avalie com ★★★★★ na Chrome Store se a extensão lhe ajudar!","description":""},"no_saved_instances":{"message":"Nenhuma instância salva","description":"message to tell user that no rules were found"},"matches":{"message":"correspondências","description":"message to tell user how many instances of the search term were found"}} \ No newline at end of file +{ + "ext_name": { + "message": "Pesquisar e Substituir", + "description": "ext_name" + }, + "ext_description": { + "message": "Pesquise texto em uma página da web e substitua-o por outro texto.", + "description": "ext_description" + }, + "options": { + "message": "Opções", + "description": "options" + }, + "saved_rules": { + "message": "Regras Salvas", + "description": "Options Tab" + }, + "select_language": { + "message": "Selecione um idioma:", + "description": "Options Tab" + }, + "settings": { + "message": "Configurações", + "description": "Settings" + }, + "about": { + "message": "Sobre", + "description": "about" + }, + "version": { + "message": "Versão", + "description": "version" + }, + "RuleID": { + "message": "ID da Regra", + "description": "options" + }, + "URLPattern": { + "message": "Padrão de URL", + "description": "options" + }, + "SearchTerm": { + "message": "Termo de Pesquisa", + "description": "options" + }, + "ReplaceTerm": { + "message": "Termo de Substituição", + "description": "options" + }, + "Delete": { + "message": "Excluir", + "description": "options" + }, + "Save": { + "message": "Salvar", + "description": "options" + }, + "matchCase": { + "message": "Diferenciar maiúsculas", + "description": "checkbox matchCase" + }, + "inputFieldsOnly": { + "message": "Apenas campos de entrada", + "description": "checkbox inputFieldsOnly" + }, + "visibleOnly": { + "message": "Apenas conteúdo visível", + "description": "checkbox visibleOnly" + }, + "wholeWord": { + "message": "Corresponder palavra inteira", + "description": "checkbox wholeWord" + }, + "isRegex": { + "message": "Expressão regular", + "description": "checkbox isRegex" + }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, + "replaceAll": { + "message": "Substituir tudo", + "description": "checkbox replaceAll" + }, + "saveApplyPageReload": { + "message": "Salvar e aplicar na recarga da página", + "description": "checkbox save" + }, + "Searchfor": { + "message": "Pesquisar por", + "description": "popup" + }, + "Swap": { + "message": "Trocar ⇅", + "description": "popup" + }, + "Replacewith": { + "message": "Substituir por", + "description": "popup" + }, + "Matchcase": { + "message": "Diferenciar maiúsculas", + "description": "popup" + }, + "Inputfields": { + "message": "Apenas campos de entrada", + "description": "popup" + }, + "Visiblecontent": { + "message": "Apenas conteúdo visível", + "description": "popup" + }, + "Matchwhole": { + "message": "Corresponder palavra inteira", + "description": "popup" + }, + "Regularexpression": { + "message": "Expressão regular", + "description": "popup" + }, + "Saveandapply": { + "message": "Salvar e aplicar na recarga da página", + "description": "popup" + }, + "ReplaceNext": { + "message": "Substituir Próximo", + "description": "popup" + }, + "ReplaceAll": { + "message": "Substituir Tudo", + "description": "popup" + }, + "History": { + "message": "Histórico", + "description": "popup" + }, + "Clear": { + "message": "Limpar", + "description": "popup" + }, + "EditSettings": { + "message": "Editar Configurações", + "description": "popup" + }, + "Help": { + "message": "Ajuda", + "description": "" + }, + "help_title": { + "message": "Página de Ajuda para Pesquisar e Substituir", + "description": "help" + }, + "URL": { + "message": "URL", + "description": "" + }, + "Search": { + "message": "Pesquisar", + "description": "" + }, + "Replace": { + "message": "Substituir", + "description": "" + }, + "Priority": { + "message": "Prioridade", + "description": "" + }, + "Example": { + "message": "Exemplo", + "description": "" + }, + "applied_first": { + "message": "aplicado primeiro", + "description": "" + }, + "applied_last": { + "message": "aplicado por último", + "description": "" + }, + "next_vs_all": { + "message": "Substituir Próximo vs. Substituir Tudo", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p1": { + "message": "Para substituir a primeira ocorrência do termo de pesquisa, pressione Substituir Próximo. Você pode continuar pressionando o botão até que não haja mais ocorrências.", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p2": { + "message": "Para substituir todas as ocorrências do termo de pesquisa, pressione Substituir Tudo.", + "description": "Replace Next vs. Replace All" + }, + "next_vs_all_p3": { + "message": "Atualmente, não há função de desfazer. Se você cometer um erro, pode recarregar a página para restaurar o texto original. No entanto, você perderá quaisquer alterações não salvas nos editores de texto e nos campos de entrada de texto.", + "description": "Replace Next vs. Replace All" + }, + "replace_editors": { + "message": "Substituir texto em editores de texto e campos de entrada de texto", + "description": "Explanation about replacing text in editors and text fields" + }, + "replace_editors_p1": { + "message": "Para substituir texto em editores de texto ou caixas de entrada, você deve marcar a caixa Apenas campos de entrada?. Caso contrário, o texto de pesquisa será substituído em todo o HTML, o que pode quebrar a página. Para evitar a alteração de campos de entrada ocultos, você também deve marcar a caixa Apenas elementos visíveis?.", + "description": "Explanation about replacing text in editors and text fields" + }, + "replace_editors_p2": { + "message": "Para substituir texto em editores de texto ou caixas de entrada, você deve marcar a caixa Apenas campos de entrada?. Caso contrário, o texto de pesquisa será substituído em todo o HTML, o que pode quebrar a página. Para evitar a alteração de campos de entrada ocultos, você também deve marcar a caixa Apenas elementos visíveis?.", + "description": "Explanation about replacing text in editors and text fields" + }, + "Setup": { + "message": "Configuração", + "description": "help" + }, + "Replacing_anywhere": { + "message": "Substituir texto em qualquer lugar na página", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_p1": { + "message": "Para substituir texto que não está contido em um editor de texto e não está contido em um campo de entrada de texto, deixe as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? não marcadas.", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_p2": { + "message": "Para substituir texto que não está contido em um editor de texto e não está contido em um campo de entrada de texto, deixe as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? não marcadas.", + "description": "Explanation about replacing text anywhere on the page" + }, + "Replacing_anywhere_warning": { + "message": "AVISO: Esta configuração alterará o HTML da página e poderá quebrar a página. Você pode restaurar a página recarregando-a, mas perderá quaisquer alterações não salvas nos editores de texto e nos campos de entrada de texto.", + "description": "Explanation about replacing text anywhere on the page" + }, + "Matching_case": { + "message": "Correspondência de maiúsculas e minúsculas do texto", + "description": "Explanation about matching the case of text" + }, + "Matching_case_p1": { + "message": "Se você precisar substituir ISTO mas não Isto, deve usar a opção de correspondência de maiúsculas e minúsculas.", + "description": "Explanation about matching the case of text" + }, + "Matching_case_p2": { + "message": "A configuração a seguir corresponderá a Condomínio mas não condomínio. Ela substituirá Condomínio por apartamento em campos de texto que são visíveis na página.", + "description": "Explanation about matching the case of text" + }, + "Matching_whole": { + "message": "Correspondência de palavra inteira", + "description": "Matching whole words" + }, + "Matching_whole_p1": { + "message": "Se você precisar substituir a palavra parcial mas não parcialmente, deve usar a opção Corresponder palavra inteira?.", + "description": "Matching whole words" + }, + "wildcards_and_regex": { + "message": "Coringas e Expressões Regulares", + "description": "Explanation about wild cards and regular expressions" + }, + "wildcards_and_regex_p1": { + "message": "Se você precisar corresponder a uma parte do termo de pesquisa, deve marcar a caixa de seleção Expressões Regulares e especificar um caractere curinga. Você precisará de um conhecimento básico de expressões regulares para usar esse recurso. Recomenda-se o uso de regexpal para testes.", + "description": "Explanation about wild cards and regular expressions" + }, + "Before": { + "message": "Antes", + "description": "" + }, + "After": { + "message": "Depois", + "description": "" + }, + "Replacing_wordpress": { + "message": "Substituir texto no WordPress", + "description": "" + }, + "Replacing_wordpress_p1": { + "message": "O WordPress está atualmente na versão 6.6, a partir de março de 2023. O editor de postagens mudou significativamente desde a criação desta extensão e é necessária uma nova configuração para substituir texto no WordPress.", + "description": "" + }, + "Replacing_wordpress_setup_w6": { + "message": "Configuração para WordPress 6+", + "description": "" + }, + "Replacing_wordpress_setup_w5": { + "message": "Configuração para WordPress 5 e versões anteriores", + "description": "" + }, + "Save_apply": { + "message": "Salvar e aplicar na recarga da página", + "description": "Save and apply on page reload" + }, + "Save_apply_p1": { + "message": "Você pode marcar a caixa Salvar e aplicar na recarga da página para salvar sua pesquisa e aplicá-la nas recargas subsequentes da página. Isso será salvo e reaberto em seu navegador.", + "description": "Save and apply on page reload" + }, + "Save_apply_multi": { + "message": "Regras de Correspondência Múltipla", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p1": { + "message": "Se várias regras se aplicarem à mesma página, as regras serão aplicadas em ordem do mais específico para o menos específico. Por exemplo:", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p2": { + "message": "Isso significa que quaisquer alterações aplicadas pela primeira regra serão passadas para as regras subsequentes. No exemplo acima, o texto Exemplo teria sido substituído pela regra que corresponde a http://www.example.com/a/deeper/nested/page. Portanto, regras subsequentes não terão efeito.", + "description": "Multiple Matching Rules" + }, + "Save_apply_multi_p3": { + "message": "Você pode editar as regras salvas clicando no link Editar Regras na janela pop-up da extensão. O campo Padrão de URL é uma expressão regular, que permite que você aplique a mesma regra a muitos sites diferentes.", + "description": "Multiple Matching Rules" + }, + "ReportingIssues": { + "message": "Relatórios de Problemas", + "description": "" + }, + "ReportingIssuesWarning": { + "message": "Lembre-se de ATUALIZAR a página na qual deseja substituir o texto após a instalação.", + "description": "" + }, + "ReportingIssuesInfo": { + "message": "Se a página estiver quebrada após o uso da extensão, tente atualizar a página e, em seguida, marcar as caixas Apenas campos de entrada? e Apenas alterar conteúdo visível? antes de realizar uma pesquisa e substituição.", + "description": "" + }, + "ReportingIssues_p1": { + "message": "Se você encontrar um erro, forneça um relatório detalhado na Chrome Extension Store ou no GitHub.", + "description": "" + }, + "Rate_on_store": { + "message": "Por favor, avalie com ★★★★★ na Chrome Store se a extensão lhe ajudar!", + "description": "" + }, + "no_saved_instances": { + "message": "Nenhuma instância salva", + "description": "message to tell user that no rules were found" + }, + "matches": { + "message": "correspondências", + "description": "message to tell user how many instances of the search term were found" + } +} diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 0920967..e1aade1 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -75,6 +75,10 @@ "message": "Регулярное выражение", "description": "checkbox isRegex" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "Заменить все", "description": "checkbox replaceAll" diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json index e07a9de..db30248 100644 --- a/_locales/zh_CN/messages.json +++ b/_locales/zh_CN/messages.json @@ -75,6 +75,10 @@ "message": "正则表达式", "description": "复选框 正则表达式" }, + "replaceHTML": { + "message": "Replace HTML", + "description": "checkbox replaceHTML" + }, "replaceAll": { "message": "替换所有", "description": "复选框 替换所有" diff --git a/assets/popup.html b/assets/popup.html index e5fe205..8b137fa 100644 --- a/assets/popup.html +++ b/assets/popup.html @@ -144,6 +144,12 @@ >? +
+ ? + +
{ false, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { console.log(`result`, result) - expect(result.count.original).to.equal(7) + expect(result.searchReplaceResult.count.original).to.equal(7) }) ).then(() => { console.log(`after wrap`) @@ -70,13 +70,13 @@ describe('Search Replace ', () => { true, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { - expect(result.count.original).to.equal(5) + expect(result.searchReplaceResult.count.original).to.equal(5) }) ).then(() => { console.log(`after wrap`) @@ -99,13 +99,13 @@ describe('Search Replace ', () => { false, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { - expect(result.count.original).to.equal(0) + expect(result.searchReplaceResult.count.original).to.equal(0) }) ).then(() => { console.log(`after wrap`) @@ -128,13 +128,13 @@ describe('Search Replace ', () => { false, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { - expect(result.count.original).to.equal(4) + expect(result.searchReplaceResult.count.original).to.equal(4) }) ).then(() => { console.log(`after wrap`) @@ -157,13 +157,13 @@ describe('Search Replace ', () => { true, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { - expect(result.count.original).to.equal(3) + expect(result.searchReplaceResult.count.original).to.equal(3) }) ).then(() => { console.log(`after wrap`) @@ -186,13 +186,15 @@ describe('Search Replace ', () => { false, false, false, + false, true, false, iframes, - false, ELEMENT_FILTER ).then((result) => { - expect(result.count.original - result.count.replaced).to.equal(0) + expect( + result.searchReplaceResult.count.original - result.searchReplaceResult.count.replaced + ).to.equal(0) }) ).then(() => { console.log(`after wrap`) @@ -217,11 +219,13 @@ describe('Search Replace ', () => { false, false, false, - iframes, false, + iframes, ELEMENT_FILTER ).then((result) => { - expect(result.count.original - result.count.replaced).to.equal(6) + expect( + result.searchReplaceResult.count.original - result.searchReplaceResult.count.replaced + ).to.equal(6) }) ).then(() => { console.log(`after wrap`) diff --git a/src/popup.ts b/src/popup.ts index 801efb4..8deb9e0 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -387,6 +387,7 @@ function getInputValues(replaceAll: boolean): SearchReplaceInstance { const visibleOnly = (document.getElementById('visibleOnly')).checked const wholeWord = (document.getElementById('wholeWord')).checked const isRegex = (document.getElementById('isRegex')).checked + const replaceHTML = (document.getElementById('replaceHTML')).checked const save = (document.getElementById('save')).checked const instance: SearchReplaceInstance = { searchTerm, @@ -397,6 +398,7 @@ function getInputValues(replaceAll: boolean): SearchReplaceInstance { visibleOnly, wholeWord, isRegex, + replaceHTML, replaceAll, save, }, diff --git a/src/searchreplace.ts b/src/searchreplace.ts index 54cf9c3..9ebd114 100644 --- a/src/searchreplace.ts +++ b/src/searchreplace.ts @@ -1,15 +1,15 @@ -import { ELEMENT_FILTER, INPUT_TEXTAREA_FILTER, RICH_TEXT_EDITORS } from './constants' +import { ELEMENT_FILTER, INPUT_TEXTAREA_FILTER } from './constants' import { + PartitionResult, RegexFlags, ReplaceFunctionReturnType, - RichTextEditor, SearchReplaceActions, SearchReplaceConfig, SearchReplaceContentMessage, SearchReplaceResponse, SearchReplaceResult, } from './types/index' -import { checkIframeHosts, elementIsVisible, getIframeElements, getInputElements, inIframe, isBlobIframe } from './util' +import { elementIsVisible, getIframeElements, getInputElements, inIframe, isBlobIframe } from './util' import { getFlags, getSearchPattern } from './regex' import { getHints } from './hints' @@ -111,21 +111,24 @@ function containsAncestor(element: Element, results: Map +): ReplaceFunctionReturnType { + for (const element of elements) { + const innerResult = replaceInInnerHTML(config, element, searchReplaceResult, elementsChecked) + searchReplaceResult = innerResult.searchReplaceResult + elementsChecked = innerResult.elementsChecked + if (config.replaceNext && searchReplaceResult.replaced) { + config.replace = false + } + } + return { searchReplaceResult, elementsChecked } } function replaceInnerText( @@ -154,7 +157,6 @@ function replaceInnerText( // continue if there is no node value or the node is not a text type if (!nodeValue || !(nodeType === 3)) { - // continue } @@ -169,9 +171,9 @@ function replaceInnerText( const newValue = oldValue.replace(config.searchPattern, config.replaceTerm) if (config.replace && oldValue !== newValue) { element.childNodes[0].nodeValue = newValue - const replacementCount = config.replaceAll ? occurrences : 1 + const replacementCount = config.replaceAll ? occurrences : 1 // adds one to replaced count if a replacement was made, adds occurrences if a global replace is made elementsChecked = updateResults(elementsChecked, element, true, occurrences, replacementCount) - searchReplaceResult.count.replaced += replacementCount // adds one to replaced count if a replacement was made, adds occurrences if a global replace is made + searchReplaceResult.count.replaced += replacementCount searchReplaceResult.replaced = true element.dispatchEvent(new Event('input', { bubbles: true })) if (config.replaceNext) { @@ -218,7 +220,7 @@ function getKnockoutValueChanger(id: string, newValue: string): string { ko.dataFor(${id}).valueChangedByUser = true; })()` } - +// replace in input fields function replaceInputFields( config: SearchReplaceConfig, document: Document, @@ -239,7 +241,6 @@ function replaceInputFields( function getFilteredElements(document: Document, elementFilter: RegExp) { const otherElements = document.body.getElementsByTagName('*') - const otherElementsArr: HTMLElement[] = Array.from(otherElements).filter( (el) => !el.tagName.match(elementFilter) ) as HTMLElement[] @@ -247,9 +248,7 @@ function getFilteredElements(document: Document, elementFilter: RegExp) { return otherElementsArr.filter((el) => el.tagName !== 'IFRAME' || isBlobIframe(el)) } -type PartitionResult = [(HTMLInputElement | HTMLTextAreaElement)[], HTMLElement[]] - -//Partition function +// Partition inputs and other elements function partitionElements(array: HTMLElement[]): PartitionResult { const inputs: (HTMLInputElement | HTMLTextAreaElement)[] = [] const others: HTMLElement[] = [] @@ -257,7 +256,7 @@ function partitionElements(array: HTMLElement[]): PartitionResult { return [inputs as (HTMLInputElement | HTMLTextAreaElement)[], others] } -function replaceHTML( +function replaceInHTML( config: SearchReplaceConfig, document: Document, searchReplaceResult: SearchReplaceResult, @@ -292,97 +291,38 @@ function replaceInElements( searchReplaceResult: SearchReplaceResult, elementsChecked: Map ): ReplaceFunctionReturnType { - // get unhidden, unchecked elements - - const [inputs, others] = partitionElements(elements) - - // replace inner texts first, dropping out if we have done a replacement and are not working globally - const innerTextResult = replaceInnerText(config, others, searchReplaceResult, elementsChecked) - - searchReplaceResult = innerTextResult.searchReplaceResult - elementsChecked = innerTextResult.elementsChecked - //TODO don't include iframes in counts for body!!! - - if (config.replaceNext && searchReplaceResult.replaced) { - config.replace = false - } - - // remove checked elements from inputs - - console.log( - 'CONTENT: elementsChecked with count', - Array.from(elementsChecked) - .filter((e) => e[1].count.original) - .map((e) => e[0].innerHTML) - ) - const inputsToCheck = inputs.filter((input) => !elementsChecked.has(input)) - inputsToCheck.map((input) => elementsChecked.set(input, newSearchReplaceCount())) - const inputResult = replaceInInputs(config, document, inputsToCheck, searchReplaceResult, elementsChecked) - searchReplaceResult = inputResult.searchReplaceResult - elementsChecked = inputResult.elementsChecked - - return { searchReplaceResult, elementsChecked } -} - -// Custom Functions - -async function replaceInEditorContainers( - config: SearchReplaceConfig, - richTextEditor: RichTextEditor, - containers: (Element | Document)[], - searchReplaceResult: SearchReplaceResult, - elementsChecked: Map -): Promise { - try { - // Loop to select editor elements inside their containers - for (const containerOuter of containers) { - let container = containerOuter - - if ('contentDocument' in containerOuter && containerOuter.contentDocument !== null) { - // container is an iframe use its contentDocument - container = containerOuter.contentDocument - } else if ( - richTextEditor.container && - richTextEditor.container.iframe && - 'tagName' in containerOuter && - containerOuter?.tagName !== 'IFRAME' - ) { - // container contains an iframe so use that iframe and its contentDocument - const innerIframe = containerOuter?.querySelector('iframe') - if (innerIframe !== null && innerIframe.contentDocument !== null) { - container = innerIframe.contentDocument - } - } + if (config.replaceHTML) { + const innerHTMLResult = replaceInnerHTML(config, elements, searchReplaceResult, elementsChecked) + searchReplaceResult = innerHTMLResult.searchReplaceResult + elementsChecked = innerHTMLResult.elementsChecked + } else { + const [inputs, others] = partitionElements(elements) - const editors = Array.from(container.querySelectorAll(richTextEditor.editor.value.join(',')) || []) - const editorResult = await replaceInEditors(config, editors, searchReplaceResult, elementsChecked) - searchReplaceResult = editorResult.searchReplaceResult - elementsChecked = editorResult.elementsChecked - if (config.replaceNext && editorResult.searchReplaceResult) { - config.replace = false - } - } - } catch (err) { - console.error(err) - return { searchReplaceResult, elementsChecked } - } + // replace inner texts first, dropping out if we have done a replacement and are not working globally + const innerTextResult = replaceInnerText(config, others, searchReplaceResult, elementsChecked) - return { searchReplaceResult, elementsChecked } -} + searchReplaceResult = innerTextResult.searchReplaceResult + elementsChecked = innerTextResult.elementsChecked -async function replaceInEditors( - config: SearchReplaceConfig, - editors: Element[], - searchReplaceResult: SearchReplaceResult, - elementsChecked: Map -): Promise { - for (const editor of editors) { - const innerResult = replaceInInnerHTML(config, editor as HTMLElement, searchReplaceResult, elementsChecked) - searchReplaceResult = innerResult.searchReplaceResult - elementsChecked = innerResult.elementsChecked if (config.replaceNext && searchReplaceResult.replaced) { config.replace = false } + + // remove checked elements from inputs + console.log( + 'CONTENT: elementsChecked with count', + Array.from(elementsChecked) + .filter((e) => e[1].count.original) + .map((e) => e[0].innerHTML) + ) + const inputsToCheck = inputs.filter((input) => !elementsChecked.has(input)) + inputsToCheck.map((input) => elementsChecked.set(input, newSearchReplaceCount())) + const inputResult = replaceInInputs(config, document, inputsToCheck, searchReplaceResult, elementsChecked) + searchReplaceResult = inputResult.searchReplaceResult + elementsChecked = inputResult.elementsChecked + } + if (config.replaceNext && searchReplaceResult.replaced) { + config.replace = false } return { searchReplaceResult, elementsChecked } } @@ -393,6 +333,9 @@ function replaceInInnerHTML( searchReplaceResult: SearchReplaceResult, elementsChecked: Map ): ReplaceFunctionReturnType { + if (elementsChecked.has(element)) { + return { searchReplaceResult, elementsChecked } + } // take a copy of the element except with iframes removed from within const elementCopy = element.cloneNode(true) as HTMLElement const iframes = Array.from(elementCopy.getElementsByTagName('iframe')) @@ -403,12 +346,15 @@ function replaceInInnerHTML( elementsChecked.set(element, newSearchReplaceCount()) if (occurrences) { + console.log('Occurrences in innerHTML: ', occurrences, element, elementCopy.innerHTML) + searchReplaceResult.count.original = Number(searchReplaceResult.count.original) + occurrences.length // select the content editable area element.dispatchEvent(new FocusEvent('focus', { bubbles: true })) let newValue = oldValue let selector = 'innerHTML' + // FIXME - this doesn't make sense if ('innerText' in element && element.innerText === element.innerHTML) { oldValue = getTextContent(element) newValue = oldValue @@ -440,45 +386,6 @@ function getTextContent(element: HTMLElement | Element): string { return '' } -async function replaceInCMSEditors( - config: SearchReplaceConfig, - document: Document, - searchReplaceResult: SearchReplaceResult, - elementsChecked: Map -): Promise { - // replacement functions for pages with text editors - for (const richTextEditor of RICH_TEXT_EDITORS) { - if (richTextEditor.container) { - const containers = Array.from(document.querySelectorAll(richTextEditor.container.value.join(','))) - if (containers.length) { - const containerResult = await replaceInEditorContainers( - config, - richTextEditor, - containers, - searchReplaceResult, - elementsChecked - ) - searchReplaceResult = containerResult.searchReplaceResult - elementsChecked = containerResult.elementsChecked - if (config.replaceNext && searchReplaceResult.replaced) { - config.replace = false - } - } - } else { - const editors = Array.from(document.querySelectorAll(richTextEditor.editor.value.join(','))) - const editorsResult = await replaceInEditors(config, editors, searchReplaceResult, elementsChecked) - searchReplaceResult = editorsResult.searchReplaceResult - elementsChecked = editorsResult.elementsChecked - document.body.dispatchEvent(new Event('input', { bubbles: true })) - if (config.replaceNext && searchReplaceResult.replaced) { - config.replace = false - } - } - } - - return { searchReplaceResult, elementsChecked } -} - export async function searchReplace( action: SearchReplaceActions, window: Window, @@ -489,10 +396,10 @@ export async function searchReplace( visibleOnly: boolean, wholeWord: boolean, matchCase: boolean, + replaceHTML: boolean, replaceAll: boolean, isIframe: boolean, iframes: HTMLIFrameElement[], - iframesOnDifferentHosts: boolean, elementFilter: RegExp ): Promise { const searchReplaceResult: SearchReplaceResult = { @@ -500,7 +407,6 @@ export async function searchReplace( replaced: false, } const elementsChecked = new Map() - const document = window.document const flags = getFlags(matchCase, replaceAll) // We only replace if this is true, otherwise we count the number of occurrences @@ -519,6 +425,7 @@ export async function searchReplace( flags, inputFieldsOnly, isRegex, + replaceHTML, visibleOnly, wholeWord, searchPattern, @@ -526,32 +433,19 @@ export async function searchReplace( matchCase, isIframe, iframes, - iframesOnDifferentHosts, elementFilter, usesKnockout: usesKnockout(window.document), } - // replacement functions for pages with text editors - let result = await replaceInCMSEditors(config, document, searchReplaceResult, elementsChecked) - if (config.replaceNext && result.searchReplaceResult.replaced) { - config.replace = false - } - // we check other places if text was not replaced in a text editor - - if (!result.searchReplaceResult.replaced || (config.replaceAll && result.searchReplaceResult.replaced)) { - if (inputFieldsOnly) { - result = replaceInputFields(config, document, result.searchReplaceResult, result.elementsChecked) - if (config.replaceNext && result.searchReplaceResult.replaced) { - config.replace = false - } - console.log( - 'CONTENT: searchReplaceResult after replaceInputFields', - JSON.stringify(result.searchReplaceResult) - ) - } else { - result = replaceHTML(config, document, result.searchReplaceResult, result.elementsChecked) + let result: ReplaceFunctionReturnType + if (inputFieldsOnly) { + result = replaceInputFields(config, document, searchReplaceResult, elementsChecked) + if (config.replaceNext && result.searchReplaceResult.replaced) { + config.replace = false } + } else { + result = replaceInHTML(config, document, searchReplaceResult, elementsChecked) } return result @@ -567,10 +461,6 @@ if (chrome && chrome.runtime && chrome.runtime.onMessage) { // get all iframes const iframes = getIframeElements(window.document) - // are the iframes on different hosts? - const iframeOnDifferentHosts = checkIframeHosts(iframes) - // get the element filter. If there are blob iframes then we need to include them in the search - // Setup event listeners to communicate between iframes and parent searchReplace( action, @@ -582,10 +472,10 @@ if (chrome && chrome.runtime && chrome.runtime.onMessage) { instance.options.visibleOnly, instance.options.wholeWord, instance.options.matchCase, + instance.options.replaceHTML, replaceAll, isIframe, iframes, - iframeOnDifferentHosts, ELEMENT_FILTER ).then((result) => { const response: SearchReplaceResponse = { diff --git a/src/types/types.ts b/src/types/types.ts index 3065682..ab3a607 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -4,20 +4,11 @@ export enum SearchReplaceCheckboxNames { visibleOnly = 'visibleOnly', wholeWord = 'wholeWord', isRegex = 'isRegex', + replaceHTML = 'replaceHTML', replaceAll = 'replaceAll', save = 'save', } -export enum SearchReplaceCheckboxLabels { - matchCase = 'Match case', - inputFieldsOnly = 'Input fields only', - visibleOnly = 'Visible content only', - wholeWord = 'Match whole word', - isRegex = 'Regular expression', - replaceAll = 'Replace all', - save = 'Save and apply on page reload', -} - export type SearchReplaceOptions = { [key in SearchReplaceCheckboxNames]: boolean } @@ -166,6 +157,7 @@ export type SearchReplaceConfig = { flags: string inputFieldsOnly: boolean isRegex: boolean + replaceHTML: boolean visibleOnly: boolean wholeWord: boolean searchPattern: RegExp @@ -173,21 +165,13 @@ export type SearchReplaceConfig = { matchCase: boolean isIframe: boolean iframes: HTMLIFrameElement[] - iframesOnDifferentHosts: boolean elementFilter: RegExp usesKnockout: boolean } -export type SearchReplaceLocalStorageResultKey = `searchReplace-${string}` -export type SearchReplaceLocalStorageOriginKey = `searchReplace-origin-${string}` - -export type SearchReplaceLocalStorage = { - searchTerm: string - replaceTerm: string - searchReplaceResult: SearchReplaceResult -} - export type ReplaceFunctionReturnType = { searchReplaceResult: SearchReplaceResult elementsChecked: Map } + +export type PartitionResult = [(HTMLInputElement | HTMLTextAreaElement)[], HTMLElement[]] diff --git a/src/util.ts b/src/util.ts index d852184..cadaf24 100644 --- a/src/util.ts +++ b/src/util.ts @@ -37,8 +37,6 @@ export function getInputElements( ): (HTMLInputElement | HTMLTextAreaElement)[] { const inputs = Array.from(>document.querySelectorAll('input,textarea')) const visibleElements = visibleOnly ? inputs.filter((input) => elementIsVisible(input)) : inputs - console.log('UTIL: visibleElements', visibleElements) - console.log('UTIL: elementFilter', elementFilter) return visibleElements.filter((input) => !elementFilter.has(input)) }