hoplon

The :hoplon: ClojureScript Web Framework - http://hoplon.io/
2017-12-15T00:57:44.000026Z

@micha not a library, but i can show you 🙂

2017-12-15T00:57:47.000268Z

(h/defelem drag-wrap
 "A drag and drop wrapper to sit between lists and items."
 [{:keys [conn list item dropped-item]} children]
 (let [new-item? (j/cell= (= item.data/new-item-id (:db/id item)))
       dropped-item (or dropped-item (j/cell nil))

       data-transfer-mime "text"
       set-dragged-item! (fn [e i]
                          (-> e
                           .-originalEvent
                           .-dataTransfer
                           (.setData data-transfer-mime (pr-str i))))
       event->dragged-item (fn [e]
                            (-> e
                             .-originalEvent
                             .-dataTransfer
                             (.getData data-transfer-mime)
                             cljs.reader/read-string))

       drag-source? (j/cell false)
       drag-target? (j/cell false)
       drag-end! #(j/dosync
                   (reset! drag-source? false)
                   (reset! drag-target? false)
                   true)]

  (h/div
   ; Drag source attributes.

   ; Must be the string "true" as this attribute is enumerated.
   ; <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable>
   ; Don't allow dummy/new items to be draggable.
   :draggable (j/cell= (when-not new-item? "true"))
   :data-drag-source drag-source?

   ; todo - replace with real styles.
   :garden (j/cell=
            (if (not new-item?)
             {:cursor :move}
             {:cursor :pointer}))

   :dragstart #(do (-&gt; % .-originalEvent .-dataTransfer (aset "effectAllowed" "move"))
                (set-dragged-item! % @item)
                (reset! drag-source? true)
                true)
   :dragend drag-end!

   ; Drag target attributes.
   :data-drag-target (j/cell= (and drag-target? (not drag-source?)))
   :dragenter #(do (.preventDefault %)
                (reset! drag-target? true)
                false)
   :dragover #(do
               (-&gt; % .-originalEvent .-dataTransfer (aset "dropEffect" "move"))
               (.preventDefault %)
               (reset! drag-target? true)
               false)
   :dragleave #(do (reset! drag-target? false)
                false)
   :drop #(j/dosync
           (.stopPropagation %)
           (drag-end!)
           (let [; The dropzone item might actually be a new item, in which
                 ; case we just want to move the dropped item to the end of
                 ; the list.
                 anchor-item (if @new-item?
                              (or (last @list) @item)
                              @item)]
            (item-list.api/move-item-after! conn @list anchor-item (event-&gt;dragged-item %)))
           (reset! dropped-item (event-&gt;dragged-item %))
           false)

   children)))

2017-12-15T01:05:39.000123Z

it works OK, but i haven't made a very nice animation/styles for it yet

2017-12-15T01:06:36.000256Z

and also ckeditor is too helpful, if i drag something onto the wysiwyg then it puts the raw dataTransfer data into the editor as EDN

micha 2017-12-15T01:07:40.000263Z

what is the dataTransfer data? is that part of a built-in drag and drop api?

2017-12-15T01:07:44.000179Z

yeah

2017-12-15T01:07:49.000058Z

dnd api is crazy

micha 2017-12-15T01:08:00.000081Z

wow never even heard of it

2017-12-15T01:08:23.000178Z

you serialise data from the thing being dragged and it gets passed to the thing being dropped onto

2017-12-15T01:09:10.000136Z

thank god for pr-str and read-string in cljs

micha 2017-12-15T01:09:32.000215Z

lol yeah

2017-12-15T01:09:44.000111Z

the nice thing is that you can then drop that serialised data anywhere, including your desktop or other tabs/browser windows

2017-12-15T01:10:03.000142Z

or drop a file from your desktop into the page and receive it as serialised data

micha 2017-12-15T01:10:32.000304Z

not sure how i feel about that

2017-12-15T01:10:56.000198Z

you will definitely experience some emotions working through this api >.<

micha 2017-12-15T01:11:04.000078Z

