Skip to content

Commit c7f1cc5

Browse files
committed
feat: add moveable
1 parent 82e518c commit c7f1cc5

File tree

1 file changed

+106
-77
lines changed

1 file changed

+106
-77
lines changed

index.html

Lines changed: 106 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8">
5+
<meta content="zpkJm8KWRDtbMaW0OX3DHdY1eYqJabj5V7ER9K0xKbA" name="google-site-verification"/>
56
<title>Plotly</title>
67
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
78
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
89
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
910
<script src="https://cdn.plot.ly/plotly-2.32.0.min.js"></script>
11+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/moveable.min.js"></script>
12+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/moveable.min.css" rel="stylesheet">
1013
<style>
1114
body {
1215
height: 100vh;
@@ -26,7 +29,7 @@
2629
position: absolute;
2730
top: 50px;
2831
left: 50px;
29-
resize: both;
32+
/*resize: both;*/
3033
overflow: hidden;
3134
z-index: 0;
3235
}
@@ -70,6 +73,10 @@
7073
background-color: #f0f0f0;
7174
}
7275

76+
.btn:active {
77+
background-color: #e0e0e0;
78+
}
79+
7380
#add-box-btn {
7481
position: absolute;
7582
top: 10px;
@@ -96,12 +103,29 @@
96103
.hidden {
97104
display: none;
98105
}
106+
107+
.moveable-control {
108+
opacity: 0;
109+
}
110+
111+
.moveable-line {
112+
opacity: 0;
113+
}
114+
115+
.input-label-required {
116+
font-weight: bold;
117+
}
118+
119+
.view-chart {
120+
box-shadow: 0 0 15px darkgrey;
121+
}
99122
</style>
100123
</head>
101124
<body>
102125
<i id="add-box-btn" class="fas fa-plus-circle fa-2x"></i>
103126
<div id="overlay-text">Plotly JSON Visualizer</div>
104127

128+
<script src="https://unpkg.com/moveable@latest/dist/moveable.min.js"></script>
105129
<script>
106130
let highestZIndex = 1000;
107131

