-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1767 lines (1707 loc) · 93.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<html>
<head>
<style type="text/css">
#toc ul {
display: flex;
flex-wrap: wrap;
margin-left:0;
justify-content: flex-start;
background-color: darkslateblue;
padding:0
}
#toc li {
height: 1em;
list-style:none;
padding:10px;
background-color: darkslateblue;
color: white;
cursor:pointer;
}
#toc li:current {
background-color: slateblue;
}
#toc li:hover {
background-color: slateblue;
}
.blocklyHtml li {
display:inline-block;
list-style:none;
padding:5px;
cursor:pointer;
margin:2px;
}
.blocklyHtml li.current {
border-top: 1px solid black;
border-left: 1px solid black;
border-right: 1px solid black;
border-bottom: 1px solid white;
font-weight: bold;
}
.blocklyHtml li.notcurrent {
border: 1px solid black;
}
.blocklyHtml ul {
margin: 0px;
}
.generatedJsTextarea {
display: none;
}
body {
font-family: Helvetica, Arial, sans-serif;
}
.instructions {
margin-top:3em;
margin-left:2em;
max-width:50em;
font-size: 1.2em;
line-height: 1.5em;
}
.instructions li {
margin-top:0.8em;
}
.blockname {
background-color: lightgrey;
}
.runButton {
border: 1px dashed;
}
</style>
</head>
<body>
<script src="https://unpkg.com/blockly/blockly.min.js"></script>
<script src="blockly-dom.js"></script>
<script src="blockly-cyf.js"></script>
<script src="editor.js"></script>
<div id="toc"></div>
<div id="exercises">
<div class="exercise" id="introduction">
<h2>Introduction</h2>
<div class="instructions"><p>In this series of exercises, you will use <em>block-based programming</em>,
similar to what you used on code.org, to create javascript that dynamically modifies the html on a web page
("dynamically" means that as the program executes, the initial html will be modified).
</p>
<p>In this "Introduction", there is nothing for you to do, only information. You can move to the first exercise whenever you're ready.</p>
<ul>
<li>
Static html can be written in the html textarea ("static" means this is the original state,
before the program).
</li>
<li>
Code to modify the html can be written with blocks.
</li>
<li>
Clicking "run" will place the html in the space just below the textarea and execute
the generated code.
</li>
<li>
These exercises assume you are familiar with using the block-based programming environment,
based on having done the code.org exercises. You should be familiar with if
and loop blocks.
</li>
<li>
There are some differences with code.org. In particular, you are free to move to the next exercise
whenever you feel ready. At some point, grey checkmarks will indicate that your current code doesn't
appear to solve all the instructions, and green checkmarks will indicate that it does.
</li>
<li>
The blocks directly translate to javascript code. You can look at the resulting code in the
generated javascript textarea. It's not intended that you be able to understand this code at this point in the curriculum.
</li>
<li>
The end goal is to be able to copy paste the generated code into a
single .js file and add it, and the appropriate html, to the an html page
created during the fundamentals module.
</li>
<li>
The way the blocks work (and the code they generate) is deliberately similar to what you will learn
in the upcoming javascript modules. There are also some differences, intended to make it easier as
a first programming experience.
</li>
</ul>
<h3>Definitions</h3>
Some of the following may need a definition:
<ul>
<li>static vs dynamic</li>
<li>block based programming</li>
<li>html elements</li>
<li>html attributes</li>
<li>variable</li>
<li>array</li>
<li>function</li>
<li>function call</li>
<li>event handler? - not used, but would be convenient</li>
</ul>
</div></div>
<div class="exercise" id="exercise_change_text">
<h2>Modifying html dynamically: changing text</h2>
<script>
BlocklyTest.registerTest("exercise_change_text", () => {
let noun1 = BlocklyTest.findElement(["#noun1"]);
let noun2 = BlocklyTest.findElement(["#noun2"]);
let verb = BlocklyTest.findElement(["#verb"]);
let adjective = BlocklyTest.findElement(["#adjective"]);
BlocklyTest.expect(1, "first noun was changed", noun1, (noun1) => {
return noun1.innerText.toLowerCase() !== "dog";
});
BlocklyTest.expect(2, "all words were changed", noun1, (noun1) => {
return (
noun1.innerText.toLowerCase() !== "dog" &&
noun2.innerText.toLowerCase() !== "cat" &&
adjective.innerText.toLowerCase() !== "white" &&
verb.innerText.toLowerCase() !== "saw"
)
});
});
</script>
<div class="instructions">
<p>
This exercise introduces the <b>Html blocks</b> to find and modify the text of html elements.
</p>
<ol>
<li>Let's start with the html below in the static html area. It represents a sentence with holes (also known as <a href="https://en.wikipedia.org/wiki/Mad_Libs">Mad Libs</a>).
<ol>
<li><code class="start_code"><p>The <u id="noun1">dog</u> <u id="verb">saw</u> the <u id="adjective">white</u> <u id="noun2">cat</u></p></code></li>
<li>you can click "run" to see the output</li>
</ol>
<li>Let's modify the contents of the first <code><u></code> element to contain the word "mouse" instead of "dog".
<ol>
<li>Add an <span class="blockname">"at the start"</span> block</li>
<li>Inside this block, add a <span class="blockname">"find the element using css selector"</span> block using the css selector for the id of the first <u> element (<code>#noun1</code>)</li>
<li>Inside this block, add a <span class="blockname">"set the text content to"</span> block</li>
<li>Set the value for the text of this block: <code>mouse</code></li>
<li id="exercise_change_text_1">Click "run" to check the content has changed.</li>
</ol>
</li>
<li id="exercise_change_text_2">Can you modify the contents of the other three <code><u></code> elements? If you can't think of some words, you can use the <span class="blockname">"get a random word"</span> block from the Values menu</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="text"></block>
<block type="get_randomWord"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="with_element_by_selector"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_set_colours">
<h2>Modifying html dynamically: setting colours</h2>
<script>
BlocklyTest.registerTest("exercise_set_colours", () => {
let firstLi = BlocklyTest.findElement(["#banana", "li:nth-child(1)"]);
let startColor = window.getComputedStyle(firstLi).color;
BlocklyTest.expect(1, "colour was changed", firstLi, (li) => {
return window.getComputedStyle(li).color != startColor;
})
let startBackgroundColor = window.getComputedStyle(firstLi).backgroundColor;
BlocklyTest.expect(2, "background colour was changed", firstLi, (li) => {
return window.getComputedStyle(li).backgroundColor != startBackgroundColor;
})
if (firstLi) {
BlocklyTest.expect(3, "all colours are changed", firstLi.parentElement, (ul) => {
return ul.children.length > 1 && Array.from(ul.children).every((li) => window.getComputedStyle(li).color != startColor);
})
}
});
</script>
<div class="instructions">
<p>
Not only can we modify the contents of html elements, we can also change their properties, such as their colour. Different kinds of <b>Values blocks</b> provide ways of setting texts, numbers and colours.
</p>
<ol>
<li>Let's start with an html list of our favourite fruit in the "Static html"
<ol>
<li>each html list item (<code><li></code>) has a different id attribute so that we can refer to it using a css selector</li>
<li>for example: <code class="start_code"><ul><br><li id="banana">Banana</li><br><li id="apple">Apple</li><br><li id="strawberry">Strawberry</li><br></ul></code></li>
<li>you can click "run" to see the output</li>
</ol>
<li>Color the banana yellow
<ol>
<li>Add an <span class="blockname">"at the start"</span> block</li>
<li>Inside this block, add a <span class="blockname">"find the element using css selector"</span> block using the id selector for the <li> element for Banana (<code>#banana</code>)</li>
<li id="exercise_set_colours_1">Inside this block, add a <span class="blockname">"set the attribute"</span> block, pick "color" and set the value to any yellow colour using the <span class="blockname">colour picker</span> (you can find a color picker block in the "Values" menu).</li>
<li id="exercise_set_colours_2">The colour for a banana is probably not easy to see against a white background. Add a second <span class="blockname">"set the attribute"</span> block and set a dark color for the background.</li>
<li>Click "run" to check the output looks like
<ul style="background-color: azure;">
<li style="color:rgb(233, 233, 22);background-color: darkgrey;">Banana</li>
<li>Orange</li>
</ul>
</li>
</ol>
</li>
<li id="exercise_set_colours_3">Repeat the process above to colour each of the fruit (hint: you can add multiple <span class="blockname">"find the element using css selector"</span> blocks one after the other). You can also change the background color if you like</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="with_element_by_selector"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_add_fruit">
<h2>Creating html dynamically: lists of fruit</h2>
<script>
BlocklyTest.registerTest("exercise_add_fruit", () => {
let ul = BlocklyTest.findElement(["#list", "ul", "ol"]);
let startLiCount = 0;
if (ul) {
startLiCount = ul.children.length;
}
BlocklyTest.expect(1, "Banana is added dynamically as the second item", ul, (ul) => {
if (startLiCount !== 2 && !ul.children.length == 2) return false;
return ul.children.item(1).innerText == "Banana" || ul.children.item(1).innerText == "banana"
})
BlocklyTest.expect(2, "There are at least 4 items", ul, (ul) => {
return ul.children.length >= 4
})
});
</script>
<div class="instructions">
<p>
Not only can we modify existing html elements, we can also create new ones and set their text and properties.
</p>
<ol>
<li>Let's start with an html list with a single apple in the "Static html"
<ol>
<li>Note the list has an id ("list") so that we can refer to it using a css selector.</li>
<li>for example: <code class="start_code"><ul id="list"><br><li>Apple</li><br></ul></code></li>
</ol>
<li>Add one more fruit dynamically
<ol>
<li>Add an <span class="blockname">"at the start"</span> block</li>
<li>Inside this block, add a <span class="blockname">"find the element using css selector"</span> block using the id for the ul element (<code>#list</code>)</li>
<li>Inside this block, add a <span class="blockname">"create a new ... element"</span> block and select "<li>"</li>
<li>Inside this block, add a <span class="blockname">"set the text content"</span> block and set the value to "Banana"</li>
<li id="exercise_add_fruit_1">Click "run" to check the output looks like
<ul style="background-color: azure;">
<li>Apple</li>
<li>Banana</li>
</ul>
</li>
</ol>
</li>
<li id="exercise_add_fruit_2">Repeat the process above to add two more of your favourite fruit (hint: you can add multiple <span class="blockname">"create a new ... element"</span> blocks one after the other)</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_list_links">
<h2>Creating html dynamically: lists of links</h2>
<script>
BlocklyTest.registerTest("exercise_list_links", () => {
let ul = BlocklyTest.findElement(["#list", "ul", "ol"]);
let startLiCount = 0;
if (ul) {
startLiCount = ul.children.length;
}
BlocklyTest.expect(1, "There are 3 links with href attributes", ul, (ul) => {
var lis = Array.from(ul.querySelectorAll("li"));
return startLiCount != 3 && lis.length == 3 && lis.every((li) => li.querySelector("a[href]") && li.querySelector("a[href]").innerText);
})
});
</script>
<div class="instructions">
<p>
This exercise consolidates the use of the blocks we learned about in the previous exercises.
</p>
<ol>
<li>Start with an empty unordered html list (<code class="start_code"><ul id="list"></ul></code>) in the static html.
<li>Dynamically add your favourite links to the html list
<ol>
<li>Find the URLs of your three favourite websites (they look something like: <code>http://www.codeyourfuture.io</code>)</li>
<li>Use the blocks we have seen so far ("at the start", "find the element using css selector", "create a new ... element", "set the attribute", "set the text content", and the Values blocks)</li>
<li>Hint: you will need to create an <code><a></code> inside of each <code><li></code></li>
<li>Hint: remember that to set the target of an <code><a></code> you can use the <code><href></code> attribute. Without this attribute, your link will not <i>look</i> like a link</li>
<li>Note about problem solving: The less blocks you add before clicking "run", the more you can be sure the code you have so far does what you expect. How could you break your solution down into small chunks where you can test at each stage by clicking "run"?</li>
<li id="exercise_list_links_1">Click "run" to check the output looks something like
<ul style="background-color: azure;">
<li><a href="http://www.codeyourfuture.io">Code your future</a></li>
<li><a href="http://www.google.com">Google</a></li>
<li><a href="http://news.bbc.co.uk">BBC News</a></li>
</ul>
</li>
</ol>
</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_button_add">
<h2>Buttons and clicks: A button to add apples</h2>
<script>
BlocklyTest.registerTest("exercise_button_add", () => {
let ul = BlocklyTest.findElement(["#list", "ul", "ol"]);
let button = BlocklyTest.findElement(["#button", "button:nth-of-type(1)"]);
let button2 = BlocklyTest.findElement(["#button2", "button:nth-of-type(2)"]);
BlocklyTest.expectAfterClick(1, "The button adds an apple", button,
() => {
let count = ul ? ul.children.length : 0;
return count;
},
(countBefore, countAfter) => {
let addsExactlyOneChild = countBefore + 1 == countAfter
var lastLi = ul.lastChild;
return (addsExactlyOneChild && lastLi.innerText.toLowerCase() == "apple");
});
BlocklyTest.expectAfterClick(2, "The second button removes all apples", button2,
() => {
let count = ul ? ul.children.length : 0;
return count;
},
(countBefore, countAfter) => countBefore > 0 && countAfter == 0);
});
</script>
<div class="instructions">
<p>
Javascript is often "event-driven". This means it is run in when the user interacts with the page (clicking, typing, etc.). Let's make it so every time we (as a "user") click on an "add an apple" button, it adds an apple to the list.
</p>
<ol>
<li>Start with an empty unordered html list (<code><ul></code>) and a button to add apples to the list (<code><button></code>) in the static html.
<ol>
<li>for example: <code class="start_code"><ul id="list"></ul><br><button id="button">add an apple</button></code></li>
</ol>
<li>When we click on the "add an apple" button, let's add an apple to the list
<ol>
<li>Add a <span class="blockname">"when the element with id ... is clicked"</span> block (it doesn't need to be connected to any other blocks)</li>
<li id="exercise_button_add_1">Inside this block, add the blocks necessary to find the "list" element, create a new "li" element and set the content to "apple" (you know how to do this from previous exercises)</li>
</ol>
</li>
<li id="exercise_button_add_2">Can you add a second button (in the static html, with a different id) that removes all the apples (you can do this by using the <span class="blockname">"remove the contents of the element"</span> block).
</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_button_input">
<h2>Inputs and clicks: say something</h2>
<div class="instructions">
<p>
We can also get user input when a button is clicked. Let's have the browser say a word or sentence that the user enters.
</p>
<ol>
<li>Start with a text input box list (<code><input /></code>) and a button to that says "speak" in the static html.
<ol>
<li>for example: <code class="start_code"><input id="text" /><br><button id="button">speak</button></code></li>
</ol>
</li>
<li>We want to do two things in order when the button is clicked. First we get the value entered by the user, then we pass it to a block that will say it out loud. A common strategy in problem solving for programming is to solve the visible (or in this case, audible) thing first: have the browser say something.
<ol>
<li>Add a <span class="blockname">"when the element with id ... is clicked"</span> block</li>
<li>Inside this block, add a <span class="blockname">"say"</span> block from the Values menu</li>
<li>As input to this block, connect a <span class="blockname">"get a random word"</span> block</li>
<li>Check that a random word gets said when you click "speak"</li>
</ol>
</li>
<li>Now that we know a word gets said out loud when we click the button, we can make it be the one from the input box.
<ol>
<li>Inside the <span class="blockname">"when the element with id ... is clicked"</span> block, add a <span class="blockname">"find the element using css selector"</span> block to find the input (<code>#text</code>)</li>
<li>Move the <span class="blockname">"say"</span> block inside this new block</li>
<li>Replace the <span class="blockname">"get a random word"</span> block with a <span class="blockname">"get the <input> element's value"</span> block</li>
<li>Check that whatever word you write in the input box gets said when you click "speak"</li>
</ol>
</li>
<li>Do you see why it was useful to solve this problem in reverse order?</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
<block type="text_to_speech"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_button_consolidation">
<h2>Buttons and clicks consolidation</h2>
<div class="instructions">
<p>
Anything that we could do previously as soon as run is clicked, we can now do as a response to clicking buttons or other elements in the static html.
</p>
<ol>
<li id="exercise_button_consolidation_4">Place the sentence from the first exercise in the static html, but this time with <button> elements around the words to be filled in (<code class="start_code"><p>The <button id="noun1">dog</button> <button id="verb">saw</button> the <button id="adjective">white</button> <button id="noun2">cat</button></p></code>). Make it so each button's text gets set to a random word when it is clicked?</li>
<li id="exercise_button_consolidation_1">Place two buttons ("day mode" and "night mode") and an html list in the static html. Can you add blocks so that when the buttons are clicked, the html list changes to "day mode" (dark text on a light background) and "night mode" (light text on a dark background)?</li>
<li id="exercise_button_consolidation_2">Place a button in the static html. Can you add blocks so it changes colour when it is clicked?</li>
<li id="exercise_button_consolidation_3">Place an image in the static html. Can you add blocks so it changes when it is clicked?</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
</category>
</xml>
</div>
<div class="exercise" id="exercise_button_variables_state">
<h2>Variables: keeping track of the number of clicks</h2>
<div class="instructions">
<p>
A variable is a name into which a value can be stored. There are several reasons for which we might want to do this. The first is when we want to keep track of a value that changes over time. Let's keep track of the number of times a button is clicked.
</p>
<ol>
<li>Start with a button (<code><button></code>) that has been clicked 0 times in the static html. <code class="start_code"><button id="button">0</button></code></li>
<li>Add an <span class="blockname">"at the start"</span> block. Inside we are going to add a variable that will keep track of the number of times the button was clicked.</li>
<ol>
<li>In the Variables menu, click "create variable..." to create a variable called <code>click_count</code></li>
<li>From the Variables menu, create a <span class="blockname">"set click_count to"</span> block and place it inside the <span class="blockname">"at the start"</span></li>
<li>Set the value to 0 (from the Values menu)</li>
</ol>
</li>
<li>When the button is clicked, we are going to do two things: increase the value of <code>click_count</code> by 1; and change the text of the button to the new value of click_count.</li>
<ol>
<li>Add an <span class="blockname">"when the element with id ... is clicked"</span> block. </li>
<li>Inside this block, add a <span class="blockname">"change click_count by 1"</span> block from the Variables menu.</li>
<li>Add the necessary blocks to set the text content of the button to the value of <code>click_count</code>. (You can get this value by selecting the <span class="blockname">"click_count"</span> block from the Variables menu)</li>
</ol>
</li>
</ol>
<p>Note that it will be a common pattern that you first set a variable in the <span class="blockname">"at the start"</span> block and then modify it in at <span class="blockname">"when the element with id ... is clicked"</span> block. This first setting of the variable is called</p>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
<block type="get_value"></block>
</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
</xml>
</div>
<div class="exercise" id="exercise_button_variables_store">
<h2>Variables: keeping track of the number of clicks</h2>
<div class="instructions">
<p>
Another reason for which we might want to use a variable is when we want to do things with multiple html elements at the same time.
For example take the value from an <code><input></code> element and set it as the text of a new <li> element. We're going to create a list of things to do.
</p>
<ol>
<li>Start with an empty list, an input, and a button "add Todo Item" in the static html. <code class="start_code"><p>Things to do:</p><br><ul id="list"></ul><br><input id="text" /><br><button id="button">add Todo Item</button></code></li>
<li>When the button is clicked, we are going to do two things: get the value of the input box and store it in a variable; and add a new <code><li></code> with that value to the list. To do the visible outcome first, we're going to do these in reverse order.</li>
<ol>
<li>Add an <span class="blockname">"when the element with id ... is clicked"</span> block.</li>
<li>First find the list element (<code>#list</code>) and add a new <code><li></code> with an arbitrary text value (for example "do cyf homework"). Check that this works.</li>
<li>In the Variables menu, click "create variable..." to create a variable called <code>new_todo</code></li>
<li>Before the code to add the new <li>, add code to find the text input element and set the <code>new_todo</code> variable to the content of this input.</li>
<li>Last, replace the arbitrary content of the new <code><li></code> with the value of the variable.</li>
</ol>
</li>
</ol>
<p>The last (but most important) reason to have variables is that their names are often very useful to help us understand what our code is doing.</p>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
<block type="get_value"></block>
</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
</xml>
</div>
<div class="exercise" id="exercise_button_variables_consolidation">
<h2>Variables consolidation: counting sheep</h2>
<div class="instructions">
<p>
Let's put our different uses of variables together. We would like to track how many times the user adds the word "sheep" and how many times they add any other word.
</p>
<ol>
<li>Let's start with the following static html. <code class="start_code"><p>There have been <span id="sheep_count">0</span> sheep 🐑 and <span id="other_count">0</span> others.</p><br><input id="text" /><br><button id="button">add animal</button></code></li>
<li>The following things should happen (use variables where necessary to keep track of various values, and the blocks you need from the Logic menu). Don't forget to break down your implementation into steps where you first add blocks that make a visible difference and test that it works.</li>
<ol>
<li>When the user clicks "add animal", if the word in the text input is "sheep", the number of sheep displayed in the <code><span></code> with id <code>sheep_count</code> should increase by one.</li>
<li>When the user clicks "add animal", if the word in the text input is not sheep, the number displayed in the <code><span></code> with id <code>other_count</code> should increase by one.</li>
<li>(we don't have any way currently to check if the word in the text input is actually an animal - we'll fix this in a few exercises)</li>
</ol>
</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Logic" colour="210">
<block type="controls_if"></block>
<block type="logic_negate"></block>
<block type="logic_compare"></block>
</category>
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
<block type="get_value"></block>
</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
</xml>
</div>
<div class="exercise" id="exercise_arrays_random">
<h2>Arrays: Mad Libs revisited</h2>
<div class="instructions">
<p>When we did the first Mad Libs exercise, we weren't able to make our own list of words to choose from but could only pick a category (noun, adjective, verb).
We will now introduce a data structure called an <b>Array</b>, that represents a list of data (typically numbers or texts) in javascript.
They can be created and used from the "Arrays" menu. Let's create our own list of words to select from.
</p>
<ol>
<li>Start with a Mad Libs sentence similar to before (<code class="start_code"><p>The <u id="noun">man</u> <u id="verb">saw</u> the <u id="adjective">white</u> <u id="animal">cat</u></p></code></li>
<li>Add an <span class="blockname">"at the start"</span> block</li>
<li>We'll now create an array of animals and assign it to a variable <ol>
<li>From the "Arrays" menu, add a <span class="blockname">"Set ... to, create array with"</span> block to the <span class="blockname">"at the start"</span> block</li>
<li>Rename the variable <span class="variablename">"array"</span> to "animals"</li>
<li>Add at least 3 animal text values to this array</li>
<li>Note: You can click on the gear icon at the top left of the <span class="blockname">"create array with"</span> block to add and remove slots for values</li>
</ol></li>
<li>Let's set the text of the <code><u id="animal"></code> to a random animal.<ol>
<li>You already know how to do most of the steps (find the element with id animal, set its text content)</li>
<li>The thing we will do differently is to set the text content to a <span class="blockname">get a random item from array</span> block, selecting the "animals" array in the dropdown.</li>
<li>Click "run" several times to check you get a random animal from your array each time.</li>
</ol></li>
<li>Create additional arrays from which to select random words for each slot to be filled and share the result with your cohort.</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
<block type="element_clicked_current"></block>
<block type="with_elements_by_selector"></block>
</category>
<category name="Arrays" colour="%{BKY_LISTS_HUE}">
<block type="variables_set">
<field name="VAR">array</field>
<value name="VALUE">
<block type="lists_create_with">
</block>
</value>
</block>
<block type="get_randomMember">
<value name="ARRAY">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
</xml>
</div>
<div class="exercise" id="exercise_arrays_foreach">
<h2>Arrays and loops</h2>
<script>
BlocklyTest.registerTest("exercise_arrays_foreach", () => {
let ul = BlocklyTest.findElement(["#list", "ul", "ol"]);
let list = BlocklyTest.findArrayValues(0); // first of the arrays is the one we want
BlocklyTest.expect(1, "One element is shown", ul, (ul) => {
var lis = Array.from(ul.querySelectorAll("li"));
return lis.length > 0 && lis[0].innerText == list[0];
});
BlocklyTest.expect(2, "As many elements are shown as there are items in the array", ul, (ul) => {
var lis = Array.from(ul.querySelectorAll("li"));
return lis.length == list.length;
});
BlocklyTest.expect(3, "All the elements in the array (at least 3) are in the html list", ul, (ul) => {
var lis = Array.from(ul.querySelectorAll("li"));
return list.length >= 3 && lis.length == list.length && lis.every((li, index) => li.innerText == list[index]);
});
BlocklyTest.expect(4, "All the elements in the array (at least 4) are in the html list", ul, (ul) => {
var lis = Array.from(ul.querySelectorAll("li"));
return list.length >= 4 && lis.length == list.length && lis.every((li, index) => li.innerText == list[index]);
});
});
</script>
<div class="instructions">
<p>In this series of exercises, we have so far used one <span class="blockname">"create a new ... element"</span> for each <code><li></code> we want to create.
Another use for an array is when we want to do the same thing with each element in an array (for example, create a <code><li></code>).
</p>
<ol>
<li>Start with an empty unordered html list with the id "list" (<code class="start_code"><ul id="list"></ul></code>) in the static html.</li>
<li>Add an <span class="blockname">"at the start"</span> block</li>
<li>We'll now create an array of fruits and assign it to a variable <ol>
<li>From the "Arrays" menu, add a <span class="blockname">"Set ... to, create array with"</span> block to the <span class="blockname">"at the start"</span> block</li>
<li>Rename the variable <span class="variablename">"array"</span> to "fruits"</li>
<li>Add at least 3 fruit text values to this array</li>
</ol></li>
<li>Let's do the first steps to convert the first entry in this array into <code><li></code><ol>
<li>You already know how to do most of the steps (find the element with id list, create an li, set its text content)</li>
<li>The thing we will do differently is to set the text content to a <span class="blockname">get the first item from the array</span> block, selecting the "fruits" array in the dropdown.</li>
<li id="exercise_arrays_foreach_1">Click "run" to check you are displaying a list with one fruit</li>
</ol></li>
<li>Let's use this same code to show all the fruits<ol>
<li>At the beginning of the <span class="blockname">"find the element using css selector"</span> block, insert a <span class="blockname">"for each item in array"</span> block. Select the fruits array in the dropdown.</li>
<li>Move all of the <span class="blockname">"create a new ... element"</span> block inside the for <span class="blockname">"for each item in array"</span> block</li>
<li id="exercise_arrays_foreach_2">As you can see by clicking "run", you now have a list with multiple items - but they are all the first item in the array</li>
<li>Inside the loop, you have a variable available called <span class="variablename">"item"</span>. Each time through the loop, this variable will take on the value of the next fruit in the array</li>
<li>Replace the <span class="blockname">get the first item from the array</span> block with a "item" variable block (you can find it in the Variables menu)</li>
<li id="exercise_arrays_foreach_3">Check by clicking run that you now have a list with each item of fruit in your array.</li>
<li>If you have an array called "fruits", it's good practice to rename the loop "item" variable to "fruit".</li>
</ol></li>
<li id="exercise_arrays_foreach_4">Add another fruit to your array and check that all your fruits are still shown.</li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>
<block type="text"></block>
<block type="colour_picker"></block>
<block type="logic_boolean"></block>
</category>
<category name="Html" colour="%{BKY_COLOUR_HUE}">
<block type="on_start"></block>
<block type="element_clicked"></block>
<block type="with_element_by_selector"></block>
<block type="add_element"></block>
<block type="set_content">
<value name="VALUE">
<shadow type="text"> </shadow>
</value>
</block>
<block type="set_attribute"></block>
<block type="remove_contents"></block>
<block type="element_clicked_current"></block>
<block type="with_elements_by_selector"></block>
</category>
<category name="Arrays" colour="%{BKY_LISTS_HUE}">
<block type="variables_set">
<field name="VAR">array</field>
<value name="VALUE">
<block type="lists_create_with">
</block>
</value>
</block>
<block type="arrays_getFirst">
<value name="VALUE">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
<block type="arrays_push">
<value name="LIST">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
<block type="lists_isEmpty">
<value name="VALUE">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
<block type="arrays_forEach">
<field name="VAR">item</field>
</value>
<value name="LIST">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
<block type="get_sum">
<value name="ARRAY">
<block type="variables_get">
<field name="VAR">array</field>
</block>
</value>
</block>
</category>
<category name="Variables" colour="330" custom="VARIABLE"></category>
</xml>
</div>
<div class="exercise" id="exercise_arrays_sum">
<h2>Arrays: Don't go higher than 11!</h2>
<div class="instructions">
<p>[A simpler version of this exercise is needed to learn only adding/pushing and summing, maybe with values from the input box, and this can come later as the first "project". When this change is made a lot of instructions can be simplified to remove the detailed scaffolding]</p><p>We are now going to learn how to add items to (and remove items from) an array, and how to calculate the sum of an array of numbers. We're going to create a game where you roll dice and your goal is to not total more than 11.
</p>
<ol>
<li>Start with an empty list (where we will display our rolls), a place to put a total, and a few buttons (<code class="start_code"><p>So far you have rolled:</p><br><ul id="list"></ul><br><button id="button_roll">Roll the dice</button><br><p>Total: <span id="total">0</span>. <span id="info">Keep playing!</span></p><br><button id="button_remove">Remove the last roll</button><br><button id="button_restart">Start again</button></code></li>
<li>The game has the following requirements. Before reading further, how would you break down and implement these requirements into steps? Think through what steps need to happen after each button click. In what order would you implement these steps so as to test each step as early as possible?<ul>
<li>When "roll the dice" is clicked, a new random number between 1 and 6 should be generated and added</li>
<li>If the total of all the dice rolls is exactly 11, display "You won" in the <code><span id="info"></code></li>
<li>If the total of all the dice rolls is over 11, display "You lost" in the <code><span id="info"></code></li>
<li>When "remove the last roll" is clicked, we should undo the last roll (this is a cheat button so that we can always win!)</li>
<li>The list should display all the rolls so far</li>
<li>The total so far should be displayed in the <code><span id="total"></code></li>
<li>When "start again" is clicked, we should return to the initial state</li>
</ul></li>
<li>
The following steps are needed. Notice that some of them repeat, some of them are similar, and that the game has a "state" which is the array of dice rolls. <ul>
<li>At the beginning: <ol>
<li>Display each roll in the array (there are currently no rolls)</li>
<li>Display the total of all rolls (it is currently 0)</li>
</ol></li>
<li>When "roll the dice" is clicked: <ol>
<li>Pick a random number between 1 and 6</li>
<li>Add that number to the array of rolls</li>
<li>Display each roll in the array</li>
<li>Calculate the total of all rolls<ul>
<li>If it is greater than 11, display "You lost"</li>
<li>If it is equal to 11, display "You won"</li>
</ul></li>
<li>Display the total of all rolls</li>
</ol></li>
<li>When "Start again" is clicked: (this is the same as at the beginning)<ol>
<li>Display each roll in the array (there are currently no rolls)</li>
<li>Display the total of all rolls (it is currently 0)</li>
</ol></li>
<li>When "Remove the last roll" is clicked: <ol>
<li>Remove the last roll from the array of rolls</li>
<li>Display each roll in the array</li>
<li>Calculate the total of all rolls<ul>
<li>If it is greater than 11, display "You lost"</li>
<li>If it is equal to 11, display "You won"</li>
<li>If it is less than 11, display "Keep playing"</li>
</ul></li>
<li>Display the total of all rolls</li>
</ol></li>
</ul></li>
<li>In order to check that anything is working, we need to be able to display an array of rolls and its total, so that's where we will start. <ol>
<li>In an <span class="blockname">"At the start"</span> block, create an array called "rolls" and put 3 numbers in the array (afterwards we will start with an empty array, but for now having numbers helps)</li>
<li>Using a loop, display each of the numbers in the array in the list (you know how to do this from previous exercises). Check that your code works.</li>
<li>Using the <span class="blockname">"get the sum of the numbers in array"</span> block, set the <code><span id="total"></code> to that value.</li>
<li>We will put in the "you won"/"you lost"/"keep playing" logic in last (but you could also do it now if you like)</li>
</ol></li>
<li>Next, let's go with the simplest: the restart button <ol>
<li>Add a <span class="blockname">"When the element with id ... is clicked"</span> block for this button</li>
<li>We want to set the "rolls" variable to an empty list (Use the same blocks as you did to initialise the rolls variable, then use the gear icon to remove all the items from the array)</li>
<li>We now want to remove the displayed rolls from the list (You will need to use the <span class="blockname">"Remove the contents of the element"</span> block)</li>
<li>And we want to set the text <code><span id="total"></code> to 0</li>
</ol></li>
<li>Slightly more tricky: the "roll the dice" button. Before following the instructions, can you think how we could create a dice?<ol>
<li>To create a dice, we'll create a new array in the <span class="blockname">"At the start"</span> block, called "dice" (be careful to select the "array" variable, not the "rolls" variable before renaming to "dice"), setting the values as the numbers 1, 2, 3, 4, 5, and 6. We can select a random item from this array when we want to roll a dice.</li>
<li>Add a <span class="blockname">"When the element with id ... is clicked"</span> block for the button</li>
<li>Let's roll the dice and add the result to the list. Use the <span class="blockname">"add ... to the start/end of the array"</span>, setting the "end" of the "rolls" array, and using a <span class="blockname">"get random item from the array"</span> block as the value.</li>
<li>We could now add a new <code><li></code> to the list and set the total. Instead, we are going to re-display the whole list - you will see why in the next step</li>
<li>To re-display the whole list (and set the total), we need a combination of the two previous steps: find the list, remove its contents, loop over the items in the array and add them to the list, set the total to the sum of the array.</li>
</ol></li>
<li>Notice that at this point, we have 3 different versions of the same steps to display the list contents and total. Now imagine we want to change something (like add the "you won"/"you lost"/"keep playing" information). We would have to add it in 3 different places! (And we still have a "remove last roll" button to implement - so it would be 4 places)<ol>
<li>We can actually write this code so that is exactly the same all the times (looping over an empty array will do nothing, and it's sum will be 0). When we see a piece of code we would like to use multiple times, we create a function.</li>
<li>From the Functions menu, select a <span class="blockname">"To <i>do something</i>"</span> block and call it "to <i>display the rolls</i>"</li>
<li>Take all the display code you wrote in the previous step and move it to inside this function.</li>
<li>In the Functions menu, there is now a <span class="blockname">"display the rolls"</span> block. You can us it as a replacement for the code you just moved. That block will "call" the function you created (this means it will execute all the blocks inside that function)</li>
<li>You can replace the 2 other versions of your display code with the <span class="blockname">"display the rolls"</span> block.</li>
</ol></li>
<li>Now you can add the logic that decides what to put into the <code><span id="info"></code>. <ol>
<li>Hint: You can calculate the sum of the array only once and store the result in a variable.</li>
<li>Hint: You can add else if and else conditions to the <span class="blockname">"if"</span> block by clicking on the gear icon.</li>
<li>To test all the logic, put different values into the initial rolls array. Once this is working, you can set the initial rolls array to an empty list.</li>
</ol></li>
<li>Last it's time to create our "cheat" functionality, the "Remove the last roll" button.<ol>
<li>You already know how to do everything except removing the last item from the array</li>
<li>From the arrays menu take a <span class="blockname">"get the first item from the array"</span> block.</li>
<li>Change the dropdowns to "remove" and "last", to remove the last roll</li>
<li>Don't for get to call the <span class="blockname">"display the rolls"</span> function!</li>
</ol></li>
</ol>
</div>
<xml class="toolbox" style="display: none">
<category name="Logic" colour="210">
<block type="controls_if"></block>
<block type="logic_negate"></block>
<block type="logic_compare"></block>
</category>
<category name="Values" colour='%{BKY_TEXTS_HUE}'>
<block type="math_number"></block>