like i never would imagine that i could just drag stuff from one browser to another

micha 2017-12-15T01:11:07.000049Z

as a user

2017-12-15T01:11:18.000023Z

well you say that, but think of google drive

2017-12-15T01:11:52.000061Z

it's pretty natural in that situation to want to drag things around outside the single browser tab

micha 2017-12-15T01:12:30.000094Z

weird i've never even tried it

2017-12-15T01:13:12.000066Z

well i assume it works, lol

2017-12-15T01:13:15.000062Z

it seems like it should

micha 2017-12-15T01:13:19.000145Z

just seems like kind of a weird thing that is only available on certain webapps

2017-12-15T01:13:45.000277Z

yes definitely

micha 2017-12-15T01:14:11.000234Z

and in order to make it ubiquitous you'd need to basically solve the clipboard problem, a universal serialization of arbitrary things

2017-12-15T01:14:43.000122Z

the general consensus seems to be that the native dnd api is weird and hard to work with >.<

2017-12-15T01:15:51.000231Z

although the extra events are handy

micha 2017-12-15T01:16:07.000056Z

does it work in all browsers?

2017-12-15T01:16:19.000227Z

you get real drag events, rather than needing to try and reverse engineer something from raw mouse events

2017-12-15T01:16:46.000089Z

mostly yeah https://caniuse.com/#feat=dragndrop

micha 2017-12-15T01:17:09.000195Z

yeah those events look pretty handy

2017-12-15T01:17:48.000002Z

looks like there are some polyfills around too

2017-12-15T01:19:37.000132Z

^^ but it's a bit tooo wysiwyg friendly >.<

2017-12-15T01:24:38.000195Z

i think i can fix/disable this behaviour, just looking into it 🙂

micha 2017-12-15T01:25:37.000069Z

:dragover #(do
               (-&gt; % .-originalEvent .-dataTransfer (aset "dropEffect" "move"))
               (.preventDefault %)
               (reset! drag-target? true)
               false)

micha 2017-12-15T01:26:17.000149Z

does that send a message when you are dragging an element

micha 2017-12-15T01:26:30.000229Z

like a message to the element you are dragging it over?

2017-12-15T01:39:54.000007Z

ah, yeah so thats an event on the dragged over element

2017-12-15T01:40:08.000051Z

in this context i have a list of things that can be dragged to re-arrange

2017-12-15T01:40:31.000238Z

so i need to put both the "thing being dragged" and "being dragged over/onto" events on all the items

2017-12-15T01:41:13.000137Z

the dataTransfer property has more than just the data in it, in this case i'm actually setting the "dropEffect"

2017-12-15T01:41:28.000113Z

which is literally just what it looks like

2017-12-15T01:41:30.000186Z

non-functional

2017-12-15T01:41:57.000227Z

the preventDefault is what you need to do to enable drag events, because the default behaviour is to disable drag events

micha 2017-12-15T01:42:22.000152Z

hahaha prevent disabling

micha 2017-12-15T01:42:25.000037Z

i like it

2017-12-15T01:43:11.000109Z

:drop #(j/dosync
           (.stopPropagation %)
           (drag-end!)
           (let [; The dropzone item might actually be a new item, in which
                 ; case we just want to move the dropped item to the end of
                 ; the list.
                 anchor-item (if @new-item?
                              (or (last @list) @item)
                              @item)]
            (item-list.api/move-item-after! conn @list anchor-item (event-&gt;dragged-item %)))
           (reset! dropped-item (event-&gt;dragged-item %))
           false)

2017-12-15T01:43:56.000042Z

this is the end of the dragging, at the drop

2017-12-15T01:44:33.000157Z

that's where i'm actually extracting the data

2017-12-15T01:44:47.000064Z

but you could do that in different ways too, depending on what you're trying to achieve

micha 2017-12-15T01:45:25.000219Z

you probably don't really need to use the dataTransfer stuff

micha 2017-12-15T01:45:33.000300Z

if you're not dragging things across windows

2017-12-15T01:46:13.000171Z

well it's the only way to communicate between the thing being dragged and thing being dragged onto using the events

2017-12-15T01:46:37.000201Z

but you could probably do something with cells too

micha 2017-12-15T01:46:51.000062Z

i mean you can still do what you'd do without the dnd api

micha 2017-12-15T01:46:53.000274Z

yeah

micha 2017-12-15T01:47:01.000044Z

and just use the events themselves

micha 2017-12-15T01:47:11.000018Z

without needing to pass information inside the events

2017-12-15T01:47:40.000052Z

yeah, passing information is the standard integration point

2017-12-15T01:48:04.000157Z

actually it probably makes perfect sense if you wanted to drag an image from your desktop into a wysiwyg

2017-12-15T01:48:32.000193Z

but if you just want a self contained dnd with the events you could just hook some basic cells up

micha 2017-12-15T01:48:57.000010Z

yeah if you're dragging things across windows you need to serialize

2017-12-15T01:49:18.000194Z

or across your app

2017-12-15T01:49:30.000198Z

you can drop onto anything

2017-12-15T01:49:56.000234Z

you might not want to maintain global state cells or many state cells if you have a lot of dnd

2017-12-15T01:50:26.000214Z

it could be easier to just handle the logic of "something just got dropped onto this element" like any other event handler

2017-12-15T01:51:15.000022Z

a flat list of identically structured items is really a special case of what the api can do

2017-12-15T01:53:16.000082Z

it could be handy if you were making a game, where basically anything can be dropped onto anything else

micha 2017-12-15T01:59:38.000191Z

right

micha 2017-12-15T02:00:21.000155Z

it's weird though, because dnd is basically cut and paste

micha 2017-12-15T02:00:38.000042Z

is there some awesome cut and paste api too that i don't know about?

2017-12-15T02:12:14.000072Z

i really wouldn't call any of these apis "awesome"...

2017-12-15T15:08:16.000017Z

@micha Will you repost your DnD implementation. Just noticed the Slack log is not logging this channel since mid November 😞 https://clojurians-log.clojureverse.org/hoplon/index.html

2017-12-15T15:22:50.000478Z

What would be the easiest approach to getting drag and drop working with touch/multi-touch. My understanding is that there are significant differences between click events and touch events, and the touch events are not in Jquery by default. Do you generally need a special library or polyfill, etc?

2017-12-15T15:22:54.000241Z

Even if the native browser Api is wierd, would it be advisable to just use, or use raw touch events with Hoplon cells, as discussed above?

2017-12-15T15:23:44.000111Z

Maybe this is a sucessor to hammer.js to add touch events to jQuery https://github.com/benmajor/jQuery-Touch-Events

2017-12-15T15:25:18.000366Z

chromalchemy i think this is micha's gist: https://gist.github.com/micha/4855e90e3085c91768faf150ab0035c3

2017-12-15T15:26:10.000172Z

@alandipert Thx!

2017-12-15T15:26:33.000672Z

interact.js looks pretty slick. http://interactjs.io/ I'm not confident with js interop, so try to stick closely to jquery... any thoughts though?

2017-12-15T15:29:03.000220Z

a couple years ago micha made a touch app w/ hoplon, i think with hammer.js or jq touch. and the integration point was do!, he seemed happy with it iirc

2017-12-15T15:37:22.000394Z

Was that related to this https://github.com/tailrecursion/hoplon.hammerjs/blob/master/src/tailrecursion/hoplon/hammerjs.cljs ? Here it is using on!

micha 2017-12-15T15:38:40.000487Z

yeah we used it in a mobile app we made, it worked pretty well

micha 2017-12-15T15:40:04.000376Z

the dnd thing i made only needs to have some event like mousedown and mouseup, not sure what those are with touch devices

micha 2017-12-15T15:45:58.000529Z

seems like they rejected the draft for touchenter event

micha 2017-12-15T15:46:19.000453Z

so you'd need to make or find a polyfill to get that functionality