Basically, since Neutron creates a COM instance of the Trident control, you can use those functions. Here I callNeutron.wnd.execScript("TestMe()") in the code for Button #1. See line 19 of 'Simple2.html'.
If you look at the Neutron.ahk code you'll see 'Neutron.wnd' is equivalent, if you consider 'wb' to be a COM object browser control, to wb.Document.parentWindow, so you can call "Neutron.wnd.execScript(<your function here>)
Simple2.html:
Spoiler
The AHK code is also scarcely changed. Code: Select all
<!DOCTYPE html>
<html>
<head>
<!--
The IE Compatibility flag, while not always necessary, makes sure your page
will always load in IE11+ rendering mode instead of being limited to IE7
features and behaviors. While IE11 is still relatively old as a rendering
engine, it supports the most fundamental parts needed for modern webpages to
function correctly.
Neutron will do its best to enable IE11+ rendering mode regardless of this
tag, but in current releases pages will not render correctly when compiled
unless this tag is present. Because of that and other edge cases, any page
you write to load in Neutron should contain this meta tag.
-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script>
function TestMe() {
alert('Hello to AHK from a JS function!');
};
</script>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-family: sans-serif;
}
body {
display: flex;
flex-direction: column;
}
/*** Window Title ***/
header {
width: 100%;
display: flex;
background: #F0F0F0;
font-family: Segoe UI;
font-size: 9pt;
}
.title-bar {
padding: 0.35em 0.5em;
flex-grow: 1;
}
.title-btn {
padding: 0.35em 1.0em;
cursor: pointer;
vertical-align: bottom;
font-family: Webdings;
font-size: 11pt;
}
.title-btn:hover {
background: rgba(0, 0, 0, .2);
}
.title-btn-close:hover {
background: #dc3545;
}
/*** Window Client Area ***/
.main {
/* Some settings for everything in the client area */
font-size: 12pt;
padding: 1em;
overflow: auto;
}
.container {
/* Only render items in the center 600px of the client area */
max-width: 600px;
margin: auto;
}
/*** Bootstrap Style Flexbox Utilities ***/
.row {
/* A row is basically just a flexbox container */
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.w-50 {
/* Fill almost half the row, leaving a bit of margin */
width: 48%;
}
.w-100 {
/* Fill the entire row */
width: 100%;
}
@media screen and (max-width: 500px) {
/* When the window gets shrunk */
.w-50 {
/* Reflow half-size elements to fill the entire row */
width: 100%;
}
}
/*** Generic Form Styling ***/
input[type=text],
input[type=email],
input[type=number],
input[type=password],
select {
width: 100%;
padding: 0.75em;
margin-bottom: 1em;
border: 1px solid silver;
border-radius: 0.35em;
box-sizing: border-box;
}
label {
display: inline-block;
margin-bottom: 0.5em;
font-weight: bold;
font-size: 0.8em;
}
button {
width: 100%;
background-color: MediumSeaGreen;
color: white;
padding: 14px 20px;
margin-bottom: 1em;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
/* https://stackoverflow.com/a/17406564 */
fieldset {
margin-bottom: 1em;
margin-top: 1.5em;
border: 1px solid silver;
border-radius: 0.35em;
padding-top: 1em;
box-sizing: border-box;
}
legend {
background: white;
}
fieldset>legend {
float: left;
margin-top: -1.5em;
}
fieldset>legend+* {
clear: both;
}
/*** Giant Key Styling ***/
.keys {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.keys>div {
width: 100px;
height: 100px;
margin: 10px;
padding: 0;
background: silver;
text-align: center;
font-size: 90px;
color: white;
border-radius: 1rem;
}
.keys>div.active {
background: MediumSeaGreen;
}
/*** Table Styling ***/
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
thead, tr:nth-child(even) {
/* Color header and every other row */
background: #eee;
}
</style>
</head>
<body>
<!-- Title Bar -->
<header>
<span class="title-bar" onmousedown="neutron.DragTitleBar()">Neutron</span>
<span class="title-btn" onclick="neutron.Minimize()">0</span>
<span class="title-btn" onclick="neutron.Maximize()">1</span>
<span class="title-btn title-btn-close" onclick="neutron.Close()">r</span>
</header>
<!-- Main content area -->
<div class="main">
<div class="container">
<h1>Welcome to Neutron</h1>
<p>
Neutron provides a powerful set of tools for build HTML-based user
interfaces with AutoHotkey. It leverages the Trident engine, known for
its use in Internet Explorer, because of its deep integration with the
Microsoft Windows operating system and its wide availability across
systems.
</p>
<p>
This example, while named Simple, is not the most simplistic example.
Instead, it is designed to demonstrate all of Neutron's built in behavior
as a single custom page. It is meant to be simple by comparison to other
examples like the Bootstrap example which demonstrate extending Neutron's
functionality with third party web frameworks.
</p>
<!-- Example #1 -->
<h2>Trigger AHK by page events</h2>
<p>
The simplest way of integrating a page to your script is by linking a
button's click event to a function in your script. This can be easily
achieved using the button's <code>onclick</code> attribute.
</p>
<div class="row">
<button class="w-50" onclick="ahk.Example1_Button(event)">Button #1</button>
<button class="w-50" onclick="ahk.Example1_Button(event)">Button #2</button>
</div>
<p>
Click events aren't the only type that can be handled. The box below
responds to mouse movement events and gets automatically updated with
the cursor position by AutoHotkey.
</p>
<div style="border: 1px solid black; width: 100%; text-align: center; padding: 1em 0;"
onmousemove="ahk.Example1_MouseMove(event)" onmouseout="ahk.Example1_MouseLeave(event)">
Mouse over this area!
</div>
<!-- Example #2 -->
<h2>Update page by Hotkey</h2>
<p>
Try pressing the keys 1 through 4 on your keyboard!
</p>
<div class="keys">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<p>
This example demonstrates the following tasks:
</p>
<ul>
<li>Limit a hotkey's activity to the Neutron window.</li>
<li>Find a collection of elements using CSS selectors.</li>
<li>Iterate over the collection with <code>Neutron.Each</code></li>
<li>Update an element's CSS class string.</li>
</ul>
<!-- Example #3 -->
<h2>Pass form data to AHK</h2>
<p>
This example shows how you would collect form data from Neutron.
</p>
<form onsubmit="ahk.Submit(event)">
<div class="row">
<div class="w-50">
<label for="firstName">First Name</label>
<input type="text" id="firstName" placeholder="John" required>
</div>
<div class="w-50">
<label for="lastName">Last Name</label>
<input type="text" id="lastName" placeholder="Smith" required>
</div>
<div class="w-100">
<label for="email">Email</label>
<input type="email" id="email" placeholder="[email protected]">
</div>
<div class="w-100">
<label for="password">Password</label>
<input type="password" id="password" placeholder="hunter2">
</div>
<div class="w-50">
<label for="address">Address</label>
<input type="text" id="address" placeholder="123 Central Avenue">
</div>
<div class="w-50">
<label for="address2">Address 2</label>
<input type="text" id="address2" placeholder="Apartment 42">
</div>
<div class="w-100">
<label for="city">City</label>
<input type="text" id="city" placeholder="LEGO® City">
</div>
<div class="w-50">
<label for="state">State</label>
<select id="state" required>
<option value="" selected>Choose...</option>
<option>Confusion</option>
</select>
</div>
<div class="w-50">
<label for="zip">Zip</label>
<input type="number" id="zip" placeholder="1337">
</div>
<div class="w-100">
<input type="checkbox" id="remember">
<label for="remember">Remember me</label>
</div>
</div>
<button type="submit">Submit</button>
</form>
<p>
You can also use forms where there are multiple options for a value,
such as by a set of checkboxes or multi-select. Radio selections work
too!
</p>
<form onsubmit="ahk.Submit2(event)">
<fieldset>
<legend>Favorite Foods</legend>
<div class="row">
<div class="w-50">
<input type="checkbox" id="hamburgers" value="hamburgers" name="food">
<label for="hamburgers">Hamburgers</label>
</div>
<div class="w-50">
<input type="checkbox" id="hotdogs" value="hotdogs" name="food">
<label for="hotdogs">Hot Dogs</label>
</div>
<div class="w-50">
<input type="checkbox" id="fries" value="fries" name="food">
<label for="fries">French Fries</label>
</div>
<div class="w-50">
<input type="checkbox" id="cookies" value="cookies" name="food">
<label for="cookies">Cookies</label>
</div>
<div class="w-50">
<input type="checkbox" id="pizza" value="pizza" name="food">
<label for="pizza">Pizza</label>
</div>
<div class="w-50">
<input type="checkbox" id="chicken" value="chicken" name="food">
<label for="chicken">Chicken</label>
</div>
</div>
</fieldset>
<fieldset>
<legend>Favorite Languages</legend>
<select id="favLangs" multiple style="border: none; padding: 0; margin: 0;">
<option value="ahk">AutoHotkey</option>
<option value="py">Python</option>
<option value="rlx">Relax</option>
<option value="cpp">C++</option>
</select>
</fieldset>
<fieldset>
<legend>Preferred Method of Contact</legend>
<div class="row">
<div class="w-50">
<input type="radio" id="contactEmail" value="email" name="contact" checked>
<label for="contactEmail">Email</label>
</div>
<div class="w-50">
<input type="radio" id="contactPhone" value="phone" name="contact">
<label for="contactPhone">Phone</label>
</div>
<div class="w-50">
<input type="radio" id="contactEmail" value="email" name="contact">
<label for="contactEmail">Snail Mail</label>
</div>
<div class="w-50">
<input type="radio" id="contactIPoAC" value="IPoAC" name="contact">
<label for="contactIPoAC">RFC 1149</label>
</div>
</div>
</fieldset>
<button type="submit">Submit</button>
</form>
<!-- Example #4 -->
<h2>Dynamic Content Generation</h2>
<p>
Often you won't have the HTML you want on the page in advance, but
instead need to generate it based on some data that the script receives,
whether from a file, a web API, input boxes on the page, etc. Generating
HTML on the fly is possible, but unless done right can introduce subtle
bugs into your application.
</p>
<p>
There are two main techniques to dynamic generation. First, you can
write code that creates the HTML, then load that HTML onto the page by
using something like <code>document.write(html);</code> or
<code>element.innerHTML = html;</code>. Second, you can use DOM
functions like <code>document.createElement</code> to generate the page
elements directly without worrying about the HTML markup. This second
option is usually the safer option, but is much more difficult to work
with. Both techniques are demonstrated below.
</p>
<h3>HTML Generation</h3>
<form onsubmit="ahk.Ex4_Submit1(event)">
<div class="row">
<div class="w-50">
<label for="ex4_item1">Item</label>
<input type="text" id="ex4_item1" placeholder="Banana" required>
</div>
<div class="w-50">
<label for="ex4_cost1">Cost ($)</label>
<input type="number" id="ex4_cost1" placeholder="3" required>
</div>
</div>
<button type="submit">Submit</button>
</form>
<table id="ex4_table1">
<thead>
<tr>
<th>Item</th>
<th>Cost</th>
</tr>
</thead>
<tbody></tbody>
</table>
<h3>DOM Generation</h3>
<form onsubmit="ahk.Ex4_Submit2(event)">
<div class="row">
<div class="w-50">
<label for="ex4_item2">Item</label>
<input type="text" id="ex4_item2" placeholder="Banana" required>
</div>
<div class="w-50">
<label for="ex4_cost2">Cost ($)</label>
<input type="number" id="ex4_cost2" placeholder="3" required>
</div>
</div>
<button type="submit">Submit</button>
</form>
<table id="ex4_table2">
<thead>
<tr>
<th>Item</th>
<th>Cost</th>
</tr>
</thead>
<tbody></tbody>
</table>
<h1>Thanks for playing!</h1>
</div> <!-- /container -->
</div> <!-- /main -->
</body>
</html>
Code: Select all
Example1_Button(neutron, event)
{
; event.target will contain the HTML Element that fired the event.
; Show a message box with its inner text.
Neutron.wnd.execScript("TestMe()")
MsgBox, % "You clicked: " event.target.innerText
}
Spoiler
When you run Simple2.ahk and click on Button #1 you should see this alert, followed by the original AHK msgbox.Code: Select all
/*
This example, while named Simple, is not the most simplistic example.
Instead, it is designed to demonstrate all of Neutron's built in behavior
as a single custom page. It is meant to be simple by comparison to other
examples like the Bootstrap example which demonstrate extending Neutron's
functionality with third party web frameworks.
*/
#NoEnv
SetBatchLines, -1
; Include the Neutron library
#Include ../../Neutron.ahk
; Create a new NeutronWindow and navigate to our HTML page
neutron := new NeutronWindow()
neutron.Load("Simple2.html")
; Use the Gui method to set a custom label prefix for GUI events. This code is
; equivalent to the line `Gui, name:+LabelNeutron` for a normal GUI.
neutron.Gui("+LabelNeutron")
; Insert example 4 table 1 contents
Ex4_Table1 := [["Apple", 1], ["Orange", 2]]
html := ""
for row, data in Ex4_Table1
{
html .= "<tr>"
for col, cell in data
html .= neutron.FormatHTML("<td>{}</td>", cell)
html .= "</tr>"
}
neutron.qs("#ex4_table1>tbody").innerHTML := html
; Insert example 4 table 2 contents
Ex4_Table2 := [["Apple", 1], ["Orange", 2]]
for row, data in Ex4_Table2
{
tr := neutron.doc.createElement("tr")
for col, cell in data
{
td := neutron.doc.createElement("td")
td.innerText := cell
tr.appendChild(td)
}
neutron.qs("#ex4_table2>tbody").appendChild(tr)
}
; Show the GUI, with an initial size of 800 x 600. Unlike with a normal GUI
; this size includes the title bar area, so the "client" area will be slightly
; shorter vertically than if you were to make this GUI the normal way.
neutron.Show("w800 h600")
return
; FileInstall all your dependencies, but put the FileInstall lines somewhere
; they won't ever be reached. Right below your AutoExecute section is a great
; location!
FileInstall, Simple.html, Simple.html
; The built in GuiClose, GuiEscape, and GuiDropFiles event handlers will work
; with Neutron GUIs. Using them is the current best practice for handling these
; types of events. Here, we're using the name NeutronClose because the GUI was
; given a custom label prefix up in the auto-execute section.
NeutronClose:
ExitApp
return
; --- Trigger AHK by page events ---
Example1_Button(neutron, event)
{
; event.target will contain the HTML Element that fired the event.
; Show a message box with its inner text.
Neutron.wnd.execScript("TestMe()")
MsgBox, % "You clicked: " event.target.innerText
}
Example1_MouseMove(neutron, event)
{
; Some events, like MouseMove, have custom attributes that can be read.
; offsetX and offsetY contain the mouse position relative to the event that
; fired the event.
event.target.innerText := Format("({:i}, {:i})", event.offsetX, event.offsetY)
}
Example1_MouseLeave(neutron, event)
{
; Reset the text of the MouseMove example when the mouse is no longer over
; it.
event.target.innerText := "Mouse over this area!"
}
; --- Update page by Hotkey ---
; Limit this hotkey to only fire while our Neutron window is the active window.
#if WinActive("ahk_id" neutron.hWnd)
~1::UpdateKeyExample(neutron, "1", "active")
~2::UpdateKeyExample(neutron, "2", "active")
~3::UpdateKeyExample(neutron, "3", "active")
~4::UpdateKeyExample(neutron, "4", "active")
~1 Up::UpdateKeyExample(neutron, "1", "")
~2 Up::UpdateKeyExample(neutron, "2", "")
~3 Up::UpdateKeyExample(neutron, "3", "")
~4 Up::UpdateKeyExample(neutron, "4", "")
UpdateKeyExample(neutron, keyName, className) {
; Use the JavaScript function document.querySelectorAll to find elements
; based on a CSS selector.
keyDivs := neutron.doc.querySelectorAll(".keys > div")
; Use Neutron's .Each() method to iterate through the HTMLCollection in a
; for loop.
for i, div in neutron.Each(keyDivs)
{
; Check if the div's innerText matches the key that was pressed
if (div.innerText == keyName)
{
; Update the div's className property to change its style on the fly
div.className := className
}
}
}
#if
; --- Pass form data to AHK ---
Submit(neutron, event)
{
; Some events have a default action that needs to be prevented. A form will
; redirect the page by default, but we want to handle the form data ourself.
event.preventDefault()
; Use Neutron's GetFormData method to process the form data into a form that
; is easily accessed. Fields that have a 'name' attribute will be keyed by
; that, or if they don't they'll be keyed by their 'id' attribute.
formData := neutron.GetFormData(event.target)
; You can access all of the form fields by iterating over the FormData
; object. It will go through them in the order they appear in the HTML.
out := "Access all fields by iterating:`n"
for name, value in formData
out .= name ": " value "`n"
out .= "`n"
; You can also get field values by name directly. Use object dot notation
; with the field name/id.
out .= "Or access individual fields directly:`n"
out .= "Hello " formData.firstName " " formData.lastName "!`n"
if formData.remember
out .= ""
else
out .= "You forgot to check the 'Remember Me' box :("
; Show the output
MsgBox, %out%
}
Submit2(neutron, event)
{
event.preventDefault()
formData := neutron.GetFormData(event.target)
; When you iterate over a FormData object with multi-selected checkboxes or
; select elements, it will act like an object with duplicate keys. The same
; name will appear multiple times, once per selected item.
out := "Access all fields by iterating:`n"
for name, value in formData
out .= name ": " value "`n"
out .= "`n"
; Iterating over the entire set of form fields is useful in some situations,
; but often you'll want to just get all the options selected for a single
; multi-select form field. Use the FormData's .All() method to get all the
; values associated with one field name as a standard array.
out .= "Or individually:`n"
out .= "Foods: [ "
for i, food in formData.All("food")
out .= food " "
out .= "]`n"
out .= "Languages: [ "
for i, language in formData.All("favLangs")
out .= language " "
out .= "]`n"
; The FormData object will combine a group of Radios with the same name
; under a single entry. Grab a Radio group's value using dot or bracket
; notation.
out .= "Contact: " formData.contact "`n"
; Show the output
MsgBox, %out%
}
; --- Dynamic Content Generation ---
Ex4_Submit1(neutron, event)
{
event.preventDefault()
formData := neutron.GetFormData(event.target)
; Generate the HTML we're going to add to the page. To do this, we use the
; FormatHTML static method, which will run the values through an HTML escape
; function before passing them on to the AHK Format function. This will
; take care of any special sequences such as angle brackets or quotes that
; exist in the data and keep them from breaking the page.
html := neutron.FormatHTML("<tr><td>{}</td><td>{}</td>", formData.ex4_item1, formData.ex4_cost1)
; Add our HTML to the page, as part of the table body. To do this, we'll be
; using the element.insertAdjacentHTML function. However, if we wanted to
; replace the body contents instead of adding to them, we could instead use
; `.innerHTML := html`.
;
; Read more about element.insertAjacentHTML here:
; https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
neutron.qs("#ex4_table1>tbody").insertAdjacentHTML("beforeend", html)
}
Ex4_Submit2(neutron, event)
{
event.preventDefault()
formData := neutron.GetFormData(event.target)
; Create the row element to add cells to
tr := neutron.doc.createElement("tr")
; Create the first column cell and add it to the row
td := neutron.doc.createElement("td")
td.innerText := formData.ex4_item2
tr.appendChild(td)
; Create the second column cell and add it to the row
td := neutron.doc.createElement("td")
td.innerText := formData.ex4_cost2
tr.appendChild(td)
; Add the row to the table
neutron.qs("#ex4_table2>tbody").appendChild(tr)
}
- alert.PNG (37.28 KiB) Viewed 5909 times
Regards,
burque505