From 1d5ae452832d7174e04fb9aff6d1a4f70ffc7378 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 28 Oct 2023 22:25:07 +0900 Subject: [PATCH 01/12] WIP --- src/WinWebDiffLib/WebDiffWindow.hpp | 176 ++++++++++++++++++++++++---- 1 file changed, 154 insertions(+), 22 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 621e4ab..0f83bfd 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -122,14 +122,36 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == WebDiffEvent::NavigationCompleted) { + addEventListener(ev.pane, nullptr); *counter = *counter - 1; if (*counter == 0) Recompare(callback2.Get()); } else if (event == WebDiffEvent::WebMessageReceived) { - const int diffIndex = _wtoi(m_webWindow[i].GetWebMessage().c_str() + sizeof(L"wwdid=") / sizeof(wchar_t) - 1); - SelectDiff(diffIndex); + std::wstring msg = m_webWindow[i].GetWebMessage(); + WDocument doc; + doc.Parse(msg.c_str()); + std::wstring event = doc.HasMember(L"event") ? doc[L"event"].GetString() : L""; + if (event == L"dblclick") + { + const int diffIndex = doc[L"wwdid"].GetInt(); + if (diffIndex > -1) + SelectDiff(diffIndex); + } + else if (event == L"click") + { + const std::wstring& selector = doc[L"selector"].GetString(); + syncClick(ev.pane, selector); + } + else if (event == L"scroll") + { + const double left = doc[L"left"].GetDouble(); + const double top = doc[L"top"].GetDouble(); + const std::wstring& window = doc[L"window"].GetString(); + const std::wstring& selector = doc[L"selector"].GetString(); + syncScroll(ev.pane, window, selector, left, top); + } } for (const auto& listener : m_listeners) listener->Invoke(ev); @@ -693,40 +715,152 @@ class CWebDiffWindow : public IWebDiffWindow return hr; } - HRESULT addDblClickEventListenerLoop(IWebDiffCallback* callback, int pane = 0) + HRESULT addEventListener(int pane, IWebDiffCallback* callback) { ComPtr callback2(callback); const wchar_t* script = LR"( (function() { - const elms = document.querySelectorAll('.wwd-diff'); - if (elms) { - elms.forEach(function(el) { - el.addEventListener('dblclick', function() { - window.chrome.webview.postMessage('wwdid=' + el.dataset['wwdid']); - }); - }); + window.wdw = { }; + wdw.syncScroll = function(win, selector, left, top) { + var el = document.querySelector(selector); + if (el && wdw.getWindowLocation() === win) { + var sleft = (el.scrollWidth - el.clientWidth) * left; + var stop = (el.scrollHeight - el.clientHeight) * top; + clearTimeout(wdw.timeout); + wdw.timeout = setTimeout(function() { + el.scroll(sleft, stop); + }, 200); + } + } + wdw.getWindowLocation = function() { + let locationString = ''; + let currentWindow = window; + + while (currentWindow !== window.top) { + const frames = currentWindow.parent.frames; + let index = -1; + for (let i = 0; i < frames.length; i++) { + if (frames[i] === currentWindow) { + index = i; + break; + } + } + if (index !== -1) { + locationString = `[${index}]` + locationString; + } else { + locationString = 'top' + locationString; + } + currentWindow = currentWindow.parent; + } + + return locationString; } + function getElementSelector(element) { + if (!(element instanceof Element)) { + return null; + } + + const selectorList = []; + while (element.parentNode) { + let nodeName = element.nodeName.toLowerCase(); + if (element.id) { + selectorList.unshift(`#${element.id}`); + break; + } else { + let sibCount = 0; + let sibIndex = 0; + const siblings = element.parentNode.childNodes; + for (let i = 0; i < siblings.length; i++) { + const sibling = siblings[i]; + if (sibling.nodeType === 1) { + if (sibling === element) { + sibIndex = sibCount; + } + if (sibling.nodeName.toLowerCase() === nodeName) { + sibCount++; + } + } + } + if (sibIndex > 0) { + nodeName += `:nth-of-type(${sibIndex + 1})`; + } + selectorList.unshift(nodeName); + element = element.parentNode; + } + } + return selectorList.join(' > '); + } + window.addEventListener('click', function(e) { + var sel = getElementSelector(e.target); + var msg = { "event": "click", "selector": sel }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.addEventListener('dblclick', function(e) { + var el = e.target; + var sel = getElementSelector(el); + var wwdid = ('wwdid' in el.dataset) ? el.dataset['wwdid'] : (('wwdid' in el.parentElement.dataset) ? el.parentElement.dataset['wwdid'] : -1); + var msg = { "event": "dblclick", "selector": sel, "wwdid": parseInt(wwdid) }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.addEventListener('scroll', function(e) { + var el = ('scrollingElement' in e.target) ? e.target.scrollingElement : e.target; + var sel = getElementSelector(el); + var msg = { + "event": "scroll", + "window": wdw.getWindowLocation(), + "selector": sel, + "left": ((el.scrollWidth == el.clientWidth) ? 0 : (el.scrollLeft / (el.scrollWidth - el.clientWidth))), + "top": ((el.scrollHeight == el.clientHeight) ? 0 : (el.scrollTop / (el.scrollHeight - el.clientHeight))) + }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); })(); )"; HRESULT hr = m_webWindow[pane].ExecuteScriptInAllFrames(script, Callback([this, pane, callback2](const WebDiffCallbackResult& result) -> HRESULT { - HRESULT hr = S_OK; // result.errorCode; - if (SUCCEEDED(hr)) - { - if (pane + 1 < m_nPanes) - hr = addDblClickEventListenerLoop(callback2.Get(), pane + 1); - else if (callback2) - return callback2->Invoke({ hr, nullptr }); - } - if (FAILED(hr) && callback2) + HRESULT hr = result.errorCode; + if (callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); return hr; } + HRESULT syncScroll(int srcPane, const std::wstring& window, const std::wstring& selector, double left, double top) + { + std::wstring script = + L"wdw.syncScroll('" + window + L"', '" + selector + L"', " + + std::to_wstring(left) + L", " + std::to_wstring(top) + L");"; + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (pane == srcPane) + continue; + m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + } + return S_OK; + } + + HRESULT syncClick(int srcPane, const std::wstring& selector) + { + std::wstring script = + L"if (!('wdw' in window)) { console.log('none'); window.wdw = {}; }" + L"var el = document.querySelector('" + selector + L"');" + L"if (el) {" + L" el.click();" + L" setTimeout(function() {" + L" }, 500);" + L"}"; + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (pane == srcPane) + continue; + m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + } + return S_OK; + } + HRESULT compare(IWebDiffCallback* callback) { ComPtr callback2(callback); @@ -781,9 +915,7 @@ LR"( Callback([this, callback2](const WebDiffCallbackResult& result) -> HRESULT { HRESULT hr = result.errorCode; - if (SUCCEEDED(hr)) - hr = addDblClickEventListenerLoop(callback2.Get()); - if (FAILED(hr) && callback2) + if (callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); From 30bb18e16a49d306e8aa4eb49bb2ed3e14da42f6 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Mon, 13 Nov 2023 23:17:15 +0900 Subject: [PATCH 02/12] WIP (2) --- src/WinWebDiff/Resource.h | 18 +++---- src/WinWebDiff/WinWebDiff.cpp | 12 +++++ src/WinWebDiff/WinWebDiff.rc | Bin 15936 -> 16300 bytes src/WinWebDiffLib/WebDiffWindow.hpp | 72 +++++++++++++++++++--------- src/WinWebDiffLib/WinWebDiffLib.h | 8 ++++ 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/WinWebDiff/Resource.h b/src/WinWebDiff/Resource.h index 1bccd82..e729625 100644 --- a/src/WinWebDiff/Resource.h +++ b/src/WinWebDiff/Resource.h @@ -38,13 +38,15 @@ #define IDM_COMPARE_LASTDIFFERENCE 149 #define IDM_COMPARE_NEXTCONFLICT 150 #define IDM_COMPARE_PREVIOUSCONFLICT 151 -#define IDM_CLEAR_DISK_CACHE 161 -#define IDM_CLEAR_COOKIES 162 -#define IDM_CLEAR_BROWSING_HISTORY 163 -#define IDM_CLEAR_ALL_PROFILE 164 -#define IDI_WINWEBDIFF 170 -#define IDI_SMALL 171 -#define IDC_WINWEBDIFF 172 +#define IDM_SYNC_SCROLL 160 +#define IDM_SYNC_CLICK 161 +#define IDM_CLEAR_DISK_CACHE 171 +#define IDM_CLEAR_COOKIES 172 +#define IDM_CLEAR_BROWSING_HISTORY 173 +#define IDM_CLEAR_ALL_PROFILE 174 +#define IDI_WINWEBDIFF 180 +#define IDI_SMALL 181 +#define IDC_WINWEBDIFF 182 #define IDC_MYICON 2 #ifndef IDC_STATIC #define IDC_STATIC -1 @@ -55,7 +57,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 130 -#define _APS_NEXT_RESOURCE_VALUE 180 +#define _APS_NEXT_RESOURCE_VALUE 190 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 111 diff --git a/src/WinWebDiff/WinWebDiff.cpp b/src/WinWebDiff/WinWebDiff.cpp index 5f5f4de..da1d5d0 100644 --- a/src/WinWebDiff/WinWebDiff.cpp +++ b/src/WinWebDiff/WinWebDiff.cpp @@ -367,6 +367,8 @@ void UpdateMenuState(HWND hWnd) CheckMenuItem(hMenu, IDM_VIEW_SPLITHORIZONTALLY, m_pWebDiffWindow->GetHorizontalSplit() ? MF_CHECKED : MF_UNCHECKED); CheckMenuRadioItem(hMenu, IDM_VIEW_DIFF_ALGORITHM_MYERS, IDM_VIEW_DIFF_ALGORITHM_NONE, m_pWebDiffWindow->GetDiffOptions().diffAlgorithm + IDM_VIEW_DIFF_ALGORITHM_MYERS, MF_BYCOMMAND); + CheckMenuItem(hMenu, IDM_SYNC_SCROLL, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hMenu, IDM_SYNC_CLICK, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK) ? MF_CHECKED : MF_UNCHECKED); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -583,6 +585,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_COMPARE_PREVIOUSCONFLICT: m_pWebDiffWindow->PrevConflict(); break; + case IDM_SYNC_SCROLL: + m_pWebDiffWindow->SetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL, + !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL)); + UpdateMenuState(m_hWnd); + break; + case IDM_SYNC_CLICK: + m_pWebDiffWindow->SetSyncEventFlag(IWebDiffWindow::EVENT_CLICK, + !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK)); + UpdateMenuState(m_hWnd); + break; case IDM_CLEAR_DISK_CACHE: m_pWebDiffWindow->ClearBrowsingData(-1, IWebDiffWindow::BrowsingDataType::DISK_CACHE); break; diff --git a/src/WinWebDiff/WinWebDiff.rc b/src/WinWebDiff/WinWebDiff.rc index dd0c8ac5d5245e84927bbd3b3ba067378fb34684..d2c811af652f859d971741298b3c4191f876dee6 100644 GIT binary patch delta 140 zcmX?5v!;H-FF92;hG2$DhCGI3h75)xhI}9^lc9MgU{qdN!`f~+$^k_K=s*Rl?tkS YNGhEfd>A}|s=X%{D(Y_jCFdp&0A6MwZU6uP delta 12 TcmZ2ef1qZ=FS*TW3U2ZMESUw) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 0f83bfd..04289a1 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -141,16 +141,22 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == L"click") { - const std::wstring& selector = doc[L"selector"].GetString(); - syncClick(ev.pane, selector); + if (GetSyncEventFlag(EVENT_CLICK)) + { + const std::wstring& selector = doc[L"selector"].GetString(); + syncClick(ev.pane, selector); + } } else if (event == L"scroll") { - const double left = doc[L"left"].GetDouble(); - const double top = doc[L"top"].GetDouble(); - const std::wstring& window = doc[L"window"].GetString(); - const std::wstring& selector = doc[L"selector"].GetString(); - syncScroll(ev.pane, window, selector, left, top); + if (GetSyncEventFlag(EVENT_SCROLL)) + { + const double left = doc[L"left"].GetDouble(); + const double top = doc[L"top"].GetDouble(); + const std::wstring& window = doc[L"window"].GetString(); + const std::wstring& selector = doc[L"selector"].GetString(); + syncScroll(ev.pane, window, selector, left, top); + } } } for (const auto& listener : m_listeners) @@ -468,6 +474,19 @@ class CWebDiffWindow : public IWebDiffWindow Recompare(nullptr); } + bool GetSyncEventFlag(EventType event) const + { + return (m_eventSyncFlags & event) != 0; + } + + void SetSyncEventFlag(EventType event, bool flag) + { + if (flag) + m_eventSyncFlags = m_eventSyncFlags | static_cast(event); + else + m_eventSyncFlags = m_eventSyncFlags & ~static_cast(event); + } + int GetDiffCount() const override { return static_cast(m_diffInfos.size()); @@ -721,12 +740,12 @@ class CWebDiffWindow : public IWebDiffWindow const wchar_t* script = LR"( (function() { - window.wdw = { }; + window.wdw = {}; wdw.syncScroll = function(win, selector, left, top) { var el = document.querySelector(selector); if (el && wdw.getWindowLocation() === win) { - var sleft = (el.scrollWidth - el.clientWidth) * left; - var stop = (el.scrollHeight - el.clientHeight) * top; + var sleft = Math.round((el.scrollWidth - el.clientWidth) * left); + var stop = Math.round((el.scrollHeight - el.clientHeight) * top); clearTimeout(wdw.timeout); wdw.timeout = setTimeout(function() { el.scroll(sleft, stop); @@ -844,19 +863,23 @@ LR"( HRESULT syncClick(int srcPane, const std::wstring& selector) { - std::wstring script = - L"if (!('wdw' in window)) { console.log('none'); window.wdw = {}; }" - L"var el = document.querySelector('" + selector + L"');" - L"if (el) {" - L" el.click();" - L" setTimeout(function() {" - L" }, 500);" - L"}"; - for (int pane = 0; pane < m_nPanes; ++pane) + uint64_t now = GetTickCount64(); + if (m_lastClickEvent.selector != selector || GetTickCount64() - m_lastClickEvent.time > 200) { - if (pane == srcPane) - continue; - m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + m_lastClickEvent.selector = selector; + m_lastClickEvent.time = now; + std::wstring script = + L"if (!('wdw' in window)) { console.log('none'); window.wdw = {}; }" + L"var el = document.querySelector('" + selector + L"');" + L"if (el) {" + L" el.click();" + L"}"; + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (pane == srcPane) + continue; + m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + } } return S_OK; } @@ -1476,6 +1499,11 @@ LR"( DiffOptions m_diffOptions{}; bool m_bShowDifferences = true; bool m_bShowWordDifferences = true; + unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK; + struct LastClickEvent { + std::wstring selector; + uint64_t time; + } m_lastClickEvent; IWebDiffWindow::ColorSettings m_colorSettings = { RGB(239, 203, 5), RGB(192, 192, 192), RGB(0, 0, 0), RGB(239, 119, 116), RGB(240, 192, 192), RGB(0, 0, 0), diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index bc73c2b..ac3418c 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -55,6 +55,12 @@ struct IWebDiffWindow SETTINGS = ( 1 << 13 ), ALL_PROFILE = ( 1 << 14 ) }; + enum EventType + { + EVENT_NONE = 0, + EVENT_SCROLL = ( 1 << 0 ), + EVENT_CLICK = ( 1 << 1 ), + }; struct DiffOptions { enum DiffAlgorithm { @@ -170,6 +176,8 @@ struct IWebDiffWindow virtual bool CanRedo() = 0; virtual const DiffOptions& GetDiffOptions() const = 0; virtual void SetDiffOptions(const DiffOptions& diffOptions) = 0; + virtual bool GetSyncEventFlag(EventType event) const = 0; + virtual void SetSyncEventFlag(EventType event, bool flag) = 0; }; extern "C" From f4894409b1e475449d0d05ac2d5c4ad24bd8fa32 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Thu, 16 Nov 2023 06:52:37 +0900 Subject: [PATCH 03/12] WIP (2) --- src/WinWebDiff/Resource.h | 1 + src/WinWebDiff/WinWebDiff.cpp | 6 ++ src/WinWebDiff/WinWebDiff.rc | Bin 16300 -> 16428 bytes src/WinWebDiffLib/WebDiffWindow.hpp | 85 ++++++++++++++++++++++------ src/WinWebDiffLib/WebWindow.hpp | 26 +++++++++ src/WinWebDiffLib/WinWebDiffLib.h | 3 +- 6 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/WinWebDiff/Resource.h b/src/WinWebDiff/Resource.h index e729625..027af76 100644 --- a/src/WinWebDiff/Resource.h +++ b/src/WinWebDiff/Resource.h @@ -40,6 +40,7 @@ #define IDM_COMPARE_PREVIOUSCONFLICT 151 #define IDM_SYNC_SCROLL 160 #define IDM_SYNC_CLICK 161 +#define IDM_SYNC_INPUT 162 #define IDM_CLEAR_DISK_CACHE 171 #define IDM_CLEAR_COOKIES 172 #define IDM_CLEAR_BROWSING_HISTORY 173 diff --git a/src/WinWebDiff/WinWebDiff.cpp b/src/WinWebDiff/WinWebDiff.cpp index da1d5d0..56b6a13 100644 --- a/src/WinWebDiff/WinWebDiff.cpp +++ b/src/WinWebDiff/WinWebDiff.cpp @@ -369,6 +369,7 @@ void UpdateMenuState(HWND hWnd) m_pWebDiffWindow->GetDiffOptions().diffAlgorithm + IDM_VIEW_DIFF_ALGORITHM_MYERS, MF_BYCOMMAND); CheckMenuItem(hMenu, IDM_SYNC_SCROLL, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_CLICK, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hMenu, IDM_SYNC_INPUT, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_INPUT) ? MF_CHECKED : MF_UNCHECKED); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -595,6 +596,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK)); UpdateMenuState(m_hWnd); break; + case IDM_SYNC_INPUT: + m_pWebDiffWindow->SetSyncEventFlag(IWebDiffWindow::EVENT_INPUT, + !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_INPUT)); + UpdateMenuState(m_hWnd); + break; case IDM_CLEAR_DISK_CACHE: m_pWebDiffWindow->ClearBrowsingData(-1, IWebDiffWindow::BrowsingDataType::DISK_CACHE); break; diff --git a/src/WinWebDiff/WinWebDiff.rc b/src/WinWebDiff/WinWebDiff.rc index d2c811af652f859d971741298b3c4191f876dee6..426627770a9f07c461bc20cd7ef1ea5d8ac963bd 100644 GIT binary patch delta 59 zcmZ2ezovn4gPX$Sbv$yMo(y>m1q`JOC6g6JwI?rNXPbP0mxDi;A(Fw5!I>eR!4pUa OOrEPOy*WT3MjikV`4BAt delta 17 YcmZ3}z__M 200) + if (m_lastEvent.type != L"click" || m_lastEvent.selector != selector || GetTickCount64() - m_lastEvent.time > 200) { - m_lastClickEvent.selector = selector; - m_lastClickEvent.time = now; + m_lastEvent.type = L"click"; + m_lastEvent.selector = selector; + m_lastEvent.time = now; std::wstring script = - L"if (!('wdw' in window)) { console.log('none'); window.wdw = {}; }" - L"var el = document.querySelector('" + selector + L"');" - L"if (el) {" - L" el.click();" - L"}"; + L"wdw.syncClick('" + window + L"', '" + selector + L"');"; for (int pane = 0; pane < m_nPanes; ++pane) { if (pane == srcPane) @@ -884,6 +923,19 @@ LR"( return S_OK; } + HRESULT syncInput(int srcPane, const std::wstring& window, const std::wstring& selector, const std::wstring& value) + { + std::wstring script = + L"wdw.syncInput('" + window + L"', '" + selector + L"', " + utils::Quote(value) + L");"; + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (pane == srcPane) + continue; + m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + } + return S_OK; + } + HRESULT compare(IWebDiffCallback* callback) { ComPtr callback2(callback); @@ -1499,11 +1551,12 @@ LR"( DiffOptions m_diffOptions{}; bool m_bShowDifferences = true; bool m_bShowWordDifferences = true; - unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK; - struct LastClickEvent { + unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK | EVENT_INPUT; + struct LastEvent { + std::wstring type; std::wstring selector; uint64_t time; - } m_lastClickEvent; + } m_lastEvent; IWebDiffWindow::ColorSettings m_colorSettings = { RGB(239, 203, 5), RGB(192, 192, 192), RGB(0, 0, 0), RGB(239, 119, 116), RGB(240, 192, 192), RGB(0, 0, 0), diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index 2db4512..fefe91f 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -119,6 +119,12 @@ class CWebWindow return m_parent->OnNavigationStarting(sender, args); }).Get(), nullptr); + m_webview->add_FrameNavigationStarting( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { + return m_parent->OnFrameNavigationStarting(sender, args); + }).Get(), nullptr); + m_webview->add_HistoryChanged( Callback( [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { @@ -144,6 +150,12 @@ class CWebWindow return m_parent->OnNavigationCompleted(sender, args); }).Get(), nullptr); + m_webview->add_FrameNavigationCompleted( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { + return m_parent->OnFrameNavigationCompleted(sender, args); + }).Get(), nullptr); + m_webview->add_WebMessageReceived( Microsoft::WRL::Callback( [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) @@ -1065,6 +1077,8 @@ class CWebWindow return S_OK; } ComPtr callback2(callback); + if (*it == nullptr) + return E_FAIL; wil::com_ptr frame2 = it->try_query(); if (!frame2) @@ -1660,6 +1674,12 @@ class CWebWindow return S_OK; } + HRESULT OnFrameNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) + { + m_eventHandler(WebDiffEvent::FrameNavigationStarting); + return S_OK; + } + HRESULT OnHistoryChanged(ICoreWebView2* sender, IUnknown* args) { UpdateToolbarControls(); @@ -1697,6 +1717,12 @@ class CWebWindow return S_OK; } + HRESULT OnFrameNavigationCompleted(ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) + { + m_eventHandler(WebDiffEvent::FrameNavigationCompleted); + return S_OK; + } + HRESULT OnFrameWebMessageReceived(ICoreWebView2Frame* sender, ICoreWebView2WebMessageReceivedEventArgs* args) { wil::unique_cotaskmem_string messageRaw; diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index ac3418c..d1e2061 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -6,7 +6,7 @@ struct WebDiffEvent { - enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, WebMessageReceived, TabChanged, HSCROLL, VSCROLL }; + enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, TabChanged, HSCROLL, VSCROLL }; EVENT_TYPE type; int pane; }; @@ -60,6 +60,7 @@ struct IWebDiffWindow EVENT_NONE = 0, EVENT_SCROLL = ( 1 << 0 ), EVENT_CLICK = ( 1 << 1 ), + EVENT_INPUT = ( 1 << 2 ), }; struct DiffOptions { From 2f0c0abdc0832e285ebee5e8874500e607ac2f43 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Fri, 17 Nov 2023 07:03:10 +0900 Subject: [PATCH 04/12] WIP (4) --- src/WinWebDiffLib/WebDiffWindow.hpp | 55 ++++++++++++++++++----------- src/WinWebDiffLib/WebWindow.hpp | 21 +++++++++++ 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 149ddeb..666a05f 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -766,9 +766,9 @@ LR"( return; } window.wdw = {}; - wdw.syncScroll = function(win, selector, left, top) { + function syncScroll(win, selector, left, top) { var el = document.querySelector(selector); - if (el && wdw.getWindowLocation() === win) { + if (el && getWindowLocation() === win) { var sleft = Math.round((el.scrollWidth - el.clientWidth) * left); var stop = Math.round((el.scrollHeight - el.clientHeight) * top); clearTimeout(wdw.timeout); @@ -777,19 +777,19 @@ LR"( }, 200); } } - wdw.syncClick = function(win, selector) { + function syncClick(win, selector) { var el = document.querySelector(selector); - if (el && wdw.getWindowLocation() === win) { + if (el && getWindowLocation() === win) { el.click(); } } - wdw.syncInput = function(win, selector, value) { + function syncInput(win, selector, value) { var el = document.querySelector(selector); - if (el && wdw.getWindowLocation() === win) { + if (el && getWindowLocation() === win) { el.value = value; } } - wdw.getWindowLocation = function() { + function getWindowLocation() { let locationString = ''; let currentWindow = window; @@ -849,19 +849,19 @@ LR"( } window.addEventListener('click', function(e) { var sel = getElementSelector(e.target); - var msg = { "event": "click", "window": wdw.getWindowLocation(), "selector": sel }; + var msg = { "event": "click", "window": getWindowLocation(), "selector": sel }; window.chrome.webview.postMessage(JSON.stringify(msg)); }, true); window.addEventListener('input', function(e) { var sel = getElementSelector(e.target); - var msg = { "event": "input", "window": wdw.getWindowLocation(), "selector": sel, "value": e.target.value }; + var msg = { "event": "input", "window": getWindowLocation(), "selector": sel, "value": e.target.value }; window.chrome.webview.postMessage(JSON.stringify(msg)); }, true); window.addEventListener('dblclick', function(e) { var el = e.target; var sel = getElementSelector(el); var wwdid = ('wwdid' in el.dataset) ? el.dataset['wwdid'] : (('wwdid' in el.parentElement.dataset) ? el.parentElement.dataset['wwdid'] : -1); - var msg = { "event": "dblclick", "window": wdw.getWindowLocation(), "selector": sel, "wwdid": parseInt(wwdid) }; + var msg = { "event": "dblclick", "window": getWindowLocation(), "selector": sel, "wwdid": parseInt(wwdid) }; window.chrome.webview.postMessage(JSON.stringify(msg)); }, true); window.addEventListener('scroll', function(e) { @@ -869,13 +869,27 @@ LR"( var sel = getElementSelector(el); var msg = { "event": "scroll", - "window": wdw.getWindowLocation(), + "window": getWindowLocation(), "selector": sel, "left": ((el.scrollWidth == el.clientWidth) ? 0 : (el.scrollLeft / (el.scrollWidth - el.clientWidth))), "top": ((el.scrollHeight == el.clientHeight) ? 0 : (el.scrollTop / (el.scrollHeight - el.clientHeight))) }; window.chrome.webview.postMessage(JSON.stringify(msg)); }, true); + window.chrome.webview.addEventListener('message', function(arg) { + var data = arg.data; + switch (data.event) { + case "scroll": + syncScroll(data.window, data.selector, data.left, data.top); + break; + case "click": + syncClick(data.window, data.selector); + break; + case "input": + syncInput(data.window, data.selector, data.value); + break; + } + }); })(); )"; HRESULT hr = m_webWindow[pane].ExecuteScriptInAllFrames(script, @@ -891,14 +905,14 @@ LR"( HRESULT syncScroll(int srcPane, const std::wstring& window, const std::wstring& selector, double left, double top) { - std::wstring script = - L"wdw.syncScroll('" + window + L"', '" + selector + L"', " - + std::to_wstring(left) + L", " + std::to_wstring(top) + L");"; + std::wstring json = + L"{\"event\": \"scroll\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\", " + L"\"left\": " + std::to_wstring(left) + L", \"top\": " + std::to_wstring(top) + L"}"; for (int pane = 0; pane < m_nPanes; ++pane) { if (pane == srcPane) continue; - m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + m_webWindow[pane].PostWebMessageAsJsonInAllFrames(json.c_str()); } return S_OK; } @@ -911,13 +925,12 @@ LR"( m_lastEvent.type = L"click"; m_lastEvent.selector = selector; m_lastEvent.time = now; - std::wstring script = - L"wdw.syncClick('" + window + L"', '" + selector + L"');"; + std::wstring json = L"{\"event\": \"click\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\"}"; for (int pane = 0; pane < m_nPanes; ++pane) { if (pane == srcPane) continue; - m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + m_webWindow[pane].PostWebMessageAsJsonInAllFrames(json.c_str()); } } return S_OK; @@ -925,13 +938,13 @@ LR"( HRESULT syncInput(int srcPane, const std::wstring& window, const std::wstring& selector, const std::wstring& value) { - std::wstring script = - L"wdw.syncInput('" + window + L"', '" + selector + L"', " + utils::Quote(value) + L");"; + std::wstring json = + L"{\"event\": \"input\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\", \"value\": " + utils::Quote(value) + L"}"; for (int pane = 0; pane < m_nPanes; ++pane) { if (pane == srcPane) continue; - m_webWindow[pane].ExecuteScriptInAllFrames(script.c_str(), nullptr); + m_webWindow[pane].PostWebMessageAsJsonInAllFrames(json.c_str()); } return S_OK; } diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index fefe91f..4df2b62 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -1122,6 +1122,27 @@ class CWebWindow return hr; } + HRESULT PostWebMessageAsJsonInAllFrames(const wchar_t* json) + { + if (!GetActiveWebView()) + return E_FAIL; + auto script2 = std::make_shared(json); + HRESULT hr = GetActiveWebView()->PostWebMessageAsJson(json); + if (FAILED(hr)) + return hr; + for (auto frame : GetActiveTab()->m_frames) + { + auto frame3 = frame.try_query(); + if (frame3) + { + hr = frame3->PostWebMessageAsJson(json); + if (FAILED(hr)) + return hr; + } + } + return S_OK; + } + HRESULT setStyleSheetText(const std::wstring& styleSheetId, const std::wstring& styles, IWebDiffCallback* callback) { static const wchar_t* method = L"CSS.setStyleSheetText"; From f3d59f35f4df9cb4f18d97f4ca6e9a9fb42e2f72 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 18 Nov 2023 09:09:08 +0900 Subject: [PATCH 05/12] WIP (5) --- src/WinWebDiffLib/WebDiffWindow.hpp | 271 ++++++++++++++-------------- src/WinWebDiffLib/WebWindow.hpp | 2 + 2 files changed, 138 insertions(+), 135 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 666a05f..40077c4 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -6,6 +6,141 @@ #include #include +const wchar_t* scriptOnLoad = +LR"( +(function() { + if (window.wdw) + { + return; + } + window.wdw = {}; + function syncScroll(win, selector, left, top) { + var el = document.querySelector(selector); + if (el && getWindowLocation() === win) { + var sleft = Math.round((el.scrollWidth - el.clientWidth) * left); + var stop = Math.round((el.scrollHeight - el.clientHeight) * top); + clearTimeout(wdw.timeout); + wdw.timeout = setTimeout(function() { + el.scroll(sleft, stop); + }, 200); + } + } + function syncClick(win, selector) { + var el = document.querySelector(selector); + if (el && getWindowLocation() === win) { + el.click(); + } + } + function syncInput(win, selector, value) { + var el = document.querySelector(selector); + if (el && getWindowLocation() === win) { + el.value = value; + } + } + function getWindowLocation() { + let locationString = ''; + let currentWindow = window; + + while (currentWindow !== window.top) { + const frames = currentWindow.parent.frames; + let index = -1; + for (let i = 0; i < frames.length; i++) { + if (frames[i] === currentWindow) { + index = i; + break; + } + } + if (index !== -1) { + locationString = `[${index}]` + locationString; + } else { + locationString = 'top' + locationString; + } + currentWindow = currentWindow.parent; + } + + return locationString; + } + function getElementSelector(element) { + if (!(element instanceof Element)) { + return null; + } + + const selectorList = []; + while (element.parentNode) { + let nodeName = element.nodeName.toLowerCase(); + if (element.id) { + selectorList.unshift(`#${element.id}`); + break; + } else { + let sibCount = 0; + let sibIndex = 0; + const siblings = element.parentNode.childNodes; + for (let i = 0; i < siblings.length; i++) { + const sibling = siblings[i]; + if (sibling.nodeType === 1) { + if (sibling === element) { + sibIndex = sibCount; + } + if (sibling.nodeName.toLowerCase() === nodeName) { + sibCount++; + } + } + } + if (sibIndex > 0) { + nodeName += `:nth-of-type(${sibIndex + 1})`; + } + selectorList.unshift(nodeName); + element = element.parentNode; + } + } + return selectorList.join(' > '); + } + window.addEventListener('click', function(e) { + var sel = getElementSelector(e.target); + var msg = { "event": "click", "window": getWindowLocation(), "selector": sel }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.addEventListener('input', function(e) { + var sel = getElementSelector(e.target); + var msg = { "event": "input", "window": getWindowLocation(), "selector": sel, "value": e.target.value }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.addEventListener('dblclick', function(e) { + var el = e.target; + var sel = getElementSelector(el); + var wwdid = ('wwdid' in el.dataset) ? el.dataset['wwdid'] : (('wwdid' in el.parentElement.dataset) ? el.parentElement.dataset['wwdid'] : -1); + var msg = { "event": "dblclick", "window": getWindowLocation(), "selector": sel, "wwdid": parseInt(wwdid) }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.addEventListener('scroll', function(e) { + var el = ('scrollingElement' in e.target) ? e.target.scrollingElement : e.target; + var sel = getElementSelector(el); + var msg = { + "event": "scroll", + "window": getWindowLocation(), + "selector": sel, + "left": ((el.scrollWidth == el.clientWidth) ? 0 : (el.scrollLeft / (el.scrollWidth - el.clientWidth))), + "top": ((el.scrollHeight == el.clientHeight) ? 0 : (el.scrollTop / (el.scrollHeight - el.clientHeight))) + }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); + window.chrome.webview.addEventListener('message', function(arg) { + var data = arg.data; + switch (data.event) { + case "scroll": + syncScroll(data.window, data.selector, data.left, data.top); + break; + case "click": + syncClick(data.window, data.selector); + break; + case "input": + syncInput(data.window, data.selector, data.value); + break; + } + }); +})(); +)"; + class CWebDiffWindow : public IWebDiffWindow { public: @@ -758,141 +893,7 @@ class CWebDiffWindow : public IWebDiffWindow HRESULT addEventListener(int pane, IWebDiffCallback* callback) { ComPtr callback2(callback); - const wchar_t* script = -LR"( -(function() { - if (window.wdw) - { - return; - } - window.wdw = {}; - function syncScroll(win, selector, left, top) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - var sleft = Math.round((el.scrollWidth - el.clientWidth) * left); - var stop = Math.round((el.scrollHeight - el.clientHeight) * top); - clearTimeout(wdw.timeout); - wdw.timeout = setTimeout(function() { - el.scroll(sleft, stop); - }, 200); - } - } - function syncClick(win, selector) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - el.click(); - } - } - function syncInput(win, selector, value) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - el.value = value; - } - } - function getWindowLocation() { - let locationString = ''; - let currentWindow = window; - - while (currentWindow !== window.top) { - const frames = currentWindow.parent.frames; - let index = -1; - for (let i = 0; i < frames.length; i++) { - if (frames[i] === currentWindow) { - index = i; - break; - } - } - if (index !== -1) { - locationString = `[${index}]` + locationString; - } else { - locationString = 'top' + locationString; - } - currentWindow = currentWindow.parent; - } - - return locationString; - } - function getElementSelector(element) { - if (!(element instanceof Element)) { - return null; - } - - const selectorList = []; - while (element.parentNode) { - let nodeName = element.nodeName.toLowerCase(); - if (element.id) { - selectorList.unshift(`#${element.id}`); - break; - } else { - let sibCount = 0; - let sibIndex = 0; - const siblings = element.parentNode.childNodes; - for (let i = 0; i < siblings.length; i++) { - const sibling = siblings[i]; - if (sibling.nodeType === 1) { - if (sibling === element) { - sibIndex = sibCount; - } - if (sibling.nodeName.toLowerCase() === nodeName) { - sibCount++; - } - } - } - if (sibIndex > 0) { - nodeName += `:nth-of-type(${sibIndex + 1})`; - } - selectorList.unshift(nodeName); - element = element.parentNode; - } - } - return selectorList.join(' > '); - } - window.addEventListener('click', function(e) { - var sel = getElementSelector(e.target); - var msg = { "event": "click", "window": getWindowLocation(), "selector": sel }; - window.chrome.webview.postMessage(JSON.stringify(msg)); - }, true); - window.addEventListener('input', function(e) { - var sel = getElementSelector(e.target); - var msg = { "event": "input", "window": getWindowLocation(), "selector": sel, "value": e.target.value }; - window.chrome.webview.postMessage(JSON.stringify(msg)); - }, true); - window.addEventListener('dblclick', function(e) { - var el = e.target; - var sel = getElementSelector(el); - var wwdid = ('wwdid' in el.dataset) ? el.dataset['wwdid'] : (('wwdid' in el.parentElement.dataset) ? el.parentElement.dataset['wwdid'] : -1); - var msg = { "event": "dblclick", "window": getWindowLocation(), "selector": sel, "wwdid": parseInt(wwdid) }; - window.chrome.webview.postMessage(JSON.stringify(msg)); - }, true); - window.addEventListener('scroll', function(e) { - var el = ('scrollingElement' in e.target) ? e.target.scrollingElement : e.target; - var sel = getElementSelector(el); - var msg = { - "event": "scroll", - "window": getWindowLocation(), - "selector": sel, - "left": ((el.scrollWidth == el.clientWidth) ? 0 : (el.scrollLeft / (el.scrollWidth - el.clientWidth))), - "top": ((el.scrollHeight == el.clientHeight) ? 0 : (el.scrollTop / (el.scrollHeight - el.clientHeight))) - }; - window.chrome.webview.postMessage(JSON.stringify(msg)); - }, true); - window.chrome.webview.addEventListener('message', function(arg) { - var data = arg.data; - switch (data.event) { - case "scroll": - syncScroll(data.window, data.selector, data.left, data.top); - break; - case "click": - syncClick(data.window, data.selector); - break; - case "input": - syncInput(data.window, data.selector, data.value); - break; - } - }); -})(); -)"; - HRESULT hr = m_webWindow[pane].ExecuteScriptInAllFrames(script, + HRESULT hr = m_webWindow[pane].ExecuteScriptInAllFrames(scriptOnLoad, Callback([this, pane, callback2](const WebDiffCallbackResult& result) -> HRESULT { HRESULT hr = result.errorCode; diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index 4df2b62..cbd0889 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -163,6 +163,8 @@ class CWebWindow return m_parent->OnWebMessageReceived(sender, args); }).Get(), nullptr); + //m_webview->AddScriptToExecuteOnDocumentCreated(m_scriptOnLoad.c_str(), nullptr); + m_webview->CallDevToolsProtocolMethod(L"Page.enable", L"{}", nullptr); m_webview->CallDevToolsProtocolMethod(L"DOM.enable", L"{}", nullptr); m_webview->CallDevToolsProtocolMethod(L"CSS.enable", L"{}", nullptr); From 5cb3d5c240df1a31e3f38dff342905c2c6a1bc29 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 18 Nov 2023 12:53:35 +0900 Subject: [PATCH 06/12] WIP (6) --- src/WinWebDiffLib/WebDiffWindow.hpp | 21 ++---- src/WinWebDiffLib/WebWindow.hpp | 100 +++++++++++++++++++--------- src/WinWebDiffLib/WinWebDiffLib.h | 2 +- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 40077c4..75215ec 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -221,7 +221,7 @@ class CWebDiffWindow : public IWebDiffWindow ComPtr callback2(callback); hr = m_webWindow[i].Create(m_hInstance, m_hWnd, urls[i], userDataFolder.c_str(), m_size, m_fitToWindow, m_zoom, m_userAgent, nullptr, - [this, i, counter, callback2](WebDiffEvent::EVENT_TYPE event) + [this, i, counter, callback2](WebDiffEvent::EVENT_TYPE event, IUnknown* sender, IUnknown* args) { WebDiffEvent ev{}; ev.type = event; @@ -257,11 +257,11 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == WebDiffEvent::NavigationStarting) { - addEventListener(ev.pane, nullptr); + addEventListener(sender, ev.pane, nullptr); } else if (event == WebDiffEvent::FrameNavigationStarting) { - addEventListener(ev.pane, nullptr); + addEventListener(sender,ev.pane, nullptr); } else if (event == WebDiffEvent::NavigationCompleted) { @@ -272,7 +272,7 @@ class CWebDiffWindow : public IWebDiffWindow else if (event == WebDiffEvent::FrameNavigationCompleted) { } - else if (event == WebDiffEvent::WebMessageReceived) + else if (event == WebDiffEvent::WebMessageReceived || event == WebDiffEvent::FrameWebMessageReceived) { std::wstring msg = m_webWindow[i].GetWebMessage(); WDocument doc; @@ -890,18 +890,9 @@ class CWebDiffWindow : public IWebDiffWindow return hr; } - HRESULT addEventListener(int pane, IWebDiffCallback* callback) + HRESULT addEventListener(IUnknown* sender, int pane, IWebDiffCallback* callback) { - ComPtr callback2(callback); - HRESULT hr = m_webWindow[pane].ExecuteScriptInAllFrames(scriptOnLoad, - Callback([this, pane, callback2](const WebDiffCallbackResult& result) -> HRESULT - { - HRESULT hr = result.errorCode; - if (callback2) - return callback2->Invoke({ hr, nullptr }); - return S_OK; - }).Get()); - return hr; + return m_webWindow[pane].ExecuteScript(sender, scriptOnLoad, callback); } HRESULT syncScroll(int srcPane, const std::wstring& window, const std::wstring& selector, double left, double top) diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index cbd0889..0c22d31 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -119,12 +119,6 @@ class CWebWindow return m_parent->OnNavigationStarting(sender, args); }).Get(), nullptr); - m_webview->add_FrameNavigationStarting( - Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { - return m_parent->OnFrameNavigationStarting(sender, args); - }).Get(), nullptr); - m_webview->add_HistoryChanged( Callback( [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { @@ -150,12 +144,6 @@ class CWebWindow return m_parent->OnNavigationCompleted(sender, args); }).Get(), nullptr); - m_webview->add_FrameNavigationCompleted( - Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { - return m_parent->OnFrameNavigationCompleted(sender, args); - }).Get(), nullptr); - m_webview->add_WebMessageReceived( Microsoft::WRL::Callback( [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) @@ -207,6 +195,18 @@ class CWebWindow { return m_parent->OnFrameWebMessageReceived(sender, args); }).Get(), nullptr); + webviewFrame2->add_NavigationStarting( + Callback( + [this](ICoreWebView2Frame* sender, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { + return m_parent->OnFrameNavigationStarting(sender, args); + }).Get(), nullptr); + + webviewFrame2->add_NavigationCompleted( + Callback( + [this](ICoreWebView2Frame* sender, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { + return m_parent->OnFrameNavigationCompleted(sender, args); + }).Get(), nullptr); + } webviewFrame->add_Destroyed( @@ -271,7 +271,7 @@ class CWebWindow HRESULT Create(HINSTANCE hInstance, HWND hWndParent, const wchar_t* url, const wchar_t* userDataFolder, const SIZE& size, bool fitToWindow, double zoom, std::wstring& userAgent, - IWebDiffCallback* callback, std::function eventHandler) + IWebDiffCallback* callback, std::function eventHandler) { m_fitToWindow = fitToWindow; m_size = size; @@ -1067,6 +1067,44 @@ class CWebWindow return hr; } + HRESULT ExecuteScript(IUnknown* target, const wchar_t* script, IWebDiffCallback *callback) + { + if (!GetActiveWebView()) + return E_FAIL; + ComPtr callback2(callback); + wil::com_ptr frame; + target->QueryInterface(&frame); + if (frame) + return frame->ExecuteScript(script, + Callback( + [this, callback2](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT { + if (FAILED(errorCode)) + { + SetToolTipText(resultObjectAsJson); + ShowToolTip(true, TOOLTIP_TIMEOUT); + } + if (callback2) + return callback2->Invoke({ errorCode, resultObjectAsJson }); + return S_OK; + }).Get()); + wil::com_ptr webview; + target->QueryInterface(&webview); + if (webview) + return webview->ExecuteScript(script, + Callback( + [this, callback2](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT { + if (FAILED(errorCode)) + { + SetToolTipText(resultObjectAsJson); + ShowToolTip(true, TOOLTIP_TIMEOUT); + } + if (callback2) + return callback2->Invoke({ errorCode, resultObjectAsJson }); + return S_OK; + }).Get()); + return E_FAIL; + } + HRESULT executeScriptLoop(std::shared_ptr script, IWebDiffCallback *callback, std::vector>::iterator it) { @@ -1356,7 +1394,7 @@ class CWebWindow ResizeWebView(); CalcScrollBarRange(m_nHScrollPos, m_nVScrollPos); UpdateToolbarControls(); - m_eventHandler(WebDiffEvent::TabChanged); + m_eventHandler(WebDiffEvent::TabChanged, nullptr, nullptr); } CWebTab* GetActiveTab() const @@ -1656,7 +1694,7 @@ class CWebWindow HRESULT OnZoomFactorChanged(ICoreWebView2Controller* sender, IUnknown* args) { - m_eventHandler(WebDiffEvent::ZoomFactorChanged); + m_eventHandler(WebDiffEvent::ZoomFactorChanged, sender, args); return S_OK; } @@ -1676,7 +1714,7 @@ class CWebWindow TabCtrl_InsertItem(m_hTabCtrl, m_activeTab, &tcItem); TabCtrl_SetCurSel(m_hTabCtrl, m_activeTab); - m_eventHandler(WebDiffEvent::NewWindowRequested); + m_eventHandler(WebDiffEvent::NewWindowRequested, sender, args); return S_OK; } @@ -1686,34 +1724,34 @@ class CWebWindow int i = FindTabIndex(sender); if (i < 0) return S_OK; - m_eventHandler(WebDiffEvent::WindowCloseRequested); + m_eventHandler(WebDiffEvent::WindowCloseRequested, sender, args); return CloseTab(i); } HRESULT OnNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) { UpdateToolbarControls(); - m_eventHandler(WebDiffEvent::NavigationStarting); + m_eventHandler(WebDiffEvent::NavigationStarting, sender, args); return S_OK; } - HRESULT OnFrameNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) + HRESULT OnFrameNavigationStarting(ICoreWebView2Frame* sender, ICoreWebView2NavigationStartingEventArgs* args) { - m_eventHandler(WebDiffEvent::FrameNavigationStarting); + m_eventHandler(WebDiffEvent::FrameNavigationStarting, sender, args); return S_OK; } HRESULT OnHistoryChanged(ICoreWebView2* sender, IUnknown* args) { UpdateToolbarControls(); - m_eventHandler(WebDiffEvent::HistoryChanged); + m_eventHandler(WebDiffEvent::HistoryChanged, sender, args); return S_OK; } HRESULT OnSourceChanged(ICoreWebView2* sender, ICoreWebView2SourceChangedEventArgs* args) { UpdateToolbarControls(); - m_eventHandler(WebDiffEvent::SourceChanged); + m_eventHandler(WebDiffEvent::SourceChanged, sender, args); return S_OK; } @@ -1729,20 +1767,20 @@ class CWebWindow tcItem.pszText = title.get(); TabCtrl_SetItem(m_hTabCtrl, i, &tcItem); } - m_eventHandler(WebDiffEvent::DocumentTitleChanged); + m_eventHandler(WebDiffEvent::DocumentTitleChanged, sender, args); return S_OK; } HRESULT OnNavigationCompleted(ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) { UpdateToolbarControls(); - m_eventHandler(WebDiffEvent::NavigationCompleted); + m_eventHandler(WebDiffEvent::NavigationCompleted, sender, args); return S_OK; } - HRESULT OnFrameNavigationCompleted(ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) + HRESULT OnFrameNavigationCompleted(ICoreWebView2Frame* sender, ICoreWebView2NavigationCompletedEventArgs* args) { - m_eventHandler(WebDiffEvent::FrameNavigationCompleted); + m_eventHandler(WebDiffEvent::FrameNavigationCompleted, sender, args); return S_OK; } @@ -1751,7 +1789,7 @@ class CWebWindow wil::unique_cotaskmem_string messageRaw; args->TryGetWebMessageAsString(&messageRaw); m_webmessage = messageRaw.get(); - m_eventHandler(WebDiffEvent::WebMessageReceived); + m_eventHandler(WebDiffEvent::FrameWebMessageReceived, sender, args); return S_OK; } @@ -1760,7 +1798,7 @@ class CWebWindow wil::unique_cotaskmem_string messageRaw; args->TryGetWebMessageAsString(&messageRaw); m_webmessage = messageRaw.get(); - m_eventHandler(WebDiffEvent::WebMessageReceived); + m_eventHandler(WebDiffEvent::WebMessageReceived, sender, args); return S_OK; } @@ -1795,7 +1833,7 @@ class CWebWindow } CalcScrollBarRange(m_nHScrollPos, m_nVScrollPos); ScrollWindow(m_hWebViewParent, si.nPos - m_nHScrollPos, 0, NULL, NULL); - m_eventHandler(WebDiffEvent::HSCROLL); + m_eventHandler(WebDiffEvent::HSCROLL, nullptr, nullptr); } void OnVScroll(UINT nSBCode, UINT nPos) @@ -1822,7 +1860,7 @@ class CWebWindow } CalcScrollBarRange(m_nHScrollPos, m_nVScrollPos); ScrollWindow(m_hWebViewParent, 0, si.nPos - m_nVScrollPos, NULL, NULL); - m_eventHandler(WebDiffEvent::VSCROLL); + m_eventHandler(WebDiffEvent::VSCROLL, nullptr, nullptr); } LRESULT OnWndMsg(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) @@ -2023,7 +2061,7 @@ class CWebWindow int m_nHScrollPos = 0; SIZE m_size{ 1024, 600 }; bool m_fitToWindow = true; - std::function m_eventHandler; + std::function m_eventHandler; std::wstring m_currentUrl; std::wstring m_toolTipText = L"test"; bool m_showToolTip = false; diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index d1e2061..66eb45e 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -6,7 +6,7 @@ struct WebDiffEvent { - enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, TabChanged, HSCROLL, VSCROLL }; + enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, FrameWebMessageReceived, TabChanged, HSCROLL, VSCROLL }; EVENT_TYPE type; int pane; }; From a5c6478a5b5947d76cd8194545b5f1dac425f28e Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 18 Nov 2023 18:33:17 +0900 Subject: [PATCH 07/12] WIP (7) --- src/WinWebDiff/Resource.h | 7 ++++--- src/WinWebDiff/WinWebDiff.cpp | 5 +++++ src/WinWebDiff/WinWebDiff.rc | Bin 16428 -> 16622 bytes src/WinWebDiffLib/WebDiffWindow.hpp | 27 ++++++++++++++++++++++++--- src/WinWebDiffLib/WinWebDiffLib.h | 4 ++++ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/WinWebDiff/Resource.h b/src/WinWebDiff/Resource.h index 027af76..9c26bbf 100644 --- a/src/WinWebDiff/Resource.h +++ b/src/WinWebDiff/Resource.h @@ -38,9 +38,10 @@ #define IDM_COMPARE_LASTDIFFERENCE 149 #define IDM_COMPARE_NEXTCONFLICT 150 #define IDM_COMPARE_PREVIOUSCONFLICT 151 -#define IDM_SYNC_SCROLL 160 -#define IDM_SYNC_CLICK 161 -#define IDM_SYNC_INPUT 162 +#define IDM_SYNC_ENABLED 160 +#define IDM_SYNC_SCROLL 161 +#define IDM_SYNC_CLICK 162 +#define IDM_SYNC_INPUT 163 #define IDM_CLEAR_DISK_CACHE 171 #define IDM_CLEAR_COOKIES 172 #define IDM_CLEAR_BROWSING_HISTORY 173 diff --git a/src/WinWebDiff/WinWebDiff.cpp b/src/WinWebDiff/WinWebDiff.cpp index 56b6a13..05b050a 100644 --- a/src/WinWebDiff/WinWebDiff.cpp +++ b/src/WinWebDiff/WinWebDiff.cpp @@ -367,6 +367,7 @@ void UpdateMenuState(HWND hWnd) CheckMenuItem(hMenu, IDM_VIEW_SPLITHORIZONTALLY, m_pWebDiffWindow->GetHorizontalSplit() ? MF_CHECKED : MF_UNCHECKED); CheckMenuRadioItem(hMenu, IDM_VIEW_DIFF_ALGORITHM_MYERS, IDM_VIEW_DIFF_ALGORITHM_NONE, m_pWebDiffWindow->GetDiffOptions().diffAlgorithm + IDM_VIEW_DIFF_ALGORITHM_MYERS, MF_BYCOMMAND); + CheckMenuItem(hMenu, IDM_SYNC_ENABLED, m_pWebDiffWindow->GetSyncEvents() ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_SCROLL, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_CLICK, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_INPUT, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_INPUT) ? MF_CHECKED : MF_UNCHECKED); @@ -586,6 +587,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_COMPARE_PREVIOUSCONFLICT: m_pWebDiffWindow->PrevConflict(); break; + case IDM_SYNC_ENABLED: + m_pWebDiffWindow->SetSyncEvents(!m_pWebDiffWindow->GetSyncEvents()); + UpdateMenuState(m_hWnd); + break; case IDM_SYNC_SCROLL: m_pWebDiffWindow->SetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL, !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL)); diff --git a/src/WinWebDiff/WinWebDiff.rc b/src/WinWebDiff/WinWebDiff.rc index 426627770a9f07c461bc20cd7ef1ea5d8ac963bd..188c1cd782f79efe1d3ffd2d45fae85471b708f2 100644 GIT binary patch delta 114 zcmZ3}!1%6_al Date: Sun, 19 Nov 2023 08:58:53 +0900 Subject: [PATCH 08/12] WIP (8) --- src/WinWebDiffLib/WebDiffWindow.hpp | 199 ++++++++++++++++------------ src/WinWebDiffLib/WinWebDiffLib.h | 7 + 2 files changed, 118 insertions(+), 88 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 9d62b49..740a038 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -9,34 +9,55 @@ const wchar_t* scriptOnLoad = LR"( (function() { - if (window.wdw) - { - return; - } - window.wdw = {}; - function syncScroll(win, selector, left, top) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - var sleft = Math.round((el.scrollWidth - el.clientWidth) * left); - var stop = Math.round((el.scrollHeight - el.clientHeight) * top); + window.wdw = { "inClick": false/*, "inSubmit": false, "inKeydown": false*/ }; + function syncScroll(e) { + var el = document.querySelector(e.selector); + if (el && getWindowLocation() === e.window) { + var sleft = Math.round((el.scrollWidth - el.clientWidth) * e.left); + var stop = Math.round((el.scrollHeight - el.clientHeight) * e.top); clearTimeout(wdw.timeout); - wdw.timeout = setTimeout(function() { - el.scroll(sleft, stop); - }, 200); - } + wdw.timeout = setTimeout(function() { + if (el.scroll) + el.scroll(sleft, stop); + }, 100); + } + } + function syncClick(e) { + var el = document.querySelector(e.selector); + if (el && getWindowLocation() === e.window) { + wdw.inClick = true; + if (el.click) + el.click(); + wdw.inClick = false; + } + } + function syncInput(e) { + var el = document.querySelector(e.selector); + if (el && getWindowLocation() === e.window) { + el.value = e.value; + } } - function syncClick(win, selector) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - el.click(); +/* + function syncSubmit(e) { + var el = document.querySelector(e.selector); + if (el && getWindowLocation() === e.window) { + wdw.inSubmit = true; + if (el.submit) + el.submit(); + wdw.inSubmit = false; } } - function syncInput(win, selector, value) { - var el = document.querySelector(selector); - if (el && getWindowLocation() === win) { - el.value = value; + function syncKeydown(e) { + var el = document.querySelector(e.selector); + if (el && getWindowLocation() === e.window) { + wdw.inKeydown = true; + var ev = new KeyboardEvent("keydown", e); + if (el.dispatchEvent) + el.dispatchEvent(ev); + wdw.inKeydown = false; } } +*/ function getWindowLocation() { let locationString = ''; let currentWindow = window; @@ -96,6 +117,8 @@ LR"( return selectorList.join(' > '); } window.addEventListener('click', function(e) { + if (wdw.inClick) + return; var sel = getElementSelector(e.target); var msg = { "event": "click", "window": getWindowLocation(), "selector": sel }; window.chrome.webview.postMessage(JSON.stringify(msg)); @@ -105,6 +128,25 @@ LR"( var msg = { "event": "input", "window": getWindowLocation(), "selector": sel, "value": e.target.value }; window.chrome.webview.postMessage(JSON.stringify(msg)); }, true); +/* + var forms = document.querySelectorAll('form'); + forms.forEach(function(form) { + form.addEventListener('submit', function(e) { + if (wdw.inSubmit) + return; + var sel = getElementSelector(e.target); + var msg = { "event": "submit", "window": getWindowLocation(), "selector": sel }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }); + }, true); + window.addEventListener('keydown', function(e) { + if (wdw.inKeydown) + return; + var sel = getElementSelector(e.target); + var msg = { "event": "keydown", "window": getWindowLocation(), "selector": sel, "altKey": e.altKey, "code": e.code, "ctrlKey": e.ctrlKey, "isComposing": e.isComposing, "key": e.key, "locale": e.locale, "location": e.location, "metaKey": e.metaKey, "repeat": e.repeat, "shiftKey": e.shiftKey }; + window.chrome.webview.postMessage(JSON.stringify(msg)); + }, true); +*/ window.addEventListener('dblclick', function(e) { var el = e.target; var sel = getElementSelector(el); @@ -128,14 +170,22 @@ LR"( var data = arg.data; switch (data.event) { case "scroll": - syncScroll(data.window, data.selector, data.left, data.top); + syncScroll(data); break; case "click": - syncClick(data.window, data.selector); + syncClick(data); break; case "input": - syncInput(data.window, data.selector, data.value); + syncInput(data); + break; +/* + case "submit": + syncSubmit(data); break; + case "keydown": + syncKeydown(data); + break; +*/ } }); })(); @@ -257,20 +307,21 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == WebDiffEvent::NavigationStarting) { - addEventListener(sender, ev.pane, nullptr); + m_compareState = NOT_COMPARED; } else if (event == WebDiffEvent::FrameNavigationStarting) { - addEventListener(sender,ev.pane, nullptr); } else if (event == WebDiffEvent::NavigationCompleted) { + addEventListener(sender, ev.pane, nullptr); *counter = *counter - 1; if (*counter == 0) Recompare(callback2.Get()); } else if (event == WebDiffEvent::FrameNavigationCompleted) { + addEventListener(sender,ev.pane, nullptr); } else if (event == WebDiffEvent::WebMessageReceived || event == WebDiffEvent::FrameWebMessageReceived) { @@ -284,36 +335,33 @@ class CWebDiffWindow : public IWebDiffWindow if (diffIndex > -1) SelectDiff(diffIndex); } + else if (event == L"scroll") + { + if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_SCROLL)) + syncEvent(ev.pane, msg); + } else if (event == L"click") { if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_CLICK)) - { - const std::wstring& window = doc[L"window"].GetString(); - const std::wstring& selector = doc[L"selector"].GetString(); - syncClick(ev.pane, window, selector); - } + syncEvent(ev.pane, msg); } else if (event == L"input") { if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_INPUT)) - { - const std::wstring& window = doc[L"window"].GetString(); - const std::wstring& selector = doc[L"selector"].GetString(); - const std::wstring& value = doc[L"value"].GetString(); - syncInput(ev.pane, window, selector, value); - } + syncEvent(ev.pane, msg); } - else if (event == L"scroll") +/* + else if (event == L"submit") { - if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_SCROLL)) - { - const double left = doc[L"left"].GetDouble(); - const double top = doc[L"top"].GetDouble(); - const std::wstring& window = doc[L"window"].GetString(); - const std::wstring& selector = doc[L"selector"].GetString(); - syncScroll(ev.pane, window, selector, left, top); - } + if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_CLICK)) + syncEvent(ev.pane, msg); } + else if (event == L"keydown") + { + if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_INPUT)) + syncEvent(ev.pane, msg); + } +*/ } for (const auto& listener : m_listeners) listener->Invoke(ev); @@ -663,6 +711,11 @@ class CWebDiffWindow : public IWebDiffWindow m_eventSyncFlags = m_eventSyncFlags & ~static_cast(event); } + CompareState GetCompareState() const + { + return m_compareState; + } + int GetDiffCount() const override { return static_cast(m_diffInfos.size()); @@ -915,43 +968,8 @@ class CWebDiffWindow : public IWebDiffWindow return m_webWindow[pane].ExecuteScript(sender, scriptOnLoad, callback); } - HRESULT syncScroll(int srcPane, const std::wstring& window, const std::wstring& selector, double left, double top) - { - std::wstring json = - L"{\"event\": \"scroll\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\", " - L"\"left\": " + std::to_wstring(left) + L", \"top\": " + std::to_wstring(top) + L"}"; - for (int pane = 0; pane < m_nPanes; ++pane) - { - if (pane == srcPane) - continue; - m_webWindow[pane].PostWebMessageAsJsonInAllFrames(json.c_str()); - } - return S_OK; - } - - HRESULT syncClick(int srcPane, const std::wstring& window, const std::wstring& selector) - { - uint64_t now = GetTickCount64(); - if (m_lastEvent.type != L"click" || m_lastEvent.selector != selector || GetTickCount64() - m_lastEvent.time > 200) - { - m_lastEvent.type = L"click"; - m_lastEvent.selector = selector; - m_lastEvent.time = now; - std::wstring json = L"{\"event\": \"click\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\"}"; - for (int pane = 0; pane < m_nPanes; ++pane) - { - if (pane == srcPane) - continue; - m_webWindow[pane].PostWebMessageAsJsonInAllFrames(json.c_str()); - } - } - return S_OK; - } - - HRESULT syncInput(int srcPane, const std::wstring& window, const std::wstring& selector, const std::wstring& value) + HRESULT syncEvent(int srcPane, const std::wstring& json) { - std::wstring json = - L"{\"event\": \"input\", \"window\": \"" + window + L"\", \"selector\": \"" + selector + L"\", \"value\": " + utils::Quote(value) + L"}"; for (int pane = 0; pane < m_nPanes; ++pane) { if (pane == srcPane) @@ -963,6 +981,7 @@ class CWebDiffWindow : public IWebDiffWindow HRESULT compare(IWebDiffCallback* callback) { + m_compareState = COMPARING; ComPtr callback2(callback); std::shared_ptr> jsons(new std::vector()); HRESULT hr = getDocumentsLoop(jsons, @@ -1015,20 +1034,27 @@ class CWebDiffWindow : public IWebDiffWindow Callback([this, callback2](const WebDiffCallbackResult& result) -> HRESULT { HRESULT hr = result.errorCode; + m_compareState = FAILED(hr) ? NOT_COMPARED : COMPARED; if (callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); } + if (FAILED(hr)) + m_compareState = NOT_COMPARED; if (FAILED(hr) && callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); } + if (FAILED(hr)) + m_compareState = NOT_COMPARED; if (FAILED(hr) && callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); + if (FAILED(hr)) + m_compareState = NOT_COMPARED; return hr; } @@ -1577,12 +1603,9 @@ class CWebDiffWindow : public IWebDiffWindow bool m_bShowDifferences = true; bool m_bShowWordDifferences = true; bool m_bSynchronizeEvents = true; + bool m_bCompareCompleted = false; unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK | EVENT_INPUT; - struct LastEvent { - std::wstring type; - std::wstring selector; - uint64_t time; - } m_lastEvent; + CompareState m_compareState = NOT_COMPARED; IWebDiffWindow::ColorSettings m_colorSettings = { RGB(239, 203, 5), RGB(192, 192, 192), RGB(0, 0, 0), RGB(239, 119, 116), RGB(240, 192, 192), RGB(0, 0, 0), diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index 7cc7431..239a1bb 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -62,6 +62,12 @@ struct IWebDiffWindow EVENT_CLICK = ( 1 << 1 ), EVENT_INPUT = ( 1 << 2 ), }; + enum CompareState + { + NOT_COMPARED, + COMPARING, + COMPARED, + }; struct DiffOptions { enum DiffAlgorithm { @@ -183,6 +189,7 @@ struct IWebDiffWindow virtual void SetSyncEventFlags(unsigned flags) = 0; virtual bool GetSyncEventFlag(EventType event) const = 0; virtual void SetSyncEventFlag(EventType event, bool flag) = 0; + virtual CompareState GetCompareState() const = 0; }; extern "C" From ba7267eb68df30d1acba34d64b80ad7d4827b67a Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 19 Nov 2023 10:40:29 +0900 Subject: [PATCH 09/12] WIP (9) --- src/WinWebDiffLib/WebDiffWindow.hpp | 25 ++++++++++++++++++------- src/WinWebDiffLib/WinWebDiffLib.h | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 740a038..c6e0afc 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -307,7 +307,7 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == WebDiffEvent::NavigationStarting) { - m_compareState = NOT_COMPARED; + SetCompareState(NOT_COMPARED); } else if (event == WebDiffEvent::FrameNavigationStarting) { @@ -675,7 +675,6 @@ class CWebDiffWindow : public IWebDiffWindow void SetDiffOptions(const DiffOptions& diffOptions) override { m_diffOptions = diffOptions; - Recompare(nullptr); } bool GetSyncEvents() const @@ -716,6 +715,18 @@ class CWebDiffWindow : public IWebDiffWindow return m_compareState; } + void SetCompareState(CompareState compareState) + { + CompareState oldCompareState = m_compareState; + m_compareState = compareState; + if (m_compareState != oldCompareState) + { + WebDiffEvent ev{ WebDiffEvent::CompareStateChanged, -1 }; + for (const auto& listener : m_listeners) + listener->Invoke(ev); + } + } + int GetDiffCount() const override { return static_cast(m_diffInfos.size()); @@ -981,7 +992,7 @@ class CWebDiffWindow : public IWebDiffWindow HRESULT compare(IWebDiffCallback* callback) { - m_compareState = COMPARING; + SetCompareState(COMPARING); ComPtr callback2(callback); std::shared_ptr> jsons(new std::vector()); HRESULT hr = getDocumentsLoop(jsons, @@ -1034,27 +1045,27 @@ class CWebDiffWindow : public IWebDiffWindow Callback([this, callback2](const WebDiffCallbackResult& result) -> HRESULT { HRESULT hr = result.errorCode; - m_compareState = FAILED(hr) ? NOT_COMPARED : COMPARED; + SetCompareState(FAILED(hr) ? NOT_COMPARED : COMPARED); if (callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); } if (FAILED(hr)) - m_compareState = NOT_COMPARED; + SetCompareState(NOT_COMPARED); if (FAILED(hr) && callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); } if (FAILED(hr)) - m_compareState = NOT_COMPARED; + SetCompareState(NOT_COMPARED); if (FAILED(hr) && callback2) return callback2->Invoke({ hr, nullptr }); return S_OK; }).Get()); if (FAILED(hr)) - m_compareState = NOT_COMPARED; + SetCompareState(NOT_COMPARED); return hr; } diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index 239a1bb..d82da73 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -6,7 +6,7 @@ struct WebDiffEvent { - enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, FrameWebMessageReceived, TabChanged, HSCROLL, VSCROLL }; + enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, FrameWebMessageReceived, TabChanged, HSCROLL, VSCROLL, CompareStateChanged }; EVENT_TYPE type; int pane; }; From 355f9d43d37a1c993fd4ec6e42008a14a8d23bf8 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 19 Nov 2023 22:09:35 +0900 Subject: [PATCH 10/12] WIP (10) --- src/WinWebDiff/Resource.h | 1 + src/WinWebDiff/WinWebDiff.cpp | 1 + src/WinWebDiff/WinWebDiff.rc | Bin 16622 -> 16766 bytes src/WinWebDiffLib/WebDiffWindow.hpp | 20 +++++++++++++++++++- src/WinWebDiffLib/WebWindow.hpp | 20 ++++++++++++++++++++ src/WinWebDiffLib/WinWebDiffLib.h | 3 ++- 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/WinWebDiff/Resource.h b/src/WinWebDiff/Resource.h index 9c26bbf..2e789da 100644 --- a/src/WinWebDiff/Resource.h +++ b/src/WinWebDiff/Resource.h @@ -42,6 +42,7 @@ #define IDM_SYNC_SCROLL 161 #define IDM_SYNC_CLICK 162 #define IDM_SYNC_INPUT 163 +#define IDM_SYNC_GOBACKFORWARD 164 #define IDM_CLEAR_DISK_CACHE 171 #define IDM_CLEAR_COOKIES 172 #define IDM_CLEAR_BROWSING_HISTORY 173 diff --git a/src/WinWebDiff/WinWebDiff.cpp b/src/WinWebDiff/WinWebDiff.cpp index 05b050a..03d05d7 100644 --- a/src/WinWebDiff/WinWebDiff.cpp +++ b/src/WinWebDiff/WinWebDiff.cpp @@ -371,6 +371,7 @@ void UpdateMenuState(HWND hWnd) CheckMenuItem(hMenu, IDM_SYNC_SCROLL, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_SCROLL) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_CLICK, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_CLICK) ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(hMenu, IDM_SYNC_INPUT, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_INPUT) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hMenu, IDM_SYNC_GOBACKFORWARD, m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_GOBACKFORWARD) ? MF_CHECKED : MF_UNCHECKED); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) diff --git a/src/WinWebDiff/WinWebDiff.rc b/src/WinWebDiff/WinWebDiff.rc index 188c1cd782f79efe1d3ffd2d45fae85471b708f2..54bed9bd35029077cc348aa8fc39ae368139f15c 100644 GIT binary patch delta 86 zcmaFY$oQ{`aYKjVF l27jO$M+RpGZ=ec)h9HJ;ATMb0eH+Ee?|At(uTXT82LSi^7K#7> delta 22 ecmey@#Q3g}aYKjVHd`pU$pZj#RtTH` diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index c6e0afc..53aecb5 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -323,6 +323,24 @@ class CWebDiffWindow : public IWebDiffWindow { addEventListener(sender,ev.pane, nullptr); } + else if (event == WebDiffEvent::GoBacked) + { + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (ev.pane == pane) + continue; + m_webWindow[pane].GoBack(); + } + } + else if (event == WebDiffEvent::GoForwarded) + { + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (ev.pane == pane) + continue; + m_webWindow[pane].GoForward(); + } + } else if (event == WebDiffEvent::WebMessageReceived || event == WebDiffEvent::FrameWebMessageReceived) { std::wstring msg = m_webWindow[i].GetWebMessage(); @@ -1615,7 +1633,7 @@ class CWebDiffWindow : public IWebDiffWindow bool m_bShowWordDifferences = true; bool m_bSynchronizeEvents = true; bool m_bCompareCompleted = false; - unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK | EVENT_INPUT; + unsigned m_eventSyncFlags = EVENT_SCROLL | EVENT_CLICK | EVENT_INPUT | EVENT_GOBACKFORWARD; CompareState m_compareState = NOT_COMPARED; IWebDiffWindow::ColorSettings m_colorSettings = { RGB(239, 203, 5), RGB(192, 192, 192), RGB(0, 0, 0), diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index 0c22d31..f70097f 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -394,6 +394,20 @@ class CWebWindow return hr; } + HRESULT GoBack() + { + if (!GetActiveWebView()) + return E_FAIL; + return GetActiveWebView()->GoBack(); + } + + HRESULT GoForward() + { + if (!GetActiveWebView()) + return E_FAIL; + return GetActiveWebView()->GoForward(); + } + HRESULT Reload() { if (!GetActiveWebView()) @@ -1872,11 +1886,17 @@ class CWebWindow { case ID_GOBACK: if (GetActiveWebView()) + { GetActiveWebView()->GoBack(); + m_eventHandler(WebDiffEvent::GoBacked, nullptr, nullptr); + } break; case ID_GOFORWARD: if (GetActiveWebView()) + { GetActiveWebView()->GoForward(); + m_eventHandler(WebDiffEvent::GoForwarded, nullptr, nullptr); + } break; case ID_RELOAD: if (GetActiveWebView()) diff --git a/src/WinWebDiffLib/WinWebDiffLib.h b/src/WinWebDiffLib/WinWebDiffLib.h index d82da73..e4e29a2 100644 --- a/src/WinWebDiffLib/WinWebDiffLib.h +++ b/src/WinWebDiffLib/WinWebDiffLib.h @@ -6,7 +6,7 @@ struct WebDiffEvent { - enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, FrameWebMessageReceived, TabChanged, HSCROLL, VSCROLL, CompareStateChanged }; + enum EVENT_TYPE { ZoomFactorChanged, NewWindowRequested, WindowCloseRequested, NavigationStarting, FrameNavigationStarting, HistoryChanged, SourceChanged, DocumentTitleChanged, NavigationCompleted, FrameNavigationCompleted, WebMessageReceived, FrameWebMessageReceived, GoBacked, GoForwarded, TabChanged, HSCROLL, VSCROLL, CompareStateChanged }; EVENT_TYPE type; int pane; }; @@ -61,6 +61,7 @@ struct IWebDiffWindow EVENT_SCROLL = ( 1 << 0 ), EVENT_CLICK = ( 1 << 1 ), EVENT_INPUT = ( 1 << 2 ), + EVENT_GOBACKFORWARD = ( 1 << 3 ), }; enum CompareState { From d9b1161e55bfef2f0c36408d6248d1d8ee33052b Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 19 Nov 2023 22:21:17 +0900 Subject: [PATCH 11/12] WIP (11) --- src/WinWebDiff/WinWebDiff.cpp | 5 +++++ src/WinWebDiffLib/WebDiffWindow.hpp | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/WinWebDiff/WinWebDiff.cpp b/src/WinWebDiff/WinWebDiff.cpp index 03d05d7..8abcf9d 100644 --- a/src/WinWebDiff/WinWebDiff.cpp +++ b/src/WinWebDiff/WinWebDiff.cpp @@ -607,6 +607,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_INPUT)); UpdateMenuState(m_hWnd); break; + case IDM_SYNC_GOBACKFORWARD: + m_pWebDiffWindow->SetSyncEventFlag(IWebDiffWindow::EVENT_GOBACKFORWARD, + !m_pWebDiffWindow->GetSyncEventFlag(IWebDiffWindow::EVENT_GOBACKFORWARD)); + UpdateMenuState(m_hWnd); + break; case IDM_CLEAR_DISK_CACHE: m_pWebDiffWindow->ClearBrowsingData(-1, IWebDiffWindow::BrowsingDataType::DISK_CACHE); break; diff --git a/src/WinWebDiffLib/WebDiffWindow.hpp b/src/WinWebDiffLib/WebDiffWindow.hpp index 53aecb5..fb66bfb 100644 --- a/src/WinWebDiffLib/WebDiffWindow.hpp +++ b/src/WinWebDiffLib/WebDiffWindow.hpp @@ -325,20 +325,26 @@ class CWebDiffWindow : public IWebDiffWindow } else if (event == WebDiffEvent::GoBacked) { - for (int pane = 0; pane < m_nPanes; ++pane) + if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_GOBACKFORWARD)) { - if (ev.pane == pane) - continue; - m_webWindow[pane].GoBack(); + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (ev.pane == pane) + continue; + m_webWindow[pane].GoBack(); + } } } else if (event == WebDiffEvent::GoForwarded) { - for (int pane = 0; pane < m_nPanes; ++pane) + if (m_bSynchronizeEvents && GetSyncEventFlag(EVENT_GOBACKFORWARD)) { - if (ev.pane == pane) - continue; - m_webWindow[pane].GoForward(); + for (int pane = 0; pane < m_nPanes; ++pane) + { + if (ev.pane == pane) + continue; + m_webWindow[pane].GoForward(); + } } } else if (event == WebDiffEvent::WebMessageReceived || event == WebDiffEvent::FrameWebMessageReceived) From 10ee2c70978786c2a51d036a3b13dd3f744667dc Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sun, 19 Nov 2023 23:14:02 +0900 Subject: [PATCH 12/12] WIP (12) --- src/WinWebDiffLib/WebWindow.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/WinWebDiffLib/WebWindow.hpp b/src/WinWebDiffLib/WebWindow.hpp index f70097f..1e545c9 100644 --- a/src/WinWebDiffLib/WebWindow.hpp +++ b/src/WinWebDiffLib/WebWindow.hpp @@ -151,8 +151,6 @@ class CWebWindow return m_parent->OnWebMessageReceived(sender, args); }).Get(), nullptr); - //m_webview->AddScriptToExecuteOnDocumentCreated(m_scriptOnLoad.c_str(), nullptr); - m_webview->CallDevToolsProtocolMethod(L"Page.enable", L"{}", nullptr); m_webview->CallDevToolsProtocolMethod(L"DOM.enable", L"{}", nullptr); m_webview->CallDevToolsProtocolMethod(L"CSS.enable", L"{}", nullptr);