@@ -123,39 +147,39 @@
123147
</div>
124148
<div class="box-body">
125149
<div class="view-input-type">
126-
<label for="input-type">Input Type:</label>
150+
<label for="input-type" class="input-label-required">Input Type:</label>
127151
<select id="input-type" class="form-control">
128152
<option value="json">JSON Text</option>
129153
<option value="http">HTTP Request</option>
130154
</select><br>
131155
</div>
132156
<div class="view-json">
133-
<label for="json-input">JSON Data:</label><br>
134-
<textarea class="json-input form-control" rows="10"></textarea><br>
157+
<label for="form-json-input" class="input-label-required">JSON Data:</label><br>
158+
<textarea id="form-json-input" class="json-input form-control" rows="10"></textarea><br>
135159
<button class="btn btn-beautify">Beautify JSON</button><br><br>
136-
<label for="json-path-json">JSON Path (optional):</label><br>
137-
<input type="text" class="json-path-json form-control" placeholder="e.g., data.chart"><br>
160+
<label for="form-json-path">JSON Path</label><br>
161+
<input id="form-json-path" type="text" class="json-path-json form-control" placeholder="data.chart"><br>
138162
</div>
139163
<div class="view-http hidden">
140164
<form id="requestForm">
141-
<label for="url">URL:</label>
142-
<input type="text" class="http-url form-control" required><br>
143-
<label for="method">HTTP Method:</label>
144-
<select class="http-method form-control">
165+
<label for="form-http-url" class="input-label-required">URL:</label>
166+
<input id="form-http-url" type="text" class="http-url form-control" required placeholder="http://localhost:8080/generate?key1=value1&key2=value2"><br>
167+
<label for="form-http-method" class="input-label-required">HTTP Method:</label>
168+
<select id="form-http-method" class="http-method form-control">
145169
<option value="GET">GET</option>
146170
<option value="POST">POST</option>
147171
</select><br>
148-
<div class="paramsContainer">
149-
<label for="params">Query Parameters</label><br>
150-
<textarea class="http-params form-control" placeholder="key1=value1&key2=value2"></textarea><br>
172+
<div class="headersContainer">
173+
<label for="form-http-headers">Headers</label><br>
174+
<textarea id="form-http-headers" class="http-headers form-control" placeholder='Content-Type=application/json\nAccept=*/*'></textarea><br>
151175
</div>
152176
<div class="bodyContainer">
153-
<label for="body">Body</label><br>
154-
<textarea class="http-body form-control" placeholder='{"key1": "value1", "key2": "value2"}'></textarea><br>
177+
<label for="form-http-body">Body</label><br>
178+
<textarea id="form-http-body" class="http-body form-control" placeholder='{"key1": "value1", "key2": "value2"}'></textarea><br>
155179
</div>
156180
<div class="jsonPathContainer">
157-
<label for="json-path-http">JSON Path (optional):</label><br>
158-
<input type="text" class="json-path-http form-control" placeholder="e.g., data.chart"><br>
181+
<label for="form-http-json-path">JSON Path</label><br>
182+
<input id="form-http-json-path" type="text" class="json-path-http form-control" placeholder="data.chart"><br>
159183
</div>
160184
</form>
161185
</div>
@@ -166,13 +190,57 @@
166190
`;
167191
document.body.appendChild(box);
168192

169-
setupDraggable(box);
170-
setupResizable(box);
193+
const headerEl = box.querySelector('[data-drag-handle]');
194+
195+
const moveable = new Moveable(document.body, {
196+
target: box,
197+
resizable: true,
198+
keepRatio: false,
199+
edge: true,
200+
draggable: true,
201+
checkInput: true,
202+
checkSelect: true,
203+
});
204+
205+
box.querySelector('#input-type').addEventListener("mousedown", (e) => {
206+
e.stopPropagation();
207+
});
208+
209+
box.querySelector('#form-http-method').addEventListener("mousedown", (e) => {
210+
e.stopPropagation();
211+
});
212+
213+
moveable.on("drag", ({target, left, top}) => {
214+
target.style.left = `${left}px`;
215+
target.style.top = `${top}px`;
216+
});
217+
218+
moveable.on("resize", ({target, width, height, delta, direction}) => {
219+
const minWidth = 100;
220+
const minHeight = 200;
221+
222+
if (width >= minWidth && height >= minHeight) {
223+
target.style.width = `${width}px`;
224+
target.style.height = `${height}px`;
225+
226+
if (direction[0] === -1) {
227+
target.style.left = `${target.offsetLeft - delta[0]}px`;
228+
}
229+
if (direction[1] === -1) {
230+
target.style.top = `${target.offsetTop - delta[1]}px`;
231+
}
232+
}
233+
updatePlotSize(box);
234+
});
235+
171236
setupZIndex(box);
172237

173238
box.querySelector('.btn-generate').addEventListener('click', () => reloadPlot(box));
174239
box.querySelector('.btn-back').addEventListener('click', () => switchToJson(box));
175-
box.querySelector('.btn-close').addEventListener('click', () => box.remove());
240+
box.querySelector('.btn-close').addEventListener('click', () => {
241+
moveable.destroy(); // Clean up movable instance
242+
box.remove();
243+
});
176244
box.querySelector('.btn-beautify').addEventListener('click', () => beautifyJson(box));
177245

178246
box.querySelector('#input-type').addEventListener('change', (event) => switchInputType(box, event.target.value));
@@ -247,19 +315,14 @@
247315
} else {
248316
const url = box.querySelector('.http-url').value;
249317
const method = box.querySelector('.http-method').value;
250-
const params = box.querySelector('.http-params').value;
318+
const headers = box.querySelector('.http-headers').value;
251319
const body = box.querySelector('.http-body').value;
252320

253-
let fullUrl = url;
254-
if (method === 'GET' && params) {
255-
fullUrl += '?' + params;
256-
}
321+
let parsedHeaders = parseHeaders(headers);
257322

258-
const response = await fetch(fullUrl, {
323+
const response = await fetch(url, {
259324
method: method,
260-
headers: {
261-
'Content-Type': 'application/json'
262-
},
325+
headers: parsedHeaders,
263326
body: method === 'POST' ? body : null
264327
});
265328
const jsonData = await response.json();
@@ -292,6 +355,20 @@
292355
}
293356
}
294357

358+
function parseHeaders(headerString) {
359+
const headers = {};
360+
const lines = headerString.split('\n'); // Split the string by new lines
361+
362+
lines.forEach(line => {
363+
const [key, value] = line.split('='); // Split each line by '='
364+
if (key && value) {
365+
headers[key.trim()] = value.trim(); // Trim and add to headers object
366+
}
367+
});
368+
369+
return headers;
370+
}
371+
295372
function beautifyJson(box) {
296373
const jsonInput = box.querySelector('.json-input');
297374
try {
@@ -303,53 +380,6 @@
303380
}
304381
}
305382

306-
function setupDraggable(box) {
307-
const dragHandleEl = box.querySelector('[data-drag-handle]');
308-
let dragEl;
309-
let lastPosition = {};
310-
311-
dragHandleEl.addEventListener('mousedown', dragStart);
312-
dragHandleEl.addEventListener('mouseup', dragEnd);
313-
dragHandleEl.addEventListener('mouseout', dragEnd);
314-
315-
function dragStart(event) {
316-
dragEl = box;
317-
dragEl.style.setProperty('position', 'absolute');
318-
dragEl.style.setProperty('z-index', ++highestZIndex); // Bring to front on drag
319-
lastPosition.left = event.clientX;
320-
lastPosition.top = event.clientY;
321-
dragHandleEl.classList.add('dragging');
322-
dragHandleEl.addEventListener('mousemove', dragMove);
323-
}
324-
325-
function dragMove(event) {
326-
const dragElRect = dragEl.getBoundingClientRect();
327-
const newLeft = dragElRect.left + event.clientX - lastPosition.left;
328-
const newTop = dragElRect.top + event.clientY - lastPosition.top;
329-
dragEl.style.setProperty('left', `${newLeft}px`);
330-
dragEl.style.setProperty('top', `${newTop}px`);
331-
lastPosition.left = event.clientX;
332-
lastPosition.top = event.clientY;
333-
window.getSelection().removeAllRanges();
334-
updatePlotSize(box);
335-
}
336-
337-
function dragEnd() {
338-
dragHandleEl.classList.remove('dragging');
339-
dragHandleEl.removeEventListener('mousemove', dragMove);
340-
dragEl = null;
341-
}
342-
}
343-
344-
function setupResizable(box) {
345-
box.style.setProperty('resize', 'both');
346-
box.style.setProperty('overflow', 'hidden');
347-
348-
new ResizeObserver(() => {
349-
updatePlotSize(box);
350-
}).observe(box);
351-
}
352-
353383
function setupZIndex(box) {
354384
box.addEventListener('mousedown', () => {
355385
box.style.zIndex = ++highestZIndex;
@@ -363,7 +393,6 @@
363393
}
364394
}
365395

366-
// Add initial box on load
367396
addNewBox();
368397
</script>
369398
</body>

0 commit comments

Comments
 (0)