   (reify
     om/IRenderState
     (render-state [this {:keys [index current?]}]
-      (dom/div #js {:className (if current? "current-track track" "track")}
-               (dom/span #js {:className "artist"} (get track "artist"))
-               (dom/span #js {:className "album"} (get track "album" ))
-               (dom/span #js {:className "title"} (get track "title"))
-               (dom/span #js {:className "duration"} (mmss (get track "length")))
-               (dom/button #js {:onClick #(dequeue-track index)}
-                           "-")))))
+      (let [command-chan (om/get-shared owner :command-channel)]
+        (html
+         [:div {:className (if current? "current-track track" "track")}
+          [:span {:className "artist"} (get track "artist")]
+          [:span {:className "album"} (get track "album" )]
+          [:span {:className "title"} (get track "title")]
+          [:span {:className "duration"} (mmss (get track "length"))]
+          [:button {:onClick #(put! command-chan [:dequeue index])}
+           "-"]])))))
 
 (defn audio-el [state owner]
   (reify
     om/IDidMount
     (did-mount [_]
       (let [el (om/get-node owner)]
-        ;; last arg "true" is cos audio events don't bubble
-        ;; http://stackoverflow.com/questions/11291651/why-dont-audio-and-video-events-bubble
-        (.addEventListener el "ended" player-next true)
-        (.addEventListener el "timeupdate" player-playing true)))
+        ;; add capturing handler (last arg "true")
+        ;; cos audio events don't bubble
+        (.addEventListener el "ended"
+                           #(om/update! state [:ended] true)
+                           true)
+        (.addEventListener el "timeupdate"
+                           #(om/update! state [:time-offset]
+                                        (.-currentTime (.-target %))))))
     om/IRender
     (render [_]
       (html [:audio {:ref "player"}]))))

  (reify
    om/IRender
    (render [this]
      (let [queue (om/observe owner (player-queue))]
        (html
         [:div {}
          [:div {:className "track header"}
           [:span {:className "artist"} "Delete queue"]
           [:button {:onClick #(dequeue-all)} "-"]]
          (map #(om/build queue-track-view
                          %1
                          {:state
                           {:index %2
                            :current? (= (-> app :player :track-number)
                                         %2)
                            }})
               queue (range 0 999))
          ])))))

           [:span {:className "album"}
            (get track "album")]]
          [:span {:className "buttons"}
           [:button {:onClick
                     (swallowing #(put! command-chan [:previous-track]))}
            (svg-skip-track :backwards)]
           [:button {:onClick
                     (swallowing #(put! command-chan [:toggle-pause]))}
            (case playing
              true (svg-pause)
              :pending (svg-spinner)
              false (svg-play))]
           [:button {:onClick
                     (swallowing #(put! command-chan [:next-track]))}
            (svg-skip-track)]]
          [:span {:className "offset"}
           [:span {:className "elapsed-time time"}
            (mmss (-> wanted :audio-el :time-offset))]
           " / "
           [:span {:className "track-time"}
            (mmss (get track "length" 0))]]
