I probably need to restructure my initializeApp() function into a class as I am using many nested functions. But I am having a problem with the populateContents() function. It calls store.getSnippetContent() and passes an id and a callback. The callback passes data to the nested function testFunc(). This nested function is supposed to set a key:value on the super-global variable localSnippets. I am confirming via debugging and MsgBox's that both the params in the nested function are correct. The problem is that it doesn't appear that localSnippets is actually getting updated. Also, my MsgBox inside of testFunc() doesn't show where it is currently. If I move it up a line, then it works and shows 0.
I am probably just misunderstanding nested functions and closures limitations in AHK.
EDIT: I attached the two includes. This should work for anyone that has a gitlab account on gitlab.com if you insert the proper root URL and access token.
Code: Select all
#Persistent
#SingleInstance Force
#Include <JSON>
#Include <Class_Toolbar>
OnExit("cleanup")
global localSnippets := loadLocalSnippets() || {}
global store := new GitLab("<token>")
store.getAllSnippets(Func("initializeApp"))
global snippetSelectionGui := new localSnippetsGui()
HotKey("#H", () => snippetSelectionGui.toggleGui())
Return
initializeApp(data) {
global localSnippets
initialHTML := "about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible' content='IE=EDGE'>"
IL := IL_Create(1, 1)
IL_Add(IL, "shell32.dll", 239)
IL_Add(IL, "imageres.dll", 233)
snippetsGui := GuiCreate("", "Public Snippets")
snippetsGui.MarginX := snippetsGui.MarginY := 10
;snippetsGui.OnEvent("Close", () => snippetsGui.Destroy())
snippetsTB := snippetsGui.Add("Custom", "w800 h15 ClassToolbarWindow32 0x0800 0x0100 0x0040")
snippetsLV := snippetsGui.Add("ListView", "xs w" 400 - snippetsGui.MarginX // 2 " h200 Section vSnippet +Checked", "Title|Author|Last Updated")
snippetsLV.OnEvent("ItemSelect", "updateSnippetContents")
snippetsLV.OnEvent("ItemCheck", "populateContents")
for i, snippet in data {
tempDate := StrSplit(RegExReplace(snippet.updated_at, "-|:"), "T")
displayDateTime := FormatTime(tempDate[1] . SubStr(tempDate[2], 1, 6), "MM/dd/yyyy HH:mm")
snippetsLV.Add(localSnippets[snippet.id] && "Check", snippet.title, snippet.author.name, displayDateTime)
LV_SetItemParam(snippetsLV.hwnd, i, snippet.id)
}
snippetsLV.ModifyCol()
;snippetsGui.Add("Edit", "ys w" 400 - snippetsGui.MarginX // 2 " h200 vDescription")
wbDescription := snippetsGui.Add("ActiveX", "ys w" 400 - snippetsGui.MarginX // 2 " h200 +VScroll +Border", initialHTML "<script src='https://cdn.rawgit.com/showdownjs/showdown/1.8.6/dist/showdown.min.js'></script><script>showdown.setFlavor('github');</script><style>body {font-family: 'Segoe UI';font-size: 14px; margin: 0; padding: 5px;} body > * {margin: 0; padding: 0;}</style>").value
;snippetsGui.Add("Edit", "w800 h400 vContents")
wbContent := snippetsGui.Add("ActiveX", "xs w800 h400 +VScroll +Border", initialHTML "<style>body {margin: 0 !important;} .gitlab-embed-snippets {margin: 0 !important;}</style>").value
snippetsGui.Show("Hide")
snippetsTBWrapper := new ToolBar(snippetsTB.hwnd)
snippetsTBWrapper.SetImageList(IL)
snippetsTBWrapper.SetPadding(15, 15)
snippetsTBWrapper.SetMaxTextRows(0)
btns := []
btns.push({ id: 1, label: "Reconfigure Snippets", image: 1, callback: () => refreshLocalSnippets(snippetsLV)})
btns.push("")
btns.push({ id: 2, label: "Exit program", image: 2, callback: () => ExitApp()})
ret := snippetsTBWrapper.Add("Enabled", btns*)
;ret := snippetsTBWrapper.Add()
HotKey("#F12", () => WinExist("ahk_id" snippetsGui.hwnd) ? snippetsGui.Hide() : snippetsGui.Show())
; Set a function to monitor the Toolbar's messages.
WM_COMMAND := 0x111
OnMessage(WM_COMMAND, "TB_Messages")
; Set a function to monitor notifications.
WM_NOTIFY := 0x4E
OnMessage(WM_NOTIFY, "TB_Notify")
TB_Messages(w, l) {
if (l = snippetsTB.hwnd) {
snippetsTBWrapper.OnMessage(w)
}
}
TB_Notify(w, l) {
code := snippetsTBWrapper.OnNotify(l, MX, MY, label, id)
}
refreshLocalSnippets(ctrl) {
rowNum := 0, newLocalSnippets := {}
while(rowNum := ctrl.GetNext(rowNum, "Checked")) {
id := LV_GetItemParam(ctrl.hwnd, rowNum)
for key, snippet in data {
if (snippet.id = id) {
newLocalSnippets[id] := { title: snippet.title }
}
}
}
localSnippets := newLocalSnippets
snippetSelectionGui.updateSnippets()
}
updateSnippetContents(ctrl, row, selected) {
if (selected) {
id := LV_GetItemParam(ctrl.hwnd, row)
store.getSnippetContents(id, (data) => showSnippet(snippetsGui, data))
}
}
populateContents(ctrl, row, checked) {
id := LV_GetItemParam(ctrl.hwnd, row)
if (checked) {
store.getSnippetContents(id, (snippetData) => testFunc(id, snippetData.content)) ; localSnippets[index].content := data.content)
}
;else {
;localSnippets.Delete(id)
;}
}
testFunc(id, content) {
localSnippets[id].content := content
MsgBox(localSnippets.Count()) ; localSnippets[5].content "'")
}
showSnippet(gui, data) {
;gui.control["description"].value := data.description
wbDescription.document.parentWindow.execScript("document.body.innerHTML = new showdown.Converter().makeHtml('" StrReplace(data.description, "`r`n", "\r\n") "');")
wbContent.document.head.innerHTML := wbContent.document.body.innerHTML := ""
wbContent.document.write("<script src='" data.web_url ".js'></script>")
}
}
class localSnippetsGui {
__New() {
this.gui := GuiCreate("+ToolWindow -Caption +AlwaysOnTop", "Pick a Snippet to insert")
this.gui.MarginX := this.gui.MarginY := 0
this.gui.OnEvent("Escape", () => this.toggleGui())
newOpts := []
for id, snippet in localSnippets {
newOpts.push(snippet.title)
}
ddl := this.gui.Add("DropDownList", "w200 vSnippet", newOpts)
this.guiSize := { w: ddl.pos.w, h: ddl.pos.h }
submitButton := this.gui.Add("Button", "Default", "Submit")
submitButton.OnEvent("click", () => this.submitGui())
}
toggleGui() {
if (WinExist("ahk_id " this.gui.hwnd)) {
this.gui.hide()
}
else {
this.gui.show("w" this.guiSize.w " h" this.guiSize.h)
}
}
submitGui() {
data := this.gui.Submit()
for id, snippet in localSnippets {
if (snippet.title = data.Snippet) {
oldClip := ClipboardAll()
Clipboard := snippet.content
SendInput("{Ctrl Down}v{Ctrl Up}")
Sleep(50)
Clipboard := oldClip, oldClip := ""
break
}
}
}
updateSnippets() {
newOpts := []
for id, snippet in localSnippets {
newOpts.push(snippet.title)
}
this.gui.control["Snippet"].Delete()
this.gui.control["Snippet"].Add(newOpts)
}
}
class GitLab {
__New(token) {
this.rootURL := "<url>"
this.token := token
this.xhr := ComObjCreate("Msxml2.XMLHTTP")
}
__Delete() {
this.xhr := ""
}
handleStatusChange(callback) {
if (this.xhr.readyState == 4 && this.xhr.status == 200) {
callback.call(JSON.load(this.xhr.responseText))
}
}
getAllSnippets(callback) {
this.xhr.open("GET", this.rootURL "/snippets/public")
this.xhr.SetRequestHeader("PRIVATE-TOKEN", this.token)
this.xhr.onreadystatechange := () => this.handleStatusChange(callback)
this.xhr.send()
}
getSnippetContents(id, callback) {
this.xhr.open("GET", this.rootURL "/snippets/" id)
this.xhr.SetRequestHeader("PRIVATE-TOKEN", this.token)
this.xhr.onreadystatechange := () => this.handleStatusChange((data) => this.populateSnippetContent(data, callback))
this.xhr.send()
}
populateSnippetContent(data, callback) {
this.xhr.open("GET", data.raw_url, false)
this.xhr.SetRequestHeader("PRIVATE-TOKEN", this.token)
;this.xhr.onreadystatechange := () => this.handleStatusChange(callback)
this.xhr.send()
data.content := this.xhr.responseText
callback.call(data)
}
}
; ======================================================================================================================
; LV_GetItemParam - Retrieves the value of the item's lParam field.
; ======================================================================================================================
LV_GetItemParam(HLV, Row) {
; LVM_GETITEM -> http://msdn.microsoft.com/en-us/library/bb774953(v=vs.85).aspx
Static LVM_GETITEM := 0x104B ; LVM_GETITEMW
Static OffParam := 24 + (A_PtrSize * 2)
LV_LVITEM(LVITEM, 0x00000004, Row) ; LVIF_PARAM
SendMessage(LVM_GETITEM, 0, &LVITEM, "", "ahk_id " . HLV)
Return NumGet(LVITEM, OffParam, "UPtr")
}
; ======================================================================================================================
; LV_SetItemParam - Sets the lParam field of the item to the specified value.
; ======================================================================================================================
LV_SetItemParam(HLV, Row, Value) {
; LVM_SETITEMA -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
Static LVM_SETITEM := 0x104C
Static OffParam := 24 + (A_PtrSize * 2)
LV_LVITEM(LVITEM, 0x00000004, Row) ; LVIF_PARAM
NumPut(Value, LVITEM, OffParam, "UPtr")
Return SendMessage(0x1006, 0, &LVITEM, "", "ahk_id " . HLV)
;Return ErrorLevel
}
LV_LVITEM(ByRef LVITEM, Mask := 0, Row := 1, Col := 1) {
Static LVITEMSize := 48 + (A_PtrSize * 3)
VarSetCapacity(LVITEM, LVITEMSize, 0)
NumPut(Mask, LVITEM, 0, "UInt"), NumPut(Row - 1, LVITEM, 4, "Int"), NumPut(Col - 1, LVITEM, 8, "Int")
}
cleanup() {
FileDelete("G-snips.json")
FileAppend(JSON.Dump(localSnippets), "G-snips.json")
}
loadLocalSnippets() {
return JSON.Load(FileRead("G-snips.json"))
}