◐ Shell
reader mode source ↗
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

<body>

<input type="button" id="hider" value="Click to hide the text" />

<div id="text">Text</div>

<script>
// Here it doesn't matter how we hide the text,
// could also use style.display:
document.getElementById('hider').onclick = function() {
document.getElementById('text').hidden = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ importance: 5

---

# Hide on click

Add JavaScript to the `button` to make `<div id="text">` disappear when we click it.

The demo:

[iframe border=1 src="solution" height=80]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Can use `this` in the handler to reference "the element itself" here:

```html run height=50
<input type="button" onclick="this.hidden=true" value="Click to hide">
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Hide self

Create a button that hides itself on click.

```online
Like this:
<input type="button" onclick="this.hidden=true" value="Click to hide">
```
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
The answer: `1` and `2`.

The first handler triggers, because it's not removed by `removeEventListener`. To remove the handler we need to pass exactly the function that was assigned. And in the code a new function is passed, that looks the same, but is still another function.

To remove a function object, we need to store a reference to it, like this:

```js
function handler() {
Expand All @@ -13,4 +13,4 @@ button.addEventListener("click", handler);
button.removeEventListener("click", handler);
```

The handler `button.onclick` works independently and in addition to `addEventListener`.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

First we need to choose a method of positioning the ball.

We can't use `position:fixed` for it, because scrolling the page would move the ball from the field.

So we should use `position:absolute` and, to make the positioning really solid, make `field` itself positioned.

Then the ball will be positioned relatively to the field:

```css
#field {
Expand All @@ -16,36 +16,36 @@ Then the ball will be positioned relatively to the field:

#ball {
position: absolute;
left: 0; /* relative to the closest positioned ancestor (field) */
top: 0;
transition: 1s all; /* CSS animation for left/top makes the ball fly */
}
```

Next we need to assign the correct `ball.style.left/top`. They contain field-relative coordinates now.

Here's the picture:

![](move-ball-coords.svg)

We have `event.clientX/clientY` -- window-relative coordinates of the click.

To get field-relative `left` coordinate of the click, we can substract the field left edge and the border width:

```js
let left = event.clientX - fieldCoords.left - field.clientLeft;
```

Normally, `ball.style.left` means the "left edge of the element" (the ball). So if we assign that `left`, then the ball edge, not center, would be under the mouse cursor.

We need to move the ball half-width left and half-height up to make it center.

So the final `left` would be:

```js
let left = event.clientX - fieldCoords.left - field.clientLeft - ball.offsetWidth/2;
```

The vertical coordinate is calculated using the same logic.

Please note that the ball width/height must be known at the time we access `ball.offsetWidth`. Should be specified in HTML or CSS.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

<body style="height:2000px">

Click on a field to move the ball there.
<br>


Expand All @@ -39,29 +39,29 @@
<script>
field.onclick = function(event) {

// window-relative field coordinates
let fieldCoords = this.getBoundingClientRect();

// the ball has position:absolute, the field: position:relative
// so ball coordinates are relative to the field inner left-upper corner
let ballCoords = {
top: event.clientY - fieldCoords.top - field.clientTop - ball.clientHeight / 2,
left: event.clientX - fieldCoords.left - field.clientLeft - ball.clientWidth / 2
};

// prevent crossing the top field boundary
if (ballCoords.top < 0) ballCoords.top = 0;

// prevent crossing the left field boundary
if (ballCoords.left < 0) ballCoords.left = 0;


// // prevent crossing the right field boundary
if (ballCoords.left + ball.clientWidth > field.clientWidth) {
ballCoords.left = field.clientWidth - ball.clientWidth;
}

// prevent crossing the bottom field boundary
if (ballCoords.top + ball.clientHeight > field.clientHeight) {
ballCoords.top = field.clientHeight - ball.clientHeight;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

<body style="height:2000px">

Click on a field to move the ball there.
<br> The ball should never leave the field.


<div id="field">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ importance: 5

---

# Move the ball across the field

Move the ball across the field to a click. Like this:

[iframe src="solution" height="260" link]

Requirements:

- The ball center should come exactly under the pointer on click (if possible without crossing the field edge).
- CSS-animation is welcome.
- The ball must not cross field boundaries.
- When the page is scrolled, nothing should break.

Notes:

- The code should also work with different ball and field sizes, not be bound to any fixed values.
- Use properties `event.clientX/event.clientY` for click coordinates.
Original file line number Diff line number Diff line change
@@ -35,11 +35,11 @@
<body>

<div id="sweeties" class="menu">
<span class="title">Sweeties (click me)!</span>
<ul>
<li>Cake</li>
<li>Donut</li>
<li>Honey</li>
</ul>

</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
</head>
<body>

▶ ▼ Sweeties (click me)!
<ul>
<li>Cake</li>
<li>Donut</li>
<li>Honey</li>
</ul>

</body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ importance: 5

---

# Create a sliding menu

Create a menu that opens/collapses on click:

[iframe border=1 height=100 src="solution"]

P.S. HTML/CSS of the source document is to be modified.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

To add the button we can use either `position:absolute` (and make the pane `position:relative`) or `float:right`. The `float:right` has the benefit that the button never overlaps the text, but `position:absolute` gives more freedom. So the choice is yours.

Then for each pane the code can be like:
```js
pane.insertAdjacentHTML("afterbegin", '<button class="remove-button">[x]</button>');
```

Then the `<button>` becomes `pane.firstChild`, so we can add a handler to it like this:

```js
pane.firstChild.onclick = () => pane.remove();
Expand Down
Loading
Toggle all file notes Toggle all file annotations