diff --git a/src/cypress/e2e/limeSurvey.cy.ts b/src/cypress/e2e/limeSurvey.cy.ts new file mode 100644 index 0000000..e604457 --- /dev/null +++ b/src/cypress/e2e/limeSurvey.cy.ts @@ -0,0 +1,94 @@ +/// + +import { ELEMENT_FILTER } from '../../constants' +import { isBlobIframe } from '../../elements' +import { searchReplace } from '../../searchreplace' + +const SEARCHTERM = 'Phone Type:' +const REPLACETERM = 'The replacement' +const BASEURL = 'http://localhost:9000' +describe('Search Replace LimeSurvey', { baseUrl: BASEURL, responseTimeout: 120e3 }, () => { + beforeEach(() => { + cy.visit('http://localhost:9000/tests/limeSurvey/test.html') + }) + + it('counts the correct number of occurrences', () => { + cy.window().then((window) => { + console.log(window.location.host) + const iframes = Array.from( + >window.document.querySelectorAll('iframe') + ).filter((iframe) => !isBlobIframe(iframe)) + cy.wrap( + searchReplace( + 'count', + window, + SEARCHTERM, + REPLACETERM, + false, + false, + true, + false, + false, + false, + true, + false, + iframes, + ELEMENT_FILTER + ).then((result) => { + console.log(`result`, result) + expect(result.searchReplaceResult.count.original).to.equal(2) + }) + ).then(() => { + console.log('done') + }) + }) + }) + it('replaces the search term and then replaces it again', () => { + cy.window().then((window) => { + console.log(window.location.host) + const iframes = Array.from( + >window.document.querySelectorAll('iframe') + ).filter((iframe) => !isBlobIframe(iframe)) + cy.wrap( + searchReplace( + 'searchReplace', + window, + SEARCHTERM, + REPLACETERM, + false, + false, + true, + false, + false, + false, + true, + false, + iframes, + ELEMENT_FILTER + ).then((result1) => { + expect(result1.searchReplaceResult.count.replaced).to.equal(2) + searchReplace( + 'searchReplace', + window, + REPLACETERM, + SEARCHTERM, + false, + false, + true, + false, + false, + false, + true, + false, + iframes, + ELEMENT_FILTER + ).then((result2) => { + expect(result2.searchReplaceResult.count.replaced).to.equal(2) + }) + }) + ).then(() => { + console.log('done') + }) + }) + }) +}) diff --git a/src/elements.ts b/src/elements.ts index e621f65..b948066 100644 --- a/src/elements.ts +++ b/src/elements.ts @@ -40,8 +40,9 @@ export function containsPartialClass(element: Element, partialClass: string) { } export function getLocalIframes(window: Window, document: Document): HTMLIFrameElement[] { + console.log('iframes', document.querySelectorAll('iframe')) return Array.from(>document.querySelectorAll('iframe')).filter((iframe) => { - return iframe.src === '' || iframe.src === 'about:blank' || iframe.src === window.location.href + return iframe.src === '' || iframe.src === 'about:blank' || iframe.srcdoc || iframe.src === window.location.href }) } @@ -72,6 +73,8 @@ export const waitForIframeLoad = async (iframe: HTMLIFrameElement): Promise, element: Ele return false } +function replaceInSrcDocIframe( + config: SearchReplaceConfig, + iframe: HTMLIFrameElement, + searchReplaceResult: SearchReplaceResult, + elementsChecked: Map +): ReplaceFunctionReturnType { + const occurrences = countOccurrences(iframe, config) + console.log("occurrences in iframe's srcdoc", occurrences) + elementsChecked = updateResults(elementsChecked, iframe, false, occurrences, 0) + searchReplaceResult.count.original = searchReplaceResult.count.original + occurrences + if (config.replace && occurrences) { + iframe.srcdoc = iframe.srcdoc.replace(config.searchPattern, config.replaceTerm) + console.log('adding', config.replaceAll ? occurrences : 1, 'to replaced count') + searchReplaceResult.count.replaced += config.replaceAll ? occurrences : 1 + } + return { searchReplaceResult, elementsChecked } +} + function replaceInHTML( config: SearchReplaceConfig, document: Document, @@ -535,7 +556,6 @@ function replaceInHTML( elementsChecked: Map ): ReplaceFunctionReturnType { for (const [originalIndex, originalElement] of originalElements.entries()) { - console.log('replacing in element', originalElement) let clonedElement = originalElement.cloneNode(true) as HTMLElement const { clonedElementRemoved, removedSet } = copyElementAndRemoveSelectedElements( @@ -544,9 +564,11 @@ function replaceInHTML( // - match the element filter, but are not blob iframes, nor are WYSIWYG iframes. // Removes SCRIPT, STYLE, IFRAME, etc. // - match the input filter, as these are handled later + // - are already in the elementsChecked map (el: HTMLElement) => (!!el.nodeName.match(config.elementFilter) && !isBlobIframe(el) && !isWYSIWYGEditorIframe(el)) || - isInputElement(el), + isInputElement(el) || + elementsChecked.has(el), false ) clonedElement = clonedElementRemoved as HTMLElement @@ -671,7 +693,7 @@ export async function searchReplace( shadowRoots, } // we check other places if text was not replaced in a text editor - let result: ReplaceFunctionReturnType + let result: ReplaceFunctionReturnType = { searchReplaceResult, elementsChecked } if (inputFieldsOnly) { result = replaceInputFields(config, document, searchReplaceResult, elementsChecked) if (config.replaceNext && result.searchReplaceResult.replaced) { @@ -680,17 +702,27 @@ export async function searchReplace( } else { const startingElement = document.body || document.querySelector('div') - const searchableIframes = (await getSearchableIframes(window, document)) - .map(getInitialIframeElement) - .filter(notEmpty) - console.log('searchable iframes', searchableIframes) - result = replaceInHTML( - config, - document, - [startingElement, ...searchableIframes], - searchReplaceResult, - elementsChecked - ) + const searchableIframesInitial = await getSearchableIframes(window, document) + const srcDocIframes = searchableIframesInitial.filter((iframe) => iframe.hasAttribute('srcdoc')) + srcDocIframes.map((iframe) => { + const srcDocResult = replaceInSrcDocIframe( + config, + iframe, + result.searchReplaceResult, + result.elementsChecked + ) + result.searchReplaceResult = srcDocResult.searchReplaceResult + result.elementsChecked = srcDocResult.elementsChecked + }) + console.log(JSON.stringify(result.searchReplaceResult)) + console.log('searchableIframesInitial', searchableIframesInitial) + const searchableIframes = searchableIframesInitial.filter((iframe: HTMLIFrameElement) => { + return iframe.srcdoc === '' || iframe.srcdoc === undefined + }) + const searchable = searchableIframes.map(getInitialIframeElement).filter(notEmpty) + console.log('searchableIframes', searchableIframes) + console.log('searchable', searchable) + result = replaceInHTML(config, document, [startingElement, ...searchable], searchReplaceResult, elementsChecked) } return result diff --git a/tests/limeSurvey/test.html b/tests/limeSurvey/test.html new file mode 100644 index 0000000..d52198e --- /dev/null +++ b/tests/limeSurvey/test.html @@ -0,0 +1,507 @@ + + + + + + + + + + +Training + + + + + + + + + Toggle navigation + + + + + + Training + + + + + + + + + + + + + National Opinion Survey TEST(ID:313145) + + + + + + + + + + + + + + + + + Preview survey + + + + + + + + + + + Preview question group + + + + + + + + + + + Preview question + + + + + + + + + + + + + + + Save + + + + + Save and close + + + + + Close + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + National Opinion Survey TEST + + + + Precodes + + + + pPhoneType + + + Edit question + + +×Your browser screen size is too small to use the administration properly. The minimum size required is 1280*1024 px. + + + Edit question: pPhoneType (ID:1698525) + + + + + + + + + + + English (Base language) + + + + + Spanish + + + + + + + + Code: + + Required + + + + + Question: + + + Phone Type:Rich Text Editor, question_enEditor toolbars Maximize Placeholder fields Cut Copy Paste Paste as plain text Paste from Word Undo Redo Find Replace Select All Remove Format Source Image Video Embed YouTube Video Flash Table Insert Horizontal Line Smiley Insert Special Character Bold Italic Underline Strikethrough Subscript Superscript Insert/Remove Numbered List Insert/Remove Bulleted List Decrease Indent Increase Indent Block Quote Create Div Container Align Left Center Align Right Justify Text direction from left to right Text direction from right to left Show Blocks Templates Link UnlinkStylesStylesFormatFormatFontFontSizeSize Anchor IFrame Text Color Background ColorPress ALT 0 for help◢Elements pathbody + + + + + Help: + + + Rich Text Editor, help_enEditor toolbars Maximize Placeholder fields Cut Copy Paste Paste as plain text Paste from Word Undo Redo Find Replace Select All Remove Format Source Image Video Embed YouTube Video Flash Table Insert Horizontal Line Smiley Insert Special Character Bold Italic Underline Strikethrough Subscript Superscript Insert/Remove Numbered List Insert/Remove Bulleted List Decrease Indent Increase Indent Block Quote Create Div Container Align Left Center Align Right Justify Text direction from left to right Text direction from right to left Show Blocks Templates Link UnlinkStylesStylesFormatFormatFontFontSizeSize Anchor IFrame Text Color Background ColorPress ALT 0 for help◢Elements path + + + + + + + + + + + + + + + + + + + + + + + Save + + + + + + + + + + + + + + + + + + + General options + + + + + + + + Question type: + + + + + List (Radio) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Question group: + + + Precodes (ID:79382) +ZipThingy (ID:79385) +Group 1 (ID:79381) +ArrQ5to13 (ID:79383) +AfterArrQ6to14 (ID:79384) + + + + + Option 'Other': + + On Off + + + Mandatory: + + + On Off + + + Relevance equation: + + 1 + + + + + + + + + + + + + + + + + + + Advanced settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Save + + + + + + + + + + + + + + + + + + + + \ No newline at end of file
Save + + +