levand / domina

A DOM manipulation library for ClojureScript
429 stars 46 forks source link

events/listen! does not work with :optimizations :advanced (??) #57

Closed deg closed 11 years ago

deg commented 11 years ago

This seems weird enough that I assume the problem lies in my code, but I don't see what I'm doing wrong...

My code works correctly until I compile it with :optimizations :advanced. Then, the domina event listener seems to return a raw object, rather than the DOM node I expected:

(defn dbg1 [x]
  (log "1: " (by-id "tabbar"))
  (log "2: " x))

(defn ^:export init []
  (events/listen! (by-id "tabbar") :click #(dbg1 %)))

I click on the page, and the console shows:

1: [object HTMLDivElement] 2: [object Object]

ddellacosta commented 11 years ago

deg, you've probably resolved this by now, but this looks like normal behavior to me. Domina returns a wrapped event object to the listen! function argument. Have you tried calling anything like "raw-event" or whatnot on the object in your function, and examining that output?

https://github.com/levand/domina#event-objects

For example, to get the clicked element, you would call (current-target event-obj).

EDIT: the perplexing thing to me is that this works at all when you don't have advanced compilation on, because as far as I can tell this is proper behavior...

deg commented 11 years ago

(Whoops, I thought I answered this a few days ago, but I apparently never hit send, or something)

I'll need to look at this more carefully tomorrow, but I've just confirmed that the problem still occurs. The relevant code has morphed a bit since I first submitted the report; it's now:

(defn ^:export init []
  ...
  (events/listen! (dom/by-id "tabbar") :click
    #(-> % events/target (. -id) ...))
  ...)

Works fine with :optimizations :simple, but :advanced gives

Uncaught Error: No protocol method Event.target defined for type object: [object Object] 
deg commented 11 years ago

Ok, I've looked at this a bit more carefully. I've verified that when I compile :advanced, the object that is passed to my listener does not respond to domina.events/target, .../raw-event, etc. In all cases, I get the error Uncaught Error: No protocol method Event.xxx defined for type object: [object Object]

So, I guess the key question is: Am I doing something wrong in my project.clj and/or my call to listen!, or does Domina not yet fully support :advanced mode?

... The rest of this message is my attempt to debug the obfuscated JS code. Ignore if I've gone off-track:

It looks like the problem is something in the compilation of Domina's Event defprotocol that goes awry in advanced mode.

First, for reference, here is the code generated in :simple mode:

domina.events.target = function(a) {
  if(a ? a.domina$events$Event$target$arity$1 : a) {
    return a.domina$events$Event$target$arity$1(a)
  }
  var b;
  b = domina.events.target[goog.typeOf(null == a ? null : a)];
  if(!b && (b = domina.events.target._, !b)) {
    throw cljs.core.missing_protocol.call(null, "Event.target", a);
  }
  return b.call(null, a)
};

Here is the code generated in :advanced mode:

function zj(a) {
  if(a ? a.Vc : a) {
    return a.ca.target
  }
  var b;
  b = zj[p(null == a ? null : a)];
  if(!b && (b = zj._, !b)) {
    throw v("Event.target", a);
  }
  return b.call(null, a)
}

In simple mode, the first line succeeds, and the target is returned immediately.

In advanced mode, a.VC seems to be undefined. a itself seems to the object jQuery.fn.jQuery.init[1] (But, big caveat, I'm a complete newbie at debugging JavaScript, so I may be misreading the debugger here).

ddellacosta commented 11 years ago

a itself seems to the object jQuery.fn.jQuery.init[1]

Why is jQuery in there? This should be straight domina/Google Closure objects that you're dealing with. This is starting to smell like namespace collisions in advanced mode...

What other javascript/Clojurescript libs are you using? Assuming you're not--do you get the same issues when you isolate this bit of code to a separate project, with nothing but Domina included?

ddellacosta commented 11 years ago

Sorry to not answer this: Am I doing something wrong in my project.clj and/or my call to listen!, or does Domina not yet fully support :advanced mode?

Domina most definitely supports advanced mode--I'm using it now in a production app. So there is probably something going on with the collection of libs you are including/namespaces you're importing into your code/etc. (based on my own experiences getting advanced compilation working w/domina and other libs).

deg commented 11 years ago

Thanks; good to know that the problem is contained. I'll start pruning/testing my project.clj later today -- have to run to a few meetings first. I'll let you know what I find; hope it's just some simple collision to add to the readme.

Meanwhile, here's my project.clj, in case something obvious catches your eye. (Sorry, it's a bit of a mess, assembled from too many different sources and failed experiments. I'm aiming to clean it up too, in this round of testing).

(defproject receipts "0.1.0-SNAPSHOT"
  :description "HTML5 web-app to manage our receipts."
  :url "https://bitbucket.org/degeldeg/receipts"
  :license {:name "Proprietary software - this is not open-source"
            :url "http://nonesuch/com/no-license.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]

                 ;; Degel's Clojure utility library
                 [degel-clojure-utils "0.1.12"]

                 ;; Degel's Redmapel state tree library
                 [redmapel "0.1.7"]

                 ;; Parser tools
                 [instaparse "1.2.2"]

                 ;; Needed, I think, in order to build a runnable uberjar with compojure
                 [ring/ring-jetty-adapter "1.1.8"]

                 ;; Routing library for Ring web application library
                 [compojure "1.1.5" :exclusions [ring/ring-core org.clojure/tools.macro]]

                 ;; DOM manipulation library for ClojureScript
                 [domina "1.0.2-SNAPSHOT"]

                 ;; HTML templating.
                 ;; [TODO] {FogBugz:139} Compare with Hiccup. Maybe choose just one
                 [enlive "1.1.1"]

                 ;; HTML generation for Clojurescript (Ported from Clojure Hiccup)
                 [hiccups "0.2.0"]

                 ;; Ring/Compojure RPC
                 ;; [TODO] {FogBugz:139} Look at the other Shoreleave libs too. Support for
                 ;;        local storage, browser history, repl, etc.
                 [shoreleave/shoreleave-remote-ring "0.3.0"]
                 [shoreleave/shoreleave-remote "0.3.0"]

                 ;; Clojure/ClojureScript validation
                 [com.cemerick/valip "0.3.2"]

                 ;; Clojure interface to AWS SimpleDB
                 [com.cemerick/rummage "1.0.1" :exclusions [commons-codec]]]

  :plugins [[lein-cljsbuild "0.3.2" :exclusions [org.clojure/clojure]]
            [lein-ring "0.8.3" :exclusions [org.clojure/clojure]]
            [com.cemerick/austin "0.1.0"]

            ;; Not supported in lein 2.2.0, but here as a reminder to get features
            ;; mentioned in https://groups.google.com/forum/#!msg/clojure/9cA5hvFJTkw/fnWwxvALd64J
            #_[lein-pedantic "0.0.5"]
            ]

  :min-lein-version "2.0.0"

  :source-paths ["server-src"]
  :test-paths ["test"]
  :ring {:handler degel.receipts.server/app}
  ;:profiles {:dev {:hooks [leiningen.cljsbuild]}}
  :main degel.receipts.server

  :cljsbuild {:crossovers [valip.core
                           valip.predicates
                           degel.cljutil.utils
                           degel.redmapel
                           degel.redmapel.node
                           degel.receipts.db
                           degel.receipts.static-validators]
              :builds {#_ :dev
                       #_
                       {:source-paths ["client-src"]
                        :compiler {:output-to "resources/public/js/receipts-dev.js"
                                   :optimizations :whitespace
                                   :libs [""] ;; See https://github.com/cemerick/pprng/
                                   :pretty-print true}
                        :jar false},
                       :production
                       {:source-paths ["client-src"]
                        :compiler {:output-to "resources/public/js/receipts.js"
                                   ;; TODO {FogBugz:134} No :advanced until dom issue resolved;
                                   ;;      No :advanced so REPL will work, until :dev is
                                   ;;      usable again (per 'lib ""' bug)
                                   :optimizations #_ :advanced :simple
                                   :libs [""] ;; See https://github.com/cemerick/pprng/
                                   :pretty-print #_ false true}
                        :jar true}}})
deg commented 11 years ago

Problem found; the clue was your comment about jquery.

My project uses bootstrap.js which, in turn, requires the inclusion of jquery.js. I pulled those two lines out of my html file and the problem went away.

Fortunately, the only features of bootstrap I actually use are in the css, so this change has near-zero impact on my project.

The control that showed the problem was a bootstrap button. So, I assume that the only connection to domina is that the domina call happened to be the first interesting access of that object. Looks like this issue can be closed as a red herring. Sorry!

But, for my future reference, do you happen to know if either jquery or bootstrap are known not to work with advanced compilation?

ddellacosta commented 11 years ago

Oh, great! Glad to hear that you figured it out.

But, for my future reference, do you happen to know if either jquery or bootstrap are known not to work with advanced compilation?

Well, I can't speak to bootstrap, but considering that jayq does (we have it in our project, although we deprecated it in favor of domina...for now), and bootstrap is mostly jQuery code (right?) it should work. Assuming you've got the right externs (https://developers.google.com/closure/compiler/docs/api-tutorial3#externs) set up it should be okay.

deg commented 11 years ago

Yeah, umm, about those externs... (embarrassed grin). No, I didn't have any, but discovered the need yesterday when I Googled for jquery and closure. But, since I don't actually need the bootstrap or jquery js files at all, I just diked out the two references and don't need to learn the extern syntax until next time.

Thanks again. All's well that ends.

ddellacosta commented 11 years ago

Yeah--I've really only ever needed the externs in a limited way, when I'm calling JS code in my CLJS, and most of the time I wrap stuff up in a function or two and that does it.

In any case, glad to hear things are working.

ckirkendall commented 11 years ago

I am closing this issue because the resolution was outside of domina.