diff --git a/Cargo.toml b/Cargo.toml
index ff0a51c..3e906c9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,6 +22,7 @@ features = [
"DragEvent",
"HtmlImageElement",
"Headers",
+ "Navigator",
"Request",
"RequestInit",
"RequestMode",
@@ -31,7 +32,7 @@ features = [
"Url",
"Blob",
"BlobPropertyBag",
- "Window"
+ "Window",
]
[profile.release]
diff --git a/assets/index.html b/assets/index.html
index bb38d9d..e61853c 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -12,6 +12,7 @@
diff --git a/assets/style.css b/assets/style.css
index de61e0d..a2bc6b9 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -47,6 +47,11 @@ h1 {
font-size: 1rem;
}
+p {
+ text-align: center;
+ opacity: 0.8;
+}
+
details {
text-align: center;
}
@@ -96,6 +101,7 @@ img {
border: 2px solid gray;
margin: 2px;
width: 12vw;
+ touch-action: none;
}
fieldset {
diff --git a/compose.yaml b/compose.yaml
index 3f64dac..e6971de 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -13,4 +13,4 @@ services:
command: firebase emulators:start -P $COMPOSE_PROJECT_NAME
volumes:
- ./firebase.json:/home/node/firebase.json
- - ./assets:/home/node/assets
\ No newline at end of file
+ - ./assets:/home/node/assets
diff --git a/src/display.rs b/src/display.rs
index e1682b2..0b016c3 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -1,8 +1,16 @@
use wasm_bindgen::JsCast;
-use web_sys::{DragEvent, HtmlImageElement};
+use web_sys::{DragEvent, Element, Event, HtmlImageElement};
use crate::util;
+pub fn change_message(msg: &str) {
+ let document = web_sys::window().unwrap().document().unwrap();
+ document
+ .get_element_by_id("message")
+ .unwrap()
+ .set_text_content(Some(msg));
+}
+
pub fn toggle_loading(display: bool) {
let document = web_sys::window().unwrap().document().unwrap();
@@ -51,34 +59,67 @@ pub fn compare_rand_urls(urls: &[String]) -> bool {
urls.eq(&random_urls)
}
-pub fn send_src_url(e: DragEvent) {
- let el = e.target().unwrap().dyn_into::().unwrap();
+pub fn send_img_src_on_drag(e: DragEvent) {
+ let t_id = e
+ .target()
+ .unwrap()
+ .dyn_into::()
+ .unwrap()
+ .id();
e.data_transfer().unwrap().clear_data().unwrap();
e.data_transfer()
.unwrap()
- .set_data("text/plain", &el.id())
+ .set_data("text/plain", &t_id)
.unwrap();
}
-pub fn swap_url(e: DragEvent) {
- let window = web_sys::window().unwrap();
- let document = window.document().unwrap();
-
+pub fn swap_img_src_on_drag(e: DragEvent) {
e.prevent_default();
- let el = e.target().unwrap().dyn_into::().unwrap();
- let src = el.src();
+
+ let document = web_sys::window().unwrap().document().unwrap();
+
+ let target = e.target().unwrap().dyn_into::().unwrap();
let id = e.data_transfer().unwrap().get_data("text/plain").unwrap();
- let dst_el = document
+ let source = document
.get_element_by_id(&id)
.unwrap()
.dyn_into::()
.unwrap();
- let dst_src = dst_el.src();
+ let temp = target.src();
+
+ target.set_src(&source.src());
+ source.set_src(&temp);
+}
+
+pub fn swap_img_src_on_touch(e: Event) {
+ let document = web_sys::window().unwrap().document().unwrap();
+ let clicked = document.query_selector(r#"[data-touched="ok"]"#).unwrap();
+
+ let t_id = e
+ .current_target()
+ .unwrap()
+ .dyn_into::()
+ .unwrap()
+ .id();
+
+ let target = document
+ .get_element_by_id(&t_id)
+ .unwrap()
+ .dyn_into::()
+ .unwrap();
- dst_el.set_src(&src);
- el.set_src(&dst_src);
+ if let Some(clicked) = clicked {
+ let clicked = clicked.dyn_into::().unwrap();
+
+ let temp = target.src();
+ target.set_src(&clicked.src());
+ clicked.set_src(&temp);
+ clicked.remove_attribute("data-touched").unwrap()
+ } else {
+ target.set_attribute("data-touched", "ok").unwrap();
+ }
}
pub fn display_img_url(id: usize, url: &str) {
diff --git a/src/puzzle.rs b/src/puzzle.rs
index 6548d4d..afe05e3 100644
--- a/src/puzzle.rs
+++ b/src/puzzle.rs
@@ -2,7 +2,7 @@ use std::rc::Rc;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
-use web_sys::{DragEvent, Element, HtmlImageElement, HtmlLabelElement};
+use web_sys::{DragEvent, Element, Event, HtmlImageElement, HtmlLabelElement};
use crate::{data::Data, display, util};
@@ -10,12 +10,12 @@ pub fn puzzle_handler(urls: Vec, data: Data) {
let document = web_sys::window().unwrap().document().unwrap();
let imgs = document.query_selector_all("figure img").unwrap();
- let drag_over_handler =
- Closure::new(Box::new(|e: DragEvent| e.prevent_default()) as Box);
-
let urls = Rc::new(urls);
let data = Rc::new(data);
+ let drag_over_handler =
+ Closure::new(Box::new(|e: DragEvent| e.prevent_default()) as Box);
+
for i in 0..imgs.length() {
let img = imgs
.item(i)
@@ -23,13 +23,39 @@ pub fn puzzle_handler(urls: Vec, data: Data) {
.dyn_into::()
.unwrap();
+ let urls = Rc::clone(&urls);
+ let data = Rc::clone(&data);
+
+ if util::is_mobile() && !util::support_drag_drop() {
+ display::change_message("Tekan 2 gambar untuk menukarnya");
+
+ let click_handler = Closure::new(Box::new(move |e: Event| {
+ display::swap_img_src_on_touch(e);
+
+ let ok = display::compare_rand_urls(&urls);
+ if ok {
+ success_handler(&data);
+ }
+ }) as Box);
+
+ img.add_event_listener_with_callback(
+ "touchstart",
+ click_handler.as_ref().unchecked_ref(),
+ )
+ .unwrap();
+
+ click_handler.forget();
+ continue;
+ }
+
img.add_event_listener_with_callback(
"dragover",
drag_over_handler.as_ref().unchecked_ref(),
)
.unwrap();
- let drag_start_handler = Closure::new(Box::new(display::send_src_url) as Box);
+ let drag_start_handler =
+ Closure::new(Box::new(display::send_img_src_on_drag) as Box);
img.add_event_listener_with_callback(
"dragstart",
@@ -37,11 +63,8 @@ pub fn puzzle_handler(urls: Vec, data: Data) {
)
.unwrap();
- let urls = Rc::clone(&urls);
- let data = Rc::clone(&data);
-
let drop_handler = Closure::new(Box::new(move |e: DragEvent| {
- display::swap_url(e);
+ display::swap_img_src_on_drag(e);
let ok = display::compare_rand_urls(&urls);
if ok {
diff --git a/src/util.rs b/src/util.rs
index 0ccb6cf..c095e04 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,11 +1,33 @@
use std::fmt::Display;
-use wasm_bindgen::JsValue;
+use wasm_bindgen::{JsCast, JsValue};
use web_sys::{
js_sys::{Array, Math, Uint8Array},
- Blob, BlobPropertyBag,
+ Blob, BlobPropertyBag, HtmlElement,
};
+pub fn is_mobile() -> bool {
+ let window = web_sys::window().unwrap();
+
+ let touch_start_exists = window.ontouchstart().is_some();
+ let touch_points = window.navigator().max_touch_points();
+ touch_start_exists || touch_points > 0
+}
+
+pub fn support_drag_drop() -> bool {
+ let document = web_sys::window().unwrap().document().unwrap();
+ let div = document
+ .create_element("div")
+ .unwrap()
+ .dyn_into::()
+ .unwrap();
+
+ div.draggable()
+ && div.ondragstart().is_some()
+ && div.ondrop().is_some()
+ && div.ondragover().is_some()
+}
+
pub fn js_buffer_to_bytes(js_buff: &JsValue) -> Vec {
let js_bytes = Uint8Array::new(js_buff);
js_bytes.to_vec()