|
| 1 | +#AutoIt3Wrapper_UseX64=n |
| 2 | +#AutoIt3Wrapper_Run_AU3Check=Y |
| 3 | +#AutoIt3Wrapper_AU3Check_Stop_OnWarning=y |
| 4 | +#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 |
| 5 | +#Au3Stripper_Ignore_Funcs=__NetWebView2_WebEvents_*,__NetWebView2_JSEvents_* |
| 6 | + |
| 7 | +; CSV_editor.au3 |
| 8 | + |
| 9 | +#include <GUIConstantsEx.au3> |
| 10 | +#include <WindowsConstants.au3> |
| 11 | +#include <Array.au3> |
| 12 | + |
| 13 | +; Register exit function to ensure clean WebView2 shutdown |
| 14 | +OnAutoItExitRegister("_ExitApp") |
| 15 | + |
| 16 | +; Global objects |
| 17 | +Global $oWeb, $oJS |
| 18 | +Global $oMyError = ObjEvent("AutoIt.Error", "_ErrFunc") ; COM Error Handler |
| 19 | +Global $g_DebugInfo = True |
| 20 | +Global $g_sProfilePath = @ScriptDir & "\UserDataFolder" |
| 21 | +Global $hGUI |
| 22 | + |
| 23 | +Main() |
| 24 | + |
| 25 | +Func Main() |
| 26 | + ; Create GUI with resizing support |
| 27 | + $hGUI = GUICreate("WebView2AutoIt CSV_editor", 1500, 650, -1, -1, BitOR($WS_OVERLAPPEDWINDOW, $WS_CLIPCHILDREN)) |
| 28 | + GUISetBkColor(0x2B2B2B, $hGUI) |
| 29 | + |
| 30 | + ; GUI Controls for CSV interaction |
| 31 | + Local $idSaveFile = GUICtrlCreateLabel("Save CSV", 100, 10, 90, 30) |
| 32 | + GUICtrlSetFont(-1, 12, Default, $GUI_FONTUNDER, "Segoe UI") |
| 33 | + GUICtrlSetResizing(-1, $GUI_DOCKALL) |
| 34 | + GUICtrlSetColor(-1, 0x4CFF00) ; Chartreuse |
| 35 | + |
| 36 | + Local $idLoadFile = GUICtrlCreateLabel("Load CSV", 280, 10, 90, 30) |
| 37 | + GUICtrlSetFont(-1, 12, Default, $GUI_FONTUNDER, "Segoe UI") |
| 38 | + GUICtrlSetResizing(-1, $GUI_DOCKALL) |
| 39 | + GUICtrlSetColor(-1, 0x00CCFF) ; Light Blue |
| 40 | + |
| 41 | + ; Initialize WebView2 Manager and register events |
| 42 | + $oWeb = ObjCreate("NetWebView2.Manager") |
| 43 | + ObjEvent($oWeb, "WebEvents_", "IWebViewEvents") |
| 44 | + |
| 45 | + ; Important: Pass $hGUI in parentheses to maintain Pointer type for COM |
| 46 | + $oWeb.Initialize(($hGUI), $g_sProfilePath, 0, 50, 1500, 600) |
| 47 | + |
| 48 | + ; Initialize JavaScript Bridge |
| 49 | + $oJS = $oWeb.GetBridge() |
| 50 | + ObjEvent($oJS, "JavaScript_", "IBridgeEvents") |
| 51 | + |
| 52 | + ; Wait for WebView2 to be ready |
| 53 | + Do |
| 54 | + Sleep(50) |
| 55 | + Until $oWeb.IsReady |
| 56 | + |
| 57 | + ; WebView2 Configuration |
| 58 | + $oWeb.SetAutoResize(True) ; Using SetAutoResize(True) to skip WM_SIZE |
| 59 | + $oWeb.BackColor = "0x2B2B2B" |
| 60 | + $oWeb.AreDevToolsEnabled = True ; Allow F12 |
| 61 | + $oWeb.ZoomFactor = 1.2 |
| 62 | + |
| 63 | + ; Initial CSV display |
| 64 | + _Web_CSVViewer($oWeb) ; 🏆 https://stackblitz.com/edit/web-platform-3kkvy2?file=index.html |
| 65 | + |
| 66 | + GUISetState(@SW_SHOW) |
| 67 | + |
| 68 | + ; Main Application Loop |
| 69 | + While 1 |
| 70 | + Switch GUIGetMsg() |
| 71 | + Case $GUI_EVENT_CLOSE |
| 72 | + Exit |
| 73 | + |
| 74 | + Case $idSaveFile |
| 75 | + $oWeb.ExecuteScript("sendDataToAutoIt();") |
| 76 | + |
| 77 | + Case $idLoadFile |
| 78 | + Local $sFilePath = FileOpenDialog("Select CSV File", @ScriptDir, "CSV Files (*.csv;*.txt)", 1) |
| 79 | + If Not @error Then |
| 80 | + Local $sFileData = FileRead($sFilePath) |
| 81 | + If $sFileData <> "" Then |
| 82 | + _Web_CSVViewer($oWeb, $sFileData) ; Re-render CSV with new data |
| 83 | + __DW("+ Loaded CSV from: " & $sFilePath) |
| 84 | + EndIf |
| 85 | + EndIf |
| 86 | + |
| 87 | + EndSwitch |
| 88 | + WEnd |
| 89 | +EndFunc ;==>Main |
| 90 | + |
| 91 | +#Region ; === EVENT HANDLERS === |
| 92 | + |
| 93 | +; Handles native WebView2 events |
| 94 | +Func WebEvents_OnMessageReceived($sMsg) |
| 95 | + __DW("+++ [WebEvents]: " & (StringLen($sMsg) > 150 ? StringLeft($sMsg, 150) & "..." : $sMsg) & @CRLF, 0) |
| 96 | + Local $iSplitPos = StringInStr($sMsg, "|") |
| 97 | + Local $sCommand = $iSplitPos ? StringStripWS(StringLeft($sMsg, $iSplitPos - 1), 3) : $sMsg |
| 98 | + Local $sData = $iSplitPos ? StringTrimLeft($sMsg, $iSplitPos) : "" |
| 99 | + Local $aParts |
| 100 | + |
| 101 | + Switch $sCommand |
| 102 | + Case "INIT_READY" |
| 103 | + $oWeb.ExecuteScript('window.chrome.webview.postMessage(JSON.stringify({ "type": "COM_TEST", "status": "OK" }));') |
| 104 | + |
| 105 | + Case "WINDOW_RESIZED" |
| 106 | + $aParts = StringSplit($sData, "|") |
| 107 | + If $aParts[0] >= 2 Then |
| 108 | + Local $iW = Int($aParts[1]), $iH = Int($aParts[2]) |
| 109 | + ; Filter minor resize glitches |
| 110 | + If $iW > 50 And $iH > 50 Then __DW("WINDOW_RESIZED : " & $iW & "x" & $iH & @CRLF) |
| 111 | + EndIf |
| 112 | + EndSwitch |
| 113 | +EndFunc ;==>WebEvents_OnMessageReceived |
| 114 | + |
| 115 | +; Handles custom messages from JavaScript (window.chrome.webview.postMessage) |
| 116 | +Func JavaScript_OnMessageReceived($sMsg) |
| 117 | + __DW(">>> [JavaScript]: " & (StringLen($sMsg) > 150 ? StringLeft($sMsg, 150) & "..." : $sMsg) & @CRLF, 0) |
| 118 | + Local $sFirstChar = StringLeft($sMsg, 1) |
| 119 | + |
| 120 | + ; 1. JSON Messaging |
| 121 | + If $sFirstChar = "{" Or $sFirstChar = "[" Then |
| 122 | + __DW("+> : Processing JSON Messaging..." & @CRLF) |
| 123 | + Local $oJson = ObjCreate("NetJson.Parser") |
| 124 | + If Not IsObj($oJson) Then Return ConsoleWrite("!> Error: Failed to create NetJson object." & @CRLF) |
| 125 | + |
| 126 | + $oJson.Parse($sMsg) |
| 127 | + Local $sJobType = $oJson.GetTokenValue("type") |
| 128 | + |
| 129 | + Switch $sJobType |
| 130 | + Case "COM_TEST" |
| 131 | + __DW("- COM_TEST Confirmed: " & $oJson.GetTokenValue("status") & @CRLF) |
| 132 | + EndSwitch |
| 133 | + |
| 134 | + Else |
| 135 | + ; 2. Legacy / Native Pipe-Delimited Messaging |
| 136 | + __DW("+> : Legacy / Native Pipe-Delimited Messaging..." & @CRLF, 0) |
| 137 | + Local $sCommand, $sData, $iSplitPos |
| 138 | + $iSplitPos = StringInStr($sMsg, "|") - 1 |
| 139 | + |
| 140 | + If $iSplitPos < 0 Then |
| 141 | + $sCommand = StringStripWS($sMsg, 3) |
| 142 | + $sData = "" |
| 143 | + Else |
| 144 | + $sCommand = StringStripWS(StringLeft($sMsg, $iSplitPos), 3) |
| 145 | + $sData = StringTrimLeft($sMsg, $iSplitPos + 1) |
| 146 | + EndIf |
| 147 | + |
| 148 | + Switch $sCommand |
| 149 | + Case "JSON_CLICKED" |
| 150 | + Local $aClickData = StringSplit($sData, "=", 2) ; Split "Key = Value" |
| 151 | + If UBound($aClickData) >= 2 Then |
| 152 | + Local $sKey = StringStripWS($aClickData[0], 3) |
| 153 | + Local $sVal = StringStripWS($aClickData[1], 3) |
| 154 | + __DW("+++ Property: " & $sKey & " | Value: " & $sVal & @CRLF) |
| 155 | + EndIf |
| 156 | + |
| 157 | + Case "COM_TEST" |
| 158 | + __DW("- Status: Legacy COM_TEST: " & $sData & @CRLF) |
| 159 | + |
| 160 | + Case "CSV_UPDATED" |
| 161 | + ; Clean up literal \n sent by JS to real @CRLF for AutoIt |
| 162 | + Local $sCleanData = StringReplace($sData, "\n", @CRLF) |
| 163 | + |
| 164 | + ; Here you define what you want to do with the data |
| 165 | + ; E.g. Save to a file so that changes are not lost |
| 166 | + Local $hFile = FileOpen(@ScriptDir & "\updated_data.csv", 2) ; 2 = Overwrite |
| 167 | + If $hFile <> -1 Then |
| 168 | + FileWrite($hFile, $sCleanData) |
| 169 | + FileClose($hFile) |
| 170 | + __DW("- CSV saved to file successfully!") |
| 171 | + EndIf |
| 172 | + |
| 173 | + Case "ERROR" |
| 174 | + __DW("! Status: " & $sData & @CRLF) |
| 175 | + EndSwitch |
| 176 | + EndIf |
| 177 | +EndFunc ;==>JavaScript_OnMessageReceived |
| 178 | + |
| 179 | +Func WebEvents_OnContextMenuRequested($sLink, $iX, $iY, $sSelection) |
| 180 | + #forceref $sLink, $iX, $iY, $sSelection |
| 181 | +EndFunc ;==>WebEvents_OnContextMenuRequested |
| 182 | + |
| 183 | +#EndRegion ; === EVENT HANDLERS === |
| 184 | + |
| 185 | +#Region ; === UTILS === |
| 186 | + |
| 187 | +Func _Web_CSVViewer(ByRef $oWeb, $sFileData = "") |
| 188 | + Local $sSafeData = StringReplace($sFileData, "\", "\\") |
| 189 | + $sSafeData = StringReplace($sSafeData, "'", "\'") |
| 190 | + $sSafeData = StringReplace($sSafeData, @CRLF, "\n") |
| 191 | + $sSafeData = StringReplace($sSafeData, @LF, "\n") |
| 192 | + |
| 193 | + Local $sCSS = "body { background-color: #2b2b2b; color: white; font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; }" & _ |
| 194 | + ".container { width: 100%; padding: 20px; box-sizing: border-box; }" & _ |
| 195 | + "h1 { font-size: 1.5rem; margin-bottom: 20px; color: #00CCFF; text-align: center; }" & _ |
| 196 | + "table { border-collapse: collapse; width: 100%; background: #333; box-shadow: 0 4px 8px rgba(0,0,0,0.5); }" & _ |
| 197 | + "th, td { border: 1px solid #444; padding: 12px 8px; text-align: left; }" & _ |
| 198 | + "th { background-color: #444; color: #00CCFF; position: sticky; top: 0; }" & _ |
| 199 | + "tr:nth-child(even) { background-color: #383838; }" & _ |
| 200 | + "tr:hover { background-color: #4a4a4a; }" |
| 201 | + |
| 202 | + Local $sJS = "const table = document.getElementById('table');" & @CRLF & _ |
| 203 | + "function renderCSV(csvData) {" & @CRLF & _ |
| 204 | + " const rows = csvData.split(/\r?\n/);" & @CRLF & _ |
| 205 | + " let html = '';" & @CRLF & _ |
| 206 | + " rows.forEach((row, index) => {" & @CRLF & _ |
| 207 | + " if (row.trim() === '') return;" & @CRLF & _ |
| 208 | + " const cells = row.split(',');" & @CRLF & _ |
| 209 | + " html += '<tr>';" & @CRLF & _ |
| 210 | + " cells.forEach(cell => {" & @CRLF & _ |
| 211 | + " const tag = index === 0 ? 'th' : 'td';" & @CRLF & _ |
| 212 | + " const editable = index === 0 ? '' : 'contenteditable=""true""';" & @CRLF & _ |
| 213 | + " html += `<${tag} ${editable}>${cell.trim()}</${tag}>`;" & @CRLF & _ |
| 214 | + " });" & @CRLF & _ |
| 215 | + " html += '</tr>';" & @CRLF & _ |
| 216 | + " });" & @CRLF & _ |
| 217 | + " table.innerHTML = html;" & @CRLF & _ |
| 218 | + "}" & @CRLF & _ |
| 219 | + "function sendDataToAutoIt() {" & @CRLF & _ |
| 220 | + " let data = [];" & @CRLF & _ |
| 221 | + " Array.from(table.rows).forEach(row => {" & @CRLF & _ |
| 222 | + " let rowData = Array.from(row.cells).map(cell => cell.innerText.replace(/,/g, ''));" & @CRLF & _ ; Removing commas from text to avoid corrupting CSV |
| 223 | + " data.push(rowData.join(','));" & @CRLF & _ |
| 224 | + " });" & @CRLF & _ |
| 225 | + " window.chrome.webview.postMessage('CSV_UPDATED|' + data.join('\\n'));" & @CRLF & _ |
| 226 | + "}" & @CRLF & _ |
| 227 | + "if ('" & $sSafeData & "' !== '') { renderCSV('" & $sSafeData & "'); }" |
| 228 | + |
| 229 | + Local $sHTML = "<html><head><meta charset='UTF-8'><style>" & $sCSS & "</style></head><body>" & _ |
| 230 | + "<div class='container'><table id='table'></table></div>" & _ |
| 231 | + "<script>" & $sJS & "</script></body></html>" |
| 232 | + |
| 233 | + $oWeb.NavigateToString($sHTML) |
| 234 | +EndFunc ;==>_Web_CSVViewer |
| 235 | + |
| 236 | +Func _ErrFunc($oError) ; Global COM Error Handler |
| 237 | + ConsoleWrite('@@ Line(' & $oError.scriptline & ') : COM Error Number: (0x' & Hex($oError.number, 8) & ') ' & $oError.windescription & @CRLF) |
| 238 | +EndFunc ;==>_ErrFunc |
| 239 | + |
| 240 | +; Debug Write utility |
| 241 | +Func __DW($sString, $iErrorNoLineNo = 1, $iLine = @ScriptLineNumber, $iError = @error, $iExtended = @extended) |
| 242 | + If Not $g_DebugInfo Then Return SetError($iError, $iExtended, 0) |
| 243 | + Local $iReturn |
| 244 | + If $iErrorNoLineNo = 1 Then |
| 245 | + If $iError Then |
| 246 | + $iReturn = ConsoleWrite("@@(" & $iLine & ") :: @error:" & $iError & ", @extended:" & $iExtended & ", " & $sString) |
| 247 | + Else |
| 248 | + $iReturn = ConsoleWrite("+>(" & $iLine & ") :: " & $sString) |
| 249 | + EndIf |
| 250 | + Else |
| 251 | + $iReturn = ConsoleWrite($sString) |
| 252 | + EndIf |
| 253 | + Return SetError($iError, $iExtended, $iReturn) |
| 254 | +EndFunc ;==>__DW |
| 255 | + |
| 256 | +Func _NetJson_New($sInitialJson = "{}") |
| 257 | + Local $oParser = ObjCreate("NetJson.Parser") |
| 258 | + If Not IsObj($oParser) Then Return SetError(1, 0, 0) |
| 259 | + If $sInitialJson <> "" Then $oParser.Parse($sInitialJson) |
| 260 | + Return $oParser |
| 261 | +EndFunc ;==>_NetJson_New |
| 262 | + |
| 263 | +Func _ExitApp() |
| 264 | + If IsObj($oWeb) Then $oWeb.Cleanup() |
| 265 | + $oWeb = 0 |
| 266 | + $oJS = 0 |
| 267 | + Exit |
| 268 | +EndFunc ;==>_ExitApp |
| 269 | + |
| 270 | +#EndRegion ; === UTILS === |
0 commit comments