pxt-microbit 7.1.23 → 7.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/built/sim.d.ts CHANGED
@@ -817,17 +817,22 @@ declare namespace pxsim.visuals {
817
817
  private microphoneLed;
818
818
  private systemLed;
819
819
  private antenna;
820
+ private antennaInitialized;
820
821
  private rssi;
821
822
  private lightLevelButton;
822
823
  private lightLevelGradient;
824
+ private lightLevelInitialized;
823
825
  private lightLevelText;
824
826
  private thermometerGradient;
825
827
  private thermometer;
828
+ private thermometerInitialized;
826
829
  private thermometerText;
827
830
  private soundLevelGradient;
828
831
  private soundLevel;
832
+ private soundLevelInitialized;
829
833
  private soundLevelText;
830
834
  private shakeButton;
835
+ private shakeInitialized;
831
836
  private shakeText;
832
837
  private accTextX;
833
838
  private accTextY;
@@ -868,6 +873,14 @@ declare namespace pxsim.visuals {
868
873
  findParentElement(): SVGSVGElement;
869
874
  private updateTilt;
870
875
  private buildDom;
876
+ private buildAntennaElement;
877
+ private buildSoundLevel;
878
+ private buildThermometerElement;
879
+ private buildLightLevelElement;
880
+ private buildHeadElement;
881
+ private buildPinElements;
882
+ private buildShakeElement;
883
+ private buildButtonElements;
871
884
  private updateHardwareVersion;
872
885
  private positionV2Elements;
873
886
  private attachEvents;
package/built/sim.js CHANGED
@@ -4088,6 +4088,7 @@ var pxsim;
4088
4088
  outline: none;
4089
4089
  }
4090
4090
  *:focus .sim-button-outer,
4091
+ .sim-antenna-outer:focus,
4091
4092
  .sim-pin:focus,
4092
4093
  .sim-thermometer:focus,
4093
4094
  .sim-shake:focus,
@@ -4142,6 +4143,11 @@ path.sim-board {
4142
4143
  "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20",
4143
4144
  "GND0", "GND", "+3v3", "GND1"
4144
4145
  ];
4146
+ const pinDrawOrder = [
4147
+ "P3", "P0", "P4", "P5", "P6", "P7", "P1", "P8", "P9", "P10", "P11",
4148
+ "P12", "P2", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20",
4149
+ "GND0", "GND", "+3v3", "GND1"
4150
+ ];
4145
4151
  const pinTitles = [
4146
4152
  "P0, ANALOG IN",
4147
4153
  "P1, ANALOG IN",
@@ -4168,6 +4174,11 @@ path.sim-board {
4168
4174
  ];
4169
4175
  const MB_WIDTH = 500;
4170
4176
  const MB_HEIGHT = 408;
4177
+ const LIGHT_LEVEL_BUTTON_POSITION_Y = 50;
4178
+ const LIGHT_LEVEL_BUTTON_RADIUS = 35;
4179
+ const ANTENNA_X = 380;
4180
+ const ANTENNA_WAVE_PERIOD_X = 18;
4181
+ const ANTENNA_WAVE_COUNT = 5;
4171
4182
  visuals.themes = ["#3ADCFE", "#FFD43A", "#3AFFB3", "#FF3A54"].map(accent => {
4172
4183
  return {
4173
4184
  accent: accent,
@@ -4204,6 +4215,11 @@ path.sim-board {
4204
4215
  constructor(props) {
4205
4216
  this.props = props;
4206
4217
  this.headInitialized = false;
4218
+ this.antennaInitialized = false;
4219
+ this.lightLevelInitialized = false;
4220
+ this.thermometerInitialized = false;
4221
+ this.soundLevelInitialized = false;
4222
+ this.shakeInitialized = false;
4207
4223
  this.pinNmToCoord = {};
4208
4224
  this.domHardwareVersion = 1;
4209
4225
  this.moveHeadingOnClick = (ev) => {
@@ -4285,8 +4301,7 @@ path.sim-board {
4285
4301
  else {
4286
4302
  pxsim.svg.fills(this.heads.slice(1), theme.accent);
4287
4303
  }
4288
- if (this.shakeButton)
4289
- pxsim.svg.fill(this.shakeButton, theme.virtualButtonUp);
4304
+ pxsim.svg.fill(this.shakeButton, theme.virtualButtonUp);
4290
4305
  this.pinGradients.forEach(lg => pxsim.svg.setGradientColors(lg, theme.pin, theme.pinActive));
4291
4306
  pxsim.svg.setGradientColors(this.lightLevelGradient, theme.lightLevelOn, theme.lightLevelOff);
4292
4307
  pxsim.svg.setGradientColors(this.thermometerGradient, theme.ledOff, theme.ledOn);
@@ -4353,8 +4368,9 @@ path.sim-board {
4353
4368
  }
4354
4369
  updateGestures() {
4355
4370
  let state = this.board;
4356
- if (state.accelerometerState.useShake && !this.shakeButton) {
4357
- this.shakeButton = pxsim.svg.child(this.g, "circle", { cx: 404, cy: 115, r: 12, class: "sim-shake" });
4371
+ if (state.accelerometerState.useShake && !this.shakeInitialized) {
4372
+ this.shakeInitialized = true;
4373
+ this.shakeButton.style.visibility = "visible";
4358
4374
  pxsim.accessibility.makeFocusable(this.shakeButton);
4359
4375
  pxsim.svg.fill(this.shakeButton, this.props.theme.virtualButtonUp);
4360
4376
  pxsim.pointerEvents.down.forEach(evid => this.shakeButton.addEventListener(evid, ev => {
@@ -4455,18 +4471,9 @@ path.sim-board {
4455
4471
  return;
4456
4472
  let tmin = -5;
4457
4473
  let tmax = 50;
4458
- if (!this.thermometer) {
4459
- let gid = "gradient-thermometer";
4460
- this.thermometerGradient = pxsim.svg.linearGradient(this.defs, gid);
4461
- this.thermometer = pxsim.svg.child(this.g, "rect", {
4462
- class: "sim-thermometer no-drag",
4463
- x: 120,
4464
- y: 110,
4465
- width: 20,
4466
- height: 160,
4467
- rx: 5, ry: 5,
4468
- fill: `url(#${gid})`
4469
- });
4474
+ if (!this.thermometerInitialized) {
4475
+ this.thermometerInitialized = true;
4476
+ this.thermometer.style.visibility = "visible";
4470
4477
  this.thermometerText = pxsim.svg.child(this.g, "text", { class: 'sim-text', x: 58, y: 130 });
4471
4478
  if (this.props.runtime)
4472
4479
  this.props.runtime.environmentGlobals[pxsim.localization.lf("temperature")] = state.thermometerState.temperature;
@@ -4488,6 +4495,7 @@ path.sim-board {
4488
4495
  (ev) => {
4489
4496
  let charCode = (typeof ev.which == "number") ? ev.which : ev.keyCode;
4490
4497
  if (charCode === 40 || charCode === 37) { // Down/Left arrow
4498
+ ev.preventDefault();
4491
4499
  state.thermometerState.temperature--;
4492
4500
  if (state.thermometerState.temperature < -5) {
4493
4501
  state.thermometerState.temperature = 50;
@@ -4495,6 +4503,7 @@ path.sim-board {
4495
4503
  this.updateTemperature();
4496
4504
  }
4497
4505
  else if (charCode === 38 || charCode === 39) { // Up/Right arrow
4506
+ ev.preventDefault();
4498
4507
  state.thermometerState.temperature++;
4499
4508
  if (state.thermometerState.temperature > 50) {
4500
4509
  state.thermometerState.temperature = -5;
@@ -4524,19 +4533,10 @@ path.sim-board {
4524
4533
  return;
4525
4534
  const tmin = 0; // state.microphoneState.min;
4526
4535
  const tmax = 255; //state.microphoneState.max;
4527
- if (!this.soundLevel) {
4536
+ if (!this.soundLevelInitialized) {
4537
+ this.soundLevelInitialized = true;
4538
+ this.soundLevel.style.visibility = "visible";
4528
4539
  const level = state.microphoneState.getLevel();
4529
- let gid = "gradient-soundlevel";
4530
- this.soundLevelGradient = pxsim.svg.linearGradient(this.defs, gid);
4531
- this.soundLevel = pxsim.svg.child(this.g, "rect", {
4532
- class: "sim-thermometer no-drag",
4533
- x: 360,
4534
- y: 110,
4535
- width: 20,
4536
- height: 160,
4537
- rx: 5, ry: 5,
4538
- fill: `url(#${gid})`
4539
- });
4540
4540
  this.soundLevelText = pxsim.svg.child(this.g, "text", { class: 'sim-text', x: 370, y: 90 });
4541
4541
  if (this.props.runtime)
4542
4542
  this.props.runtime.environmentGlobals[pxsim.localization.lf("sound level")] = state.microphoneState.getLevel();
@@ -4558,10 +4558,12 @@ path.sim-board {
4558
4558
  (ev) => {
4559
4559
  let charCode = (typeof ev.which == "number") ? ev.which : ev.keyCode;
4560
4560
  if (charCode === 40 || charCode === 37) { // Down/Left arrow
4561
+ ev.preventDefault();
4561
4562
  state.microphoneState.setLevel(state.microphoneState.getLevel() - 1);
4562
4563
  this.updateMicrophone();
4563
4564
  }
4564
4565
  else if (charCode === 38 || charCode === 39) { // Up/Right arrow
4566
+ ev.preventDefault();
4565
4567
  state.microphoneState.setLevel(state.microphoneState.getLevel() + 1);
4566
4568
  this.updateMicrophone();
4567
4569
  }
@@ -4620,30 +4622,45 @@ path.sim-board {
4620
4622
  }
4621
4623
  }
4622
4624
  flashAntenna() {
4623
- if (!this.antenna) {
4624
- let ax = 380;
4625
- let dax = 18;
4626
- let ayt = 10;
4627
- let ayb = 40;
4628
- const wh = dax * 5;
4629
- const antenaBackground = pxsim.svg.child(this.g, "rect", { x: ax, y: ayt, width: wh, height: ayb - ayt, fill: "transparent" });
4630
- this.antenna = pxsim.svg.child(this.g, "polyline", { class: "sim-antenna", points: `${ax},${ayb} ${ax},${ayt} ${ax += dax},${ayt} ${ax},${ayb} ${ax += dax},${ayb} ${ax},${ayt} ${ax += dax},${ayt} ${ax},${ayb} ${ax += dax},${ayb} ${ax},${ayt} ${ax += dax},${ayt}` });
4625
+ if (!this.antennaInitialized) {
4626
+ this.antenna.style.visibility = "visible";
4627
+ this.antennaInitialized = true;
4628
+ const antennaWidth = ANTENNA_WAVE_PERIOD_X * ANTENNA_WAVE_COUNT;
4629
+ const valueMin = -128;
4630
+ const valueMax = -42;
4631
+ const setValue = (val) => {
4632
+ const rs = Math.max(valueMin, Math.min(valueMax, val));
4633
+ this.board.radioState.datagram.rssi = rs;
4634
+ this.updateRSSI();
4635
+ };
4631
4636
  const pt = this.element.createSVGPoint();
4632
- const evh = (ev) => {
4637
+ const mouseEventHandler = (ev) => {
4633
4638
  const state = this.board;
4634
4639
  if (!state)
4635
4640
  return;
4636
4641
  const pos = pxsim.svg.cursorPoint(pt, this.element, ev);
4637
- const rs = Math.max(-128, Math.min(-42, (-138 + (pos.x - ax + wh) / wh * 100) | 0));
4638
- this.board.radioState.datagram.rssi = rs;
4639
- this.updateRSSI();
4642
+ setValue((-138 + (pos.x - ANTENNA_X) / antennaWidth * 100) | 0);
4643
+ };
4644
+ const keyboardEventHandler = (ev) => {
4645
+ var _a;
4646
+ const charCode = (typeof ev.which == "number") ? ev.which : ev.keyCode;
4647
+ const rs = (_a = this.board.radioState.datagram.rssi) !== null && _a !== void 0 ? _a : -75;
4648
+ if (charCode === 40 || charCode === 37) { // Down/Left arrow
4649
+ ev.preventDefault();
4650
+ setValue(rs - 1);
4651
+ }
4652
+ else if (charCode === 38 || charCode === 39) { // Up/Right arrow
4653
+ ev.preventDefault();
4654
+ setValue(rs + 1);
4655
+ }
4640
4656
  };
4641
- pxsim.svg.buttonEvents(antenaBackground, evh, evh, evh, (ev) => { });
4642
- pxsim.svg.buttonEvents(this.antenna, evh, evh, evh, (ev) => { });
4657
+ pxsim.svg.buttonEvents(this.antenna.children[0], mouseEventHandler, mouseEventHandler, mouseEventHandler, () => { });
4658
+ pxsim.svg.buttonEvents(this.antenna.children[1], mouseEventHandler, mouseEventHandler, mouseEventHandler, () => { });
4659
+ this.antenna.addEventListener('keydown', keyboardEventHandler);
4643
4660
  pxsim.accessibility.makeFocusable(this.antenna);
4644
4661
  pxsim.accessibility.setAria(this.antenna, "slider", "RSSI");
4645
- this.antenna.setAttribute("aria-valuemin", "-128");
4646
- this.antenna.setAttribute("aria-valuemax", "-42");
4662
+ this.antenna.setAttribute("aria-valuemin", `${valueMin}`);
4663
+ this.antenna.setAttribute("aria-valuemax", `${valueMax}`);
4647
4664
  this.antenna.setAttribute("aria-orientation", "horizontal");
4648
4665
  this.antenna.setAttribute("aria-valuenow", "");
4649
4666
  pxsim.accessibility.setLiveContent("");
@@ -4651,7 +4668,7 @@ path.sim-board {
4651
4668
  let now = Date.now();
4652
4669
  if (now - this.lastAntennaFlash > 200) {
4653
4670
  this.lastAntennaFlash = now;
4654
- pxsim.svg.animate(this.antenna, 'sim-flash-stroke');
4671
+ pxsim.svg.animate(this.antenna.children[1], 'sim-flash-stroke');
4655
4672
  }
4656
4673
  this.updateRSSI();
4657
4674
  }
@@ -4663,14 +4680,11 @@ path.sim-board {
4663
4680
  if (v === undefined)
4664
4681
  return;
4665
4682
  if (!this.rssi) {
4666
- let ax = 380;
4667
- let dax = 18;
4668
4683
  let ayt = 10;
4669
4684
  let ayb = 40;
4670
- const wh = dax * 5;
4671
4685
  for (let i = 0; i < 4; ++i)
4672
- pxsim.svg.child(this.g, "rect", { x: ax - 90 + i * 6, y: ayt + 28 - i * 4, width: 4, height: 2 + i * 4, fill: "#fff" });
4673
- this.rssi = pxsim.svg.child(this.g, "text", { x: ax - 64, y: ayb, class: "sim-text" });
4686
+ pxsim.svg.child(this.g, "rect", { x: ANTENNA_X - 90 + i * 6, y: ayt + 28 - i * 4, width: 4, height: 2 + i * 4, fill: "#fff" });
4687
+ this.rssi = pxsim.svg.child(this.g, "text", { x: ANTENNA_X - 64, y: ayb, class: "sim-text" });
4674
4688
  this.rssi.textContent = "";
4675
4689
  }
4676
4690
  const vt = v.toString();
@@ -4690,23 +4704,16 @@ path.sim-board {
4690
4704
  let state = this.board;
4691
4705
  if (!state || !state.lightSensorState.usesLightLevel)
4692
4706
  return;
4693
- if (!this.lightLevelButton) {
4694
- let gid = "gradient-light-level";
4695
- this.lightLevelGradient = pxsim.svg.linearGradient(this.defs, gid);
4696
- let cy = 50;
4697
- let r = 35;
4698
- this.lightLevelButton = pxsim.svg.child(this.g, "circle", {
4699
- cx: `50px`, cy: `${cy}px`, r: `${r}px`,
4700
- class: 'sim-light-level-button no-drag',
4701
- fill: `url(#${gid})`
4702
- });
4707
+ if (!this.lightLevelInitialized) {
4708
+ this.lightLevelInitialized = true;
4709
+ this.lightLevelButton.style.visibility = "visible";
4703
4710
  let pt = this.element.createSVGPoint();
4704
4711
  pxsim.svg.buttonEvents(this.lightLevelButton,
4705
4712
  // move
4706
4713
  (ev) => {
4707
4714
  let pos = pxsim.svg.cursorPoint(pt, this.element, ev);
4708
- let rs = r / 2;
4709
- let level = Math.max(0, Math.min(255, Math.floor((pos.y - (cy - rs)) / (2 * rs) * 255)));
4715
+ let rs = LIGHT_LEVEL_BUTTON_RADIUS / 2;
4716
+ let level = Math.max(0, Math.min(255, Math.floor((pos.y - (LIGHT_LEVEL_BUTTON_POSITION_Y - rs)) / (2 * rs) * 255)));
4710
4717
  if (level != this.board.lightSensorState.lightLevel) {
4711
4718
  this.board.lightSensorState.lightLevel = level;
4712
4719
  this.applyLightLevel();
@@ -4720,6 +4727,7 @@ path.sim-board {
4720
4727
  (ev) => {
4721
4728
  let charCode = (typeof ev.which == "number") ? ev.which : ev.keyCode;
4722
4729
  if (charCode === 40 || charCode === 37) { // Down/Left arrow
4730
+ ev.preventDefault();
4723
4731
  this.board.lightSensorState.lightLevel--;
4724
4732
  if (this.board.lightSensorState.lightLevel < 0) {
4725
4733
  this.board.lightSensorState.lightLevel = 255;
@@ -4727,6 +4735,7 @@ path.sim-board {
4727
4735
  this.applyLightLevel();
4728
4736
  }
4729
4737
  else if (charCode === 38 || charCode === 39) { // Up/Right arrow
4738
+ ev.preventDefault();
4730
4739
  this.board.lightSensorState.lightLevel++;
4731
4740
  if (this.board.lightSensorState.lightLevel > 255) {
4732
4741
  this.board.lightSensorState.lightLevel = 0;
@@ -4734,7 +4743,7 @@ path.sim-board {
4734
4743
  this.applyLightLevel();
4735
4744
  }
4736
4745
  });
4737
- this.lightLevelText = pxsim.svg.child(this.g, "text", { x: 85, y: cy + r - 5, text: '', class: 'sim-text' });
4746
+ this.lightLevelText = pxsim.svg.child(this.g, "text", { x: 85, y: LIGHT_LEVEL_BUTTON_POSITION_Y + LIGHT_LEVEL_BUTTON_RADIUS - 5, text: '', class: 'sim-text' });
4738
4747
  if (this.props.runtime)
4739
4748
  this.props.runtime.environmentGlobals[pxsim.localization.lf("lightLevel")] = state.lightSensorState.lightLevel;
4740
4749
  this.updateTheme();
@@ -4872,6 +4881,74 @@ path.sim-board {
4872
4881
  this.leds.push(led);
4873
4882
  }
4874
4883
  }
4884
+ // Order of construction affects tab ordering
4885
+ this.buildLightLevelElement();
4886
+ this.buildAntennaElement();
4887
+ this.buildHeadElement();
4888
+ this.buildThermometerElement();
4889
+ this.buildSoundLevel();
4890
+ this.buildShakeElement();
4891
+ this.buildButtonElements();
4892
+ this.buildPinElements();
4893
+ }
4894
+ buildAntennaElement() {
4895
+ this.antenna = pxsim.svg.child(this.g, "g", { class: "sim-antenna-outer" });
4896
+ const ayt = 10;
4897
+ const ayb = 40;
4898
+ const antennaWidth = ANTENNA_WAVE_PERIOD_X * ANTENNA_WAVE_COUNT;
4899
+ const borderOffset = 3;
4900
+ pxsim.svg.child(this.antenna, "rect", {
4901
+ x: ANTENNA_X - borderOffset,
4902
+ y: ayt - borderOffset,
4903
+ width: antennaWidth + 2 * borderOffset,
4904
+ height: ayb - ayt + 2 * borderOffset,
4905
+ fill: "transparent",
4906
+ rx: 2
4907
+ });
4908
+ let ax = ANTENNA_X;
4909
+ const dax = ANTENNA_WAVE_PERIOD_X;
4910
+ pxsim.svg.child(this.antenna, "polyline", { class: "sim-antenna", points: `${ax},${ayb} ${ax},${ayt} ${ax += dax},${ayt} ${ax},${ayb} ${ax += dax},${ayb} ${ax},${ayt} ${ax += dax},${ayt} ${ax},${ayb} ${ax += dax},${ayb} ${ax},${ayt} ${ax += dax},${ayt}` });
4911
+ this.antenna.style.visibility = "hidden";
4912
+ }
4913
+ buildSoundLevel() {
4914
+ let gid = "gradient-soundlevel";
4915
+ this.soundLevelGradient = pxsim.svg.linearGradient(this.defs, gid);
4916
+ this.soundLevel = pxsim.svg.child(this.g, "rect", {
4917
+ class: "sim-thermometer no-drag",
4918
+ x: 360,
4919
+ y: 110,
4920
+ width: 20,
4921
+ height: 160,
4922
+ rx: 5, ry: 5,
4923
+ fill: `url(#${gid})`
4924
+ });
4925
+ this.soundLevel.style.visibility = "hidden";
4926
+ }
4927
+ buildThermometerElement() {
4928
+ let gid = "gradient-thermometer";
4929
+ this.thermometerGradient = pxsim.svg.linearGradient(this.defs, gid);
4930
+ this.thermometer = pxsim.svg.child(this.g, "rect", {
4931
+ class: "sim-thermometer no-drag",
4932
+ x: 120,
4933
+ y: 110,
4934
+ width: 20,
4935
+ height: 160,
4936
+ rx: 5, ry: 5,
4937
+ fill: `url(#${gid})`
4938
+ });
4939
+ this.thermometer.style.visibility = "hidden";
4940
+ }
4941
+ buildLightLevelElement() {
4942
+ let gid = "gradient-light-level";
4943
+ this.lightLevelGradient = pxsim.svg.linearGradient(this.defs, gid);
4944
+ this.lightLevelButton = pxsim.svg.child(this.g, "circle", {
4945
+ cx: `50px`, cy: `${LIGHT_LEVEL_BUTTON_POSITION_Y}px`, r: `${LIGHT_LEVEL_BUTTON_RADIUS}px`,
4946
+ class: 'sim-light-level-button no-drag',
4947
+ fill: `url(#${gid})`
4948
+ });
4949
+ this.lightLevelButton.style.visibility = "hidden";
4950
+ }
4951
+ buildHeadElement() {
4875
4952
  // head
4876
4953
  this.head = pxsim.svg.child(this.g, "g", { class: "sim-head" });
4877
4954
  pxsim.svg.child(this.head, "ellipse", { cx: 251, cy: 75, rx: 75, ry: 35, fill: "transparent" });
@@ -4884,22 +4961,33 @@ path.sim-board {
4884
4961
  this.heads.push(pxsim.svg.path(this.headParts, "sim-theme", "M230.6,69.7c-2.9,0-5.3,2.4-5.3,5.3c0,2.9,2.4,5.3,5.3,5.3c2.9,0,5.3-2.4,5.3-5.3C235.9,72.1,233.5,69.7,230.6,69.7"));
4885
4962
  this.heads.push(pxsim.svg.path(this.headParts, "sim-theme", "M269.7,80.3c2.9,0,5.3-2.4,5.3-5.3c0-2.9-2.4-5.3-5.3-5.3c-2.9,0-5.3,2.4-5.3,5.3C264.4,77.9,266.8,80.3,269.7,80.3"));
4886
4963
  this.headText = pxsim.svg.child(this.g, "text", { x: 160, y: 60, class: "sim-text" });
4964
+ }
4965
+ buildPinElements() {
4887
4966
  // https://www.microbit.co.uk/device/pins
4967
+ // The order of this.pins must match the edgeConnectorState.pins order.
4968
+ // The draw order must match the desired tab order. To this end we
4969
+ // create the drawlist in sim order and evaluate it in tab order.
4888
4970
  // P0, P1, P2
4889
- this.pins = [
4971
+ let drawList = [
4890
4972
  "M16.5,341.2c0,0.4-0.1,0.9-0.1,1.3v60.7c4.1,1.7,8.6,2.7,12.9,2.7h34.4v-64.7c0,0,0-0.1,0-0.1c0-13-10.6-23.6-23.7-23.6C27.2,317.6,16.5,328.1,16.5,341.2z M21.2,341.6c0-10.7,8.7-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3c0,10.7-8.6,19.3-19.3,19.3C29.9,360.9,21.2,352.2,21.2,341.6z",
4891
4973
  "M139.1,317.3c-12.8,0-22.1,10.3-23.1,23.1V406h46.2v-65.6C162.2,327.7,151.9,317.3,139.1,317.3zM139.3,360.1c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C158.6,351.5,150,360.1,139.3,360.1z",
4892
4974
  "M249,317.3c-12.8,0-22.1,10.3-23.1,23.1V406h46.2v-65.6C272.1,327.7,261.8,317.3,249,317.3z M249.4,360.1c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C268.7,351.5,260.1,360.1,249.4,360.1z"
4893
- ].map((p, pi) => pxsim.svg.path(this.g, "sim-pin sim-pin-touch", p));
4975
+ ].map((p) => () => pxsim.svg.path(this.g, "sim-pin sim-pin-touch", p));
4894
4976
  // P3
4895
- this.pins.push(pxsim.svg.path(this.g, "sim-pin", "M0,357.7v19.2c0,10.8,6.2,20.2,14.4,25.2v-44.4H0z"));
4977
+ drawList.push(() => pxsim.svg.path(this.g, "sim-pin", "M0,357.7v19.2c0,10.8,6.2,20.2,14.4,25.2v-44.4H0z"));
4896
4978
  pins4onXs.forEach(x => {
4897
- this.pins.push(pxsim.svg.child(this.g, "rect", { x: x, y: 356.7, width: 10, height: 50, class: "sim-pin" }));
4979
+ drawList.push(() => pxsim.svg.child(this.g, "rect", { x: x, y: 356.7, width: 10, height: 50, class: "sim-pin" }));
4898
4980
  });
4899
- this.pins.push(pxsim.svg.path(this.g, "sim-pin", "M483.6,402c8.2-5,14.4-14.4,14.4-25.1v-19.2h-14.4V402z"));
4900
- this.pins.push(pxsim.svg.path(this.g, "sim-pin", "M359.9,317.3c-12.8,0-22.1,10.3-23.1,23.1V406H383v-65.6C383,327.7,372.7,317.3,359.9,317.3z M360,360.1c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C379.3,351.5,370.7,360.1,360,360.1z"));
4901
- this.pins.push(pxsim.svg.path(this.g, "sim-pin", "M458,317.6c-13,0-23.6,10.6-23.6,23.6c0,0,0,0.1,0,0.1h0V406H469c4.3,0,8.4-1,12.6-2.7v-60.7c0-0.4,0-0.9,0-1.3C481.6,328.1,471,317.6,458,317.6z M457.8,360.9c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C477.1,352.2,468.4,360.9,457.8,360.9z"));
4902
- this.pins.forEach((p, i) => pxsim.svg.hydrate(p, { title: pinTitles[i] }));
4981
+ drawList.push(() => pxsim.svg.path(this.g, "sim-pin", "M483.6,402c8.2-5,14.4-14.4,14.4-25.1v-19.2h-14.4V402z"));
4982
+ drawList.push(() => pxsim.svg.path(this.g, "sim-pin", "M359.9,317.3c-12.8,0-22.1,10.3-23.1,23.1V406H383v-65.6C383,327.7,372.7,317.3,359.9,317.3z M360,360.1c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C379.3,351.5,370.7,360.1,360,360.1z"));
4983
+ drawList.push(() => pxsim.svg.path(this.g, "sim-pin", "M458,317.6c-13,0-23.6,10.6-23.6,23.6c0,0,0,0.1,0,0.1h0V406H469c4.3,0,8.4-1,12.6-2.7v-60.7c0-0.4,0-0.9,0-1.3C481.6,328.1,471,317.6,458,317.6z M457.8,360.9c-10.7,0-19.3-8.6-19.3-19.3c0-10.7,8.6-19.3,19.3-19.3c10.7,0,19.3,8.7,19.3,19.3C477.1,352.2,468.4,360.9,457.8,360.9z"));
4984
+ this.pins = pinDrawOrder.reduce((pins, pinName) => {
4985
+ const simPinIndex = pinNames.indexOf(pinName);
4986
+ const newPin = drawList[simPinIndex]();
4987
+ pxsim.svg.hydrate(newPin, { title: pinTitles[simPinIndex] });
4988
+ pins[simPinIndex] = newPin;
4989
+ return pins;
4990
+ }, new Array(pinDrawOrder.length));
4903
4991
  this.pinGradients = this.pins.map((pin, i) => {
4904
4992
  let gid = "gradient-pin-" + i;
4905
4993
  let lg = pxsim.svg.linearGradient(this.defs, gid);
@@ -4907,6 +4995,17 @@ path.sim-board {
4907
4995
  return lg;
4908
4996
  });
4909
4997
  this.pinTexts = [67, 165, 275].map(x => pxsim.svg.child(this.g, "text", { class: "sim-text-pin", x: x, y: 345 }));
4998
+ }
4999
+ buildShakeElement() {
5000
+ this.shakeButton = pxsim.svg.child(this.g, "circle", {
5001
+ cx: 404,
5002
+ cy: 115,
5003
+ r: 12,
5004
+ class: "sim-shake",
5005
+ });
5006
+ this.shakeButton.style.visibility = "hidden";
5007
+ }
5008
+ buildButtonElements() {
4910
5009
  this.buttonsOuter = [];
4911
5010
  this.buttons = [];
4912
5011
  const outerBtn = (left, top, label) => {
@@ -5130,6 +5229,7 @@ path.sim-board {
5130
5229
  let state = this.board;
5131
5230
  let pin = state.edgeConnectorState.pins[index];
5132
5231
  if (charCode === 40 || charCode === 37) { // Down/Left arrow
5232
+ ev.preventDefault();
5133
5233
  pin.value -= 10;
5134
5234
  if (pin.value < 0) {
5135
5235
  pin.value = 1023;
@@ -5137,6 +5237,7 @@ path.sim-board {
5137
5237
  this.updatePin(pin, index);
5138
5238
  }
5139
5239
  else if (charCode === 38 || charCode === 39) { // Up/Right arrow
5240
+ ev.preventDefault();
5140
5241
  pin.value += 10;
5141
5242
  if (pin.value > 1023) {
5142
5243
  pin.value = 0;
@@ -1 +1 @@
1
- {"A Blocks / JavaScript code editor for the micro:bit powered by Microsoft MakeCode.":"A Blocks / JavaScript code editor for the micro:bit powered by Microsoft MakeCode.","A micro-servo library":"A micro-servo library","Adds new blocks for message communication in the radio category":"Adds new blocks for message communication in the radio category","BETA - Camera, remote control and other Bluetooth services. App required.":"BETA - Camera, remote control and other Bluetooth services. App required.","Behind the MakeCode Hardware":"Behind the MakeCode Hardware","Blocks to JavaScript":"Blocks to JavaScript","Bluetooth services":"Bluetooth services","Buy":"Buy","Can't import microbit.co.uk scripts...":"Can't import microbit.co.uk scripts...","Coding Cards":"Coding Cards","Coding for Teachers":"Coding for Teachers","Color manipulation":"Color manipulation","Courses":"Courses","Data logging to flash memory. micro:bit (V2) only.":"Data logging to flash memory. micro:bit (V2) only.","Data logging to flash.":"Data logging to flash.","Deep Dive":"Deep Dive","Disable Bluetooth Event Service":"Disable Bluetooth Event Service","Download cancelled":"Download cancelled","Download failed, please try again":"Download failed, please try again","Download for V2 only":"Download for V2 only","Fashion":"Fashion","Fonts for displays (V2 only).":"Fonts for displays (V2 only).","Games":"Games","Go Back":"Go Back","Go to the old editor":"Go to the old editor","Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V1😢. You can go back and try to make your program smaller, or you can download your program onto a micro:bit V2.":"Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V1😢. You can go back and try to make your program smaller, or you can download your program onto a micro:bit V2.","Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V2😢. You can go back and try to make your program smaller, or continue to use the simulator to run your code.":"Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V2😢. You can go back and try to make your program smaller, or continue to use the simulator to run your code.","Hardware":"Hardware","Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor.":"Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor.","Jacdac":"Jacdac","JustWorks pairing (default): Pairing is automatic once the pairing is initiated.":"JustWorks pairing (default): Pairing is automatic once the pairing is initiated.","Live Coding":"Live Coding","MicroCode for the new micro:bit (V2)":"MicroCode for the new micro:bit (V2)","Microsoft MakeCode for micro:bit":"Microsoft MakeCode for micro:bit","Music":"Music","New? Start here!":"New? Start here!","No Pairing Required: Anyone can connect via Bluetooth.":"No Pairing Required: Anyone can connect via Bluetooth.","Oops, there was a problem downloading your code":"Oops, there was a problem downloading your code","Passkey pairing: Pairing requires 6 digit key to pair.":"Passkey pairing: Pairing requires 6 digit key to pair.","Radio Games":"Radio Games","Record sound clips. micro:bit (V2) only":"Record sound clips. micro:bit (V2) only","Reference":"Reference","Science":"Science","Science Experiments":"Science Experiments","Settings storage in internal flash":"Settings storage in internal flash","Support":"Support","Support for bitmaps (micro:bit V2 only).":"Support for bitmaps (micro:bit V2 only).","The microbit core library":"The microbit core library","The microphone library":"The microphone library","The radio services":"The radio services","Tools":"Tools","Toys":"Toys","Turtle":"Turtle","Tutorials":"Tutorials","Tutorials for the new micro:bit (V2)":"Tutorials for the new micro:bit (V2)","makecode.microbit.org":"makecode.microbit.org","{0} is a write only analog pin":"{0} is a write only analog pin","{id:extension-tag}Gaming":"Gaming","{id:extension-tag}Lights and Display":"Lights and Display","{id:extension-tag}Networking":"Networking","{id:extension-tag}Robotics":"Robotics","{id:extension-tag}Science":"Science","{id:extension-tag}Software":"Software","{id:type}Image":"Image","{id:type}LedSprite":"LedSprite","{id:var}image":"image","{id:var}sprite":"sprite"}
1
+ {"A Blocks / JavaScript code editor for the micro:bit powered by Microsoft MakeCode.":"A Blocks / JavaScript code editor for the micro:bit powered by Microsoft MakeCode.","A micro-servo library":"A micro-servo library","Adds new blocks for message communication in the radio category":"Adds new blocks for message communication in the radio category","BETA - Camera, remote control and other Bluetooth services. App required.":"BETA - Camera, remote control and other Bluetooth services. App required.","Behind the MakeCode Hardware":"Behind the MakeCode Hardware","Blocks to JavaScript":"Blocks to JavaScript","Bluetooth services":"Bluetooth services","Buy":"Buy","Can't import microbit.co.uk scripts...":"Can't import microbit.co.uk scripts...","Coding Cards":"Coding Cards","Coding for Teachers":"Coding for Teachers","Color manipulation":"Color manipulation","Courses":"Courses","Data logging to flash memory. micro:bit (V2) only.":"Data logging to flash memory. micro:bit (V2) only.","Data logging to flash.":"Data logging to flash.","Deep Dive":"Deep Dive","Disable Bluetooth Event Service":"Disable Bluetooth Event Service","Download cancelled":"Download cancelled","Download failed, please try again":"Download failed, please try again","Download for V2 only":"Download for V2 only","Fashion":"Fashion","Fonts for displays (V2 only).":"Fonts for displays (V2 only).","Games":"Games","Go Back":"Go Back","Go to the old editor":"Go to the old editor","Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V1😢. You can go back and try to make your program smaller, or you can download your program onto a micro:bit V2.":"Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V1😢. You can go back and try to make your program smaller, or you can download your program onto a micro:bit V2.","Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V2😢. You can go back and try to make your program smaller, or continue to use the simulator to run your code.":"Great coding skills! Unfortunately, your program is too large to fit on a micro:bit V2😢. You can go back and try to make your program smaller, or continue to use the simulator to run your code.","Hardware":"Hardware","Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor.":"Importing microbit.co.uk programs is not supported in this editor anymore. Please open this script in the https://makecode.microbit.org/v0 editor.","Jacdac":"Jacdac","JustWorks pairing (default): Pairing is automatic once the pairing is initiated.":"JustWorks pairing (default): Pairing is automatic once the pairing is initiated.","Live Coding":"Live Coding","MicroCode for the new micro:bit (V2)":"MicroCode for the new micro:bit (V2)","Microsoft MakeCode for micro:bit":"Microsoft MakeCode for micro:bit","Music":"Music","New? Start here!":"New? Start here!","No Pairing Required: Anyone can connect via Bluetooth.":"No Pairing Required: Anyone can connect via Bluetooth.","Oops, there was a problem downloading your code":"Oops, there was a problem downloading your code","Passkey pairing: Pairing requires 6 digit key to pair.":"Passkey pairing: Pairing requires 6 digit key to pair.","Radio Games":"Radio Games","Record sound clips. micro:bit (V2) only":"Record sound clips. micro:bit (V2) only","Reference":"Reference","Science":"Science","Science Experiments":"Science Experiments","Settings storage in internal flash":"Settings storage in internal flash","Support":"Support","Support for bitmaps (micro:bit V2 only).":"Support for bitmaps (micro:bit V2 only).","The microbit core library":"The microbit core library","The microphone library":"The microphone library","The radio services":"The radio services","Tools":"Tools","Toys":"Toys","Turtle":"Turtle","Tutorials":"Tutorials","Tutorials for the new micro:bit (V2)":"Tutorials for the new micro:bit (V2)","makecode.microbit.org":"makecode.microbit.org","{0} is a write only analog pin":"{0} is a write only analog pin","{id:color-theme-name}High Contrast":"High Contrast","{id:color-theme-name}Micro:bit Light":"Micro:bit Light","{id:extension-tag}Gaming":"Gaming","{id:extension-tag}Lights and Display":"Lights and Display","{id:extension-tag}Networking":"Networking","{id:extension-tag}Robotics":"Robotics","{id:extension-tag}Science":"Science","{id:extension-tag}Software":"Software","{id:type}Image":"Image","{id:type}LedSprite":"LedSprite","{id:var}image":"image","{id:var}sprite":"sprite"}