summaryrefslogtreecommitdiffstats
path: root/virtual-programs/web/new-program-web-editor.folk
blob: 5e4803a3976a049bea9cb09c263b8ccba2e00135 (plain)
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
Wish the web server handles route "/new" with handler {
    html {
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body { overflow: hidden; }
    </style>
  </head>
  <body>
    <span id="status">Status</span>
    <div id="dragme" style="cursor: move; position: absolute; user-select: none; background-color: #ccc; padding: 1em">
      <textarea id="code" cols="50" rows="20" style="font-family: monospace">Wish $this is outlined blue</textarea>
      <p>
        <button onclick="handleSave()">Save</button>
        <button onclick="handlePrint()">Print</button>

        <input id="regionAngleRange" type="range" value="0" min="0" max="360" step="0.1" oninput="this.nextElementSibling.value = `angle: ${this.value}&deg;`; regionAngle = this.value; handleDrag();">
        <output>angle: 0&deg;</output>
      </p>
      <pre id="error"></pre>
    </div>

    <script src="/lib/folk.js"></script>
    <script>
  // The current position of mouse
  let x = 0;
  let y = 0;

  // Query the element
  const ele = document.getElementById('dragme');
  const codeEle = document.getElementById("code");
  const angleEle = document.getElementById("regionAngleRange");
  const errorEle = document.getElementById("error");
  

  // Handle the mousedown event
  // that's triggered when user drags the element
  const mouseDownHandler = function (e) {
    if (e.target == codeEle) return;
    if (e.target == angleEle) return;

    // Get the current mouse position
    x = e.clientX;
    y = e.clientY;

    // Attach the listeners to `document`
    document.addEventListener('pointermove', mouseMoveHandler);
    document.addEventListener('pointerup', mouseUpHandler);
  };

  const mouseMoveHandler = function (e) {
    if (e.target == codeEle) return;

    // How far the mouse has been moved
    const dx = e.clientX - x;
    const dy = e.clientY - y;

    // Set the position of element
    const [top, left] = [ele.offsetTop + dy, ele.offsetLeft + dx];
    ele.style.top = `${top}px`;
    ele.style.left = `${left}px`;
    handleDrag();

    // Reassign the position of mouse
    x = e.clientX;
    y = e.clientY;
  };

  const mouseUpHandler = function () {
    // Remove the handlers of `mousemove` and `mouseup`
    document.removeEventListener('pointermove', mouseMoveHandler);
    document.removeEventListener('pointerup', mouseUpHandler);
  };

  // Cmd + S || Ctrl + S => Save
  document.addEventListener('keydown', function(e) {
    if ((window.navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)  && e.keyCode == 83) {
      e.preventDefault();
      handleSave();
    }
  }, false);
  // Cmd + P || Ctrl + P => Print
  document.addEventListener('keydown', function(e) {
    if ((window.navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)  && e.keyCode == 80) {
      e.preventDefault();
      handlePrint();
    }
  }, false);

  ele.addEventListener('pointerdown', mouseDownHandler);

  function uuidv4() {
    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
      (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
    );
    }
  const program = "web-program-" + uuidv4();

  let regionAngle = 0;
  const ws = new FolkWS(document.getElementById('status'));

  ws.watchCollected(tcl`${program} has error /something/ with info /errorInfo/`, errors => {
    errorEle.style.backgroundColor = errors.length ? "#f55" : "";
    errorEle.innerText = errors.map(e => e.errorInfo).join('\n');
  });

  function handleDrag() {
    let [top, left, w, h] = [ele.offsetTop, ele.offsetLeft, ele.offsetWidth, ele.offsetHeight];
    ws.send(tcl`
      set top [expr {int(double(${(top + (top/window.innerHeight) * h)}) * (double($Display::HEIGHT) / ${window.innerHeight}))}]
      set left [expr {int(double(${(left + (left/window.innerWidth) * w)}) * (double($Display::WIDTH) / ${window.innerWidth}))}]
      proc handleConfigure {program x y w h} {
        set vertices [list [list [expr {$x+$w}] $y] \
            [list $x $y] \
            [list $x [expr {$y+$h}]] \
            [list [expr {$x+$w}] [expr {$y+$h}]]]
        set edges [list [list 0 1] [list 1 2] [list 2 3] [list 3 0]]
        set basicRegion [region create $vertices $edges]
        set rotatedRegion [region rotate $basicRegion ${regionAngle * (3.1415 / 180)}]
        Commit region {
          claim $program has region $rotatedRegion
        }
      }
      handleConfigure ${program} $left $top ${w} ${h}
      if {$::isLaptop} { Step }
  `);
  }
  function handleSave() {
    const code = document.getElementById("code").value;
    ws.send(tcl`
      Commit code {
        Claim ${program} has program code ${code}
      }
      if {$::isLaptop} { Step }
    `);
  }
  function handlePrint() {
    const code = document.getElementById("code").value;
    const jobid = String(Math.random());
    ws.send(tcl`Wish to print ${code} with job-id ${jobid}`);
  }

  handleDrag();
    </script>
  </body>
</html>
    }
}