Mouse events
A page that only shows things is a document. A page that answers a click is a program. This lesson shows how to attach a Salam function to a mouse event, how to read where the pointer is, and how the twelve mouse events differ. Every example runs in the preview under it.
Giving an element a handler
A handler is a function the browser calls when something happens to an element. In Salam you attach it with an attribute named after the event: click = ... on a button says what to do when the button is clicked. Events with two words have a space, as everywhere in the page language: double click, mouse move, context menu. The value of the attribute can be written in four ways.
import dom
mut named_clicks := 0
func named():
named_clicks += 1
dom.SetText(dom.ById("out"), "named function, click " + named_clicks)
end
func with_event(e: i64):
dom.SetText(dom.ById("out"), "named function with the event, pointer at x " + dom.EventX(e))
end
page:
title = "Four ways to handle a click"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
global: selector = "button" padding = "8px 14px" margin = "0 8px 8px 0" font size = "1rem" end
paragraph: id = "out" content = "Press a button." end
button: click = named content = "Named function" end
button: click = with_event content = "With the event" end
button: click = (): dom.SetText(dom.ById("out"), "lambda") end content = "Lambda" end
button: click = "this.textContent = 'JS string was here'" content = "JS string" end
endHere is what each form is for.
- A named function declared above the
page:block. Use it when the code is longer than a line or when two elements share it. The function may have no parameters, asnamedhas, or one parameter of typei64, aswith_eventhas. That parameter receives the event, and you hand it to the helpers that read it:dom.EventX(e)anddom.EventY(e)for the pointer position,dom.EventTarget(e)for the element that was hit,dom.PreventDefault(e)anddom.StopPropagation(e)to change what the browser does next. - A lambda written inline as
(): ... end. It is the shortest form for one or two statements. In a page attribute a lambda takes no parameters, so it cannot see the event. When you need the event, use a named function. - A JavaScript string such as
"this.textContent = 'hi'". It is copied into the HTML as it is, so inside itthisis the element andeventis the event. Use it only for tiny things the Salam helpers do not cover.
The functions you write in Salam are compiled to JavaScript and placed in one script at the end of the page. A browser finds the function named in onclick="named()" by looking it up on window, so the compiler also stores every handler there. You never write this yourself, but it explains why a handler must be a plain function of the page and not, say, a method.
State, for example a counter, lives in a top level mut variable above the page. The handler changes it and then writes the new value into the page with dom.SetText. The compiler checks your work: dom.ById("x") must name an id that exists in the same page (error E138), and an event must name a function that exists (error E137).
Do not name a handler like a built-in. The browser looks a name in an attribute up on the element, then on its form, then on the document, and only then on the window. A function called clear, open, close, write, reset, submit, focus, click or name loses to the built-in of that name, and nothing seems to happen. Some names are worse than useless: the window has read-only properties such as closed, status, top and length, and a handler with one of those names makes the whole page script stop with an error, so none of your handlers work. Choose names such as clear_board or open_menu.
A page script only knows the dom helpers and your own code. Helpers that do more than pass one call on, such as dom.RandomInt, and other packages such as math are not part of it. dom.Random() gives a number from 0 up to 1, so (dom.Random() * 85.0) as i64 is a whole number from 0 to 84.
Click: counting and switching
click fires when the user presses and releases the primary mouse button on the element, and also when a keyboard user presses Enter or Space on a focused button, so it is the right event for anything that acts like a button. Use it on a real button element and not on a box: a button can be reached with the Tab key, a box cannot.
The counter below keeps its number in count. Each handler is a lambda that changes the variable and calls show, a small function that copies the number into the heading. The two parts, the state and the code that draws it, stay separate, and that is the habit worth learning first.
import dom
mut count := 0
func show:
dom.SetText(dom.ById("n"), "" + count)
end
page:
title = "Click counter"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" text align = center end
heading: id = "n" size = 1 content = "0" font size = "4rem" margin = "0 0 12px 0" end
button: id = "plus" click = (): count += 1 show() end content = "+1" padding = "8px 18px" font size = "1.1rem" end
button: id = "reset" click = (): count = 0 show() end content = "Reset" padding = "8px 18px" font size = "1.1rem" margin = "0 0 0 8px" end
endThe second example needs no variable, because the page itself remembers the state: dom.ToggleClass adds a class when the element does not have it and removes it when it does. The look of each state is written in CSS, in a style element, and the script only flips the class. The transition property makes the change fade instead of jump.
import dom
page:
title = "Lamp"
style: content = "#room.on { background: #fde68a; color: #422006 } #room.on .bulb { background: #f59e0b }" end
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "room"
background = "#1e293b"
color = "#e2e8f0"
padding = 24
border radius = 12
text align = center
transition = "background 0.3s"
box: class = "bulb" width = 60 height = 60 margin = "0 auto 12px" background = "#475569" border radius = "50%" end
button: id = "switch" click = (): dom.ToggleClass(dom.ById("room"), "on") end content = "Switch" padding = "6px 16px" end
end
endDouble click, other buttons and the context menu
double click fires after two quick clicks on the same element. The browser still sends the two ordinary click events first, so a handler on click runs twice before the double click arrives. Do not put two different actions on click and double click of the same element. aux click is the click of every button except the main one. The event's button number tells which: 0 is the main button, 1 the middle one, 2 the right one, and 3 and 4 are the back and forward buttons of some mice. context menu fires when the user asks for the context menu, which is a right click, the menu key or Shift and F10. Calling dom.PreventDefault(e) stops the browser's own menu.
import dom
mut history := ""
mut lines := 0
func note(text: str):
lines += 1
if lines > 7:
history = ""
lines = 1
end
history = history + text + "\n"
dom.SetText(dom.ById("log"), history)
end
func aux(e: i64):
note("aux click, button " + (dom.GetNum(e, "button") as i64))
end
func menu(e: i64):
dom.PreventDefault(e)
note("context menu (the browser menu is blocked)")
end
page:
title = "Kinds of clicks"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "pad"
click = (): note("click") end
double click = (): note("double click") end
aux click = aux
context menu = menu
content = "Click, double click, middle click or right click here"
padding = 28
background = "#e0f2fe"
border radius = 10
user select = none
end
paragraph: id = "log" content = "Nothing yet." white space = "pre-line" min height = "10em" end
endThe example reads the button number with dom.GetNum(e, "button"), which reads any number property of the event object. The log holds the last seven events, and white space = "pre-line" turns each \n in the text into a new line. user select = none stops a double click from selecting the words of the box.
That is enough to build your own menu. On context menu the handler prevents the default, moves a hidden box to the pointer and shows it. Any click on the area closes it again, and each item closes it as well.
import dom
func open_menu(e: i64):
dom.PreventDefault(e)
menu := dom.ById("menu")
dom.SetStyle(menu, "left", "" + dom.EventX(e) + "px")
dom.SetStyle(menu, "top", "" + dom.EventY(e) + "px")
dom.SetStyle(menu, "display", "block")
end
func close_menu():
dom.SetStyle(dom.ById("menu"), "display", "none")
end
func pick(what: str):
dom.SetText(dom.ById("chosen"), "You chose: " + what)
close_menu()
end
page:
title = "Custom menu"
global: selector = "body" font family = "system-ui, sans-serif" margin = 0 end
box:
id = "area"
context menu = open_menu
click = close_menu
padding = 32
min height = "260px"
background = "#f1f5f9"
paragraph: content = "Right click anywhere on this area." end
paragraph: id = "chosen" content = "Nothing chosen." end
end
box:
id = "menu"
display = none
position = fixed
background = white
border = "1px solid #cbd5e1"
border radius = 8
box shadow = "0 6px 18px rgba(0,0,0,0.18)"
padding = 4
button: id = "copy" click = (): pick("Copy") end content = "Copy" display = block width = "100%" end
button: id = "rename" click = (): pick("Rename") end content = "Rename" display = block width = "100%" end
button: id = "delete" click = (): pick("Delete") end content = "Delete" display = block width = "100%" end
end
endThe menu box has position = fixed, which places it relative to the window, so left and top can be set straight from the pointer position dom.EventX(e) and dom.EventY(e). Those two are measured from the top left corner of the window, which is the same corner a fixed box uses.
Use a custom context menu only where it adds something, as in an editor or a file list. A right click that does nothing useful, or hides the ordinary menu with its spell check and copy, annoys people. Keep every action of the menu reachable in another way too, because touch screens and keyboards do not right click.
Pressing, releasing and moving
mouse down fires the moment a button goes down, mouse up when it comes up, and click is what the browser makes of a down and an up on the same element. mouse move fires again and again while the pointer moves, many times a second, so keep its handler short.
The position in the event is measured from the window. Most of the time you want it measured from some box, such as a drawing area. Ask the box where it is with getBoundingClientRect and subtract its left and top. In Salam that is dom.Call0(box, "getBoundingClientRect") for the rectangle and dom.GetNum(rect, "left") for each number. The first example shows the position inside the green box and moves a dot with it. The dot has pointer events = none, so it never gets in the way of the pointer.
import dom
func moved(e: i64):
pad := dom.ById("pad")
r := dom.Call0(pad, "getBoundingClientRect")
x := (dom.EventX(e) - dom.GetNum(r, "left")) as i64
y := (dom.EventY(e) - dom.GetNum(r, "top")) as i64
dom.SetText(dom.ById("pos"), "x " + x + ", y " + y)
dot := dom.ById("dot")
dom.SetStyle(dot, "left", "" + x + "px")
dom.SetStyle(dot, "top", "" + y + "px")
end
page:
title = "Pointer position"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "pad"
mouse move = moved
position = relative
height = 180
background = "#ecfccb"
border radius = 10
cursor = crosshair
overflow = hidden
box: id = "dot" position = absolute width = 12 height = 12 margin = "-6px 0 0 -6px" border radius = "50%" background = "#15803d" pointer events = none end
end
paragraph: id = "pos" content = "Move the mouse over the green area." end
endThe next example draws. A top level mut variable says whether the button is down. mouse down sets it and paints the first dot, mouse move paints while it is set, and mouse up clears it. mouse leave clears it too, because a button released outside the box would never reach the box. Each dot is a new element made with dom.Create and added with dom.Append, and the look of the dots comes from one CSS rule written in a style element.
import dom
mut drawing := false
func begin_stroke(e: i64):
drawing = true
paint(e)
end
func end_stroke:
drawing = false
end
func paint(e: i64):
if drawing:
r := dom.Call0(dom.ById("board"), "getBoundingClientRect")
dot := dom.Create("div")
dom.SetAttr(dot, "class", "dot")
dom.SetStyle(dot, "left", "" + (dom.EventX(e) - dom.GetNum(r, "left")) + "px")
dom.SetStyle(dot, "top", "" + (dom.EventY(e) - dom.GetNum(r, "top")) + "px")
dom.Append(dom.ById("board"), dot)
end
end
func clear_board:
dom.SetHtml(dom.ById("board"), "")
end
page:
title = "Drawing"
style: content = ".dot { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: #7c3aed; pointer-events: none }" end
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "board"
mouse down = begin_stroke
mouse move = paint
mouse up = end_stroke
mouse leave = end_stroke
position = relative
height = 200
background = "#faf5ff"
border = "2px dashed #c4b5fd"
border radius = 10
cursor = crosshair
overflow = hidden
user select = none
end
button: id = "clear" click = clear_board content = "Clear" margin = "10px 0 0 0" padding = "6px 14px" end
endThis draws dots, so a fast stroke leaves gaps. For a smooth line use a canvas, and see web/canvas. The pattern of down, move and up is the same for dragging an element by hand, and the next lessons build on it.
Enter and leave, over and out
Four events tell you that the pointer has come or gone, and two pairs behave differently. mouse enter and mouse leave fire only for the element they are set on: when the pointer first comes into the element, and when it goes out of it altogether. Moving between the element and its children does not count. mouse over and mouse out also fire for the children, because they bubble up from them: moving from the outer box onto the inner one sends an out for the outer box and an over that rises from the inner one. Try both below and watch the counters. The left box says enter 1, leave 0 while you are over it or its inner square, and the right box counts every step.
import dom
mut enters := 0
mut leaves := 0
mut overs := 0
mut outs := 0
func show_a:
dom.SetText(dom.ById("count-a"), "enter " + enters + ", leave " + leaves)
end
func show_b:
dom.SetText(dom.ById("count-b"), "over " + overs + ", out " + outs)
end
page:
title = "Enter and leave"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
global: selector = ".zone" position = relative height = 90 width = 220 background = "#dbeafe" border radius = 10 padding = 10 box sizing = "border-box" end
global: selector = ".inner" position = absolute right = 10 top = 10 width = 70 height = 70 background = "#2563eb" color = white border radius = 8 text align = center end
box:
display = flex
gap = 24
flex wrap = wrap
box:
heading: size = 3 content = "enter and leave" margin = "0 0 8px 0" end
box:
id = "a" class = "zone" content = "outer"
mouse enter = (): enters += 1 show_a() end
mouse leave = (): leaves += 1 show_a() end
box: id = "a-inner" class = "inner" content = "inner" end
end
paragraph: id = "count-a" content = "enter 0, leave 0" end
end
box:
heading: size = 3 content = "over and out" margin = "0 0 8px 0" end
box:
id = "b" class = "zone" content = "outer"
mouse over = (): overs += 1 show_b() end
mouse out = (): outs += 1 show_b() end
box: id = "b-inner" class = "inner" content = "inner" end
end
paragraph: id = "count-b" content = "over 0, out 0" end
end
end
endMost of the time you want enter and leave: a menu that opens while the pointer is over it, a tooltip, a highlight. Use over and out when you really want to know about each child, for example to light up the exact cell of a table the pointer touches.
Here is a tooltip that follows the pointer. mouse enter shows it with the right text, mouse move moves it, and mouse leave hides it. It sits 14 and 18 pixels away from the pointer, because a tooltip under the pointer would take the pointer's events and flicker. Its pointer events = none prevents the same problem.
import dom
func show_tip(text: str):
tip := dom.ById("tip")
dom.SetText(tip, text)
dom.SetStyle(tip, "display", "block")
end
func hide_tip:
dom.SetStyle(dom.ById("tip"), "display", "none")
end
func follow(e: i64):
tip := dom.ById("tip")
dom.SetStyle(tip, "left", "" + (dom.EventX(e) + 14.0) + "px")
dom.SetStyle(tip, "top", "" + (dom.EventY(e) + 18.0) + "px")
end
page:
title = "Tooltip"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
global: selector = "button" padding = "8px 14px" margin = "0 8px 0 0" font size = "1rem" end
button: id = "save" content = "Save" mouse enter = (): show_tip("Save the file") end mouse move = follow mouse leave = hide_tip end
button: id = "open" content = "Open" mouse enter = (): show_tip("Open a file from disk") end mouse move = follow mouse leave = hide_tip end
button: id = "share" content = "Share" mouse enter = (): show_tip("Send a link to a friend") end mouse move = follow mouse leave = hide_tip end
box: id = "tip" display = none position = fixed background = "#0f172a" color = white padding = "4px 10px" border radius = 6 font size = "0.85rem" pointer events = none end
endThe target and bubbling
When you click the word inside a button inside a box, the event first goes to the word, and then it bubbles: it is offered to the button, then to the box, then upwards to the page. Every element on the way that has a click handler runs it. Inside a handler, dom.EventTarget(e) is the element that was really hit, even when the handler is set on an ancestor. This lets one handler on a list serve a hundred items. Call dom.StopPropagation(e) and the event goes no further.
import dom
func outer(e: i64):
who := dom.GetAttr(dom.EventTarget(e), "id")
dom.SetText(dom.ById("log"), "The outer box heard a click from: " + who)
end
func inner_stop(e: i64):
dom.StopPropagation(e)
dom.SetText(dom.ById("log"), "The stopping button kept the click to itself.")
end
page:
title = "Bubbling"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
global: selector = "button" padding = "8px 14px" margin = "0 8px 0 0" font size = "1rem" end
box:
id = "outer-box"
click = outer
padding = 20
background = "#ede9fe"
border radius = 10
paragraph: content = "Outer box" margin = "0 0 10px 0" end
button: id = "plain" content = "Plain button" end
button: id = "stopper" click = inner_stop content = "Stopping button" end
span: id = "label" content = "or the text here" end
end
paragraph: id = "log" content = "Click something." end
endThe outer box has one handler. It reads the target's id with dom.GetAttr and prints it. The plain button has no handler of its own and still reports to the box, and so does the text. The stopping button has a handler that stops the event, so the box never hears from it. Do not stop propagation without a reason: other code that listens higher up, such as a menu that wants to close on any click, stops working for that element.
Most events bubble. A few do not, and mouse enter and mouse leave are the ones from this lesson. This is why they count differently from over and out above.
The wheel
wheel fires when the wheel turns, or two fingers slide on a touchpad. The event's deltaY is negative when the user scrolls up, away from themselves, and positive when they scroll down. By default the wheel scrolls the page. A handler that calls dom.PreventDefault(e) cancels that, which is what you want in a map or an image viewer and what you should not do on a normal page. Most browsers treat wheel handlers on the window, document and body as passive and ignore the cancel there, so put the handler on an element, as the example does.
import dom
mut zoom := 1.0
func scroll_zoom(e: i64):
dom.PreventDefault(e)
if dom.GetNum(e, "deltaY") < 0.0:
zoom = zoom * 1.1
else:
zoom = zoom / 1.1
end
if zoom > 3.0:
zoom = 3.0
end
if zoom < 0.5:
zoom = 0.5
end
percent := (zoom * 100.0) as i64
dom.SetStyle(dom.ById("card"), "transform", "scale(" + zoom + ")")
dom.SetText(dom.ById("level"), "Zoom " + percent + "%")
end
page:
title = "Wheel zoom"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "stage"
wheel = scroll_zoom
height = 200
overflow = hidden
background = "#f1f5f9"
border radius = 10
display = flex
align items = center
justify content = center
box: id = "card" content = "Scroll the wheel over me" padding = 24 background = "#0f766e" color = white border radius = 10 end
end
paragraph: id = "level" content = "Zoom 100%" end
endThe handler multiplies or divides the zoom by 1.1 on each step and keeps it between 0.5 and 3, with two plain if statements, because the page script has no math. The result is written into transform as scale(...). The box that is scaled is inside a stage with overflow = hidden, so what grows beyond the stage is cut off and the page does not move.
Putting it together: a click game
This game uses what you have seen. The red square has a handler for click that counts a hit and moves the square to a random place. The yellow field around it also has a click handler that counts a miss. A click on the square would bubble to the field and count as a miss as well, so the square's handler first calls dom.StopPropagation(e). Positions are set in percent, so the game works at any width.
import dom
mut hits := 0
mut misses := 0
func show:
dom.SetText(dom.ById("score"), "Hits " + hits + ", misses " + misses)
end
func move_target:
t := dom.ById("target")
dom.SetStyle(t, "left", "" + ((dom.Random() * 85.0) as i64) + "%")
dom.SetStyle(t, "top", "" + ((dom.Random() * 75.0) as i64) + "%")
end
func hit(e: i64):
dom.StopPropagation(e)
hits += 1
show()
move_target()
end
func miss:
misses += 1
show()
end
page:
title = "Catch the square"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
box:
id = "field"
click = miss
position = relative
height = 220
background = "#fef9c3"
border radius = 10
overflow = hidden
cursor = crosshair
box: id = "target" click = hit position = absolute left = "40%" top = "30%" width = 44 height = 44 background = "#dc2626" border radius = 8 cursor = pointer end
end
paragraph: id = "score" content = "Hits 0, misses 0" end
endWhen CSS is the better tool
Before you write mouse over and mouse out to change how something looks, remember that CSS can do it alone. A style with the prefix hover applies while the pointer is over the element, and the browser takes it away again, with no code that can forget a case. The two buttons below look the same. The first uses hover background and states each colour once. The second needs two handlers, repeats the colours in the script, and does nothing when the script fails to load. CSS also takes the hover style away by itself in every case, while a script has to remember each way the pointer can leave.
import dom
page:
title = "Hover"
global: selector = "body" font family = "system-ui, sans-serif" margin = "1.5rem" end
global: selector = "button" padding = "10px 18px" margin = "0 12px 0 0" font size = "1rem" border = "none" border radius = 8 color = white end
button:
id = "css"
content = "Hover in CSS"
background = "#0f766e"
transition = "background 0.2s"
hover background = "#115e59"
end
button:
id = "js"
content = "Hover in JS"
background = "#0f766e"
mouse over = (): dom.SetStyle(dom.ById("js"), "background", "#115e59") end
mouse out = (): dom.SetStyle(dom.ById("js"), "background", "#0f766e") end
end
paragraph: content = "Both look the same. Only the first one needs no script." end
endUse a mouse event when something must happen, such as a number that changes, a box that appears, a request that is sent. Use CSS when the page only has to look different. The CSS lessons come back to hover, focus and active in detail.
Touch screens have no pointer to hover with. A tooltip or a menu that appears only on hover is out of reach for a phone, so also offer a click or a tap.
Reference: every mouse event
Each row gives the attribute, the name of the HTML attribute it becomes and when the event fires. The snippets are checked by the compiler. Where a handler needs the event itself, the snippet uses a JavaScript string, because a pasted snippet has no named function to call; in your own code use a named function with an i64 parameter, as in the examples above.
| Attribute | When it fires | Example |
|---|---|---|
clickکلیک onclick | Runs when the primary button is pressed and released on the element, or when a keyboard user activates a focused button with Enter or Space. It is the event for anything that acts like a button. | button: click = (): dom.SetText(dom.ById("out"), "Clicked") end content = "Click me" end
paragraph: id = "out" content = "-" end |
double clickدو کلیک ondblclick | Runs after two quick clicks on the same element. The two ordinary click events come first, so a click handler on the same element runs twice before this one. | box: double click = (): dom.SetText(dom.ById("out"), "Double clicked") end content = "Double click here" padding = 20 background = "#e0f2fe" user select = none end
paragraph: id = "out" content = "-" end |
aux clickکلیک کمکی onauxclick | Runs when a button other than the main one is clicked. The event property button says which: 1 is the middle button and 2 the right one, and 3 and 4 are the back and forward buttons of some mice. | box: aux click = (): dom.SetText(dom.ById("out"), "Another button") end content = "Middle click here" padding = 20 background = "#fef3c7" end
paragraph: id = "out" content = "-" end |
context menuمنوی زمینه oncontextmenu | Runs when the user asks for the context menu: a right click, the menu key or Shift and F10. dom.PreventDefault(e) stops the browser's own menu so the page can show its own. | box: context menu = "event.preventDefault(); this.textContent = 'Your own menu goes here'" content = "Right click here" padding = 20 background = "#fce7f3" end |
mouse downفشردن ماوس onmousedown | Runs the moment a mouse button goes down on the element, before the button is released. It is where dragging and drawing start. | box: mouse down = (): dom.SetText(dom.ById("out"), "Button is down") end mouse up = (): dom.SetText(dom.ById("out"), "Button is up") end content = "Press and hold" padding = 20 background = "#e0e7ff" user select = none end
paragraph: id = "out" content = "-" end |
mouse upرها کردن ماوس onmouseup | Runs when a mouse button comes up over the element. A button released outside the element where it went down is reported to the element under the pointer, not to the first one. | box: mouse up = (): dom.SetText(dom.ById("out"), "Released here") end content = "Release the button over me" padding = 20 background = "#dcfce7" user select = none end
paragraph: id = "out" content = "-" end |
mouse moveحرکت ماوس onmousemove | Runs again and again while the pointer moves over the element, many times a second. Keep the handler short. The position is dom.EventX(e) and dom.EventY(e), measured from the window. | box: mouse move = "this.textContent = event.clientX + ', ' + event.clientY" content = "Move over me" padding = 24 background = "#dcfce7" end |
mouse enterورود ماوس onmouseenter | Runs once when the pointer comes into the element. It does not bubble and does not repeat when the pointer moves between the element and its children, which makes it the right choice for hover effects done in script. | box: mouse enter = (): dom.SetText(dom.ById("out"), "Entered") end content = "Point at me" padding = 20 background = "#e0f2fe" end
paragraph: id = "out" content = "-" end |
mouse leaveخروج ماوس onmouseleave | Runs once when the pointer leaves the element and all its children. It does not bubble. | box: mouse leave = (): dom.SetText(dom.ById("out"), "Left") end content = "Point at me, then move away" padding = 20 background = "#e0f2fe" end
paragraph: id = "out" content = "-" end |
mouse overعبور ماوس onmouseover | Runs when the pointer comes onto the element or onto one of its children. It bubbles, so a handler on a parent hears about every child; use dom.EventTarget(e) to see which one. | box: mouse over = (): dom.SetText(dom.ById("out"), "Over") end content = "Point at me" padding = 20 background = "#fef3c7" end
paragraph: id = "out" content = "-" end |
mouse outبیرون رفتن ماوس onmouseout | Runs when the pointer goes off the element or off one of its children. It bubbles, and it also fires when the pointer moves from the element onto its own child. | box: mouse out = (): dom.SetText(dom.ById("out"), "Out") end content = "Point at me, then move away" padding = 20 background = "#fef3c7" end
paragraph: id = "out" content = "-" end |
wheelچرخ ماوس onwheel | Runs when the mouse wheel turns or two fingers slide on a touchpad. The event property deltaY is negative when scrolling up and positive when scrolling down. dom.PreventDefault(e) stops the page from scrolling. | box: wheel = "event.preventDefault(); this.textContent = event.deltaY < 0 ? 'Up' : 'Down'" content = "Turn the wheel here" padding = 24 background = "#ede9fe" end |
Try it yourself
- Change the counter so that a double click adds ten and a click adds one. Watch the counter on a double click: what does it show? Why?
- Make the drawing board paint in a colour that depends on the button: left button purple, middle button green. Use
mouse downand thebuttonnumber. - Add a "score" for the click game that counts how many hits in a row you made without a miss, and show it in the paragraph.
- Give the lamp example a second button and make both buttons control the same lamp with one named function.