           imagesInternal[id].count += 1
           checkImageInternal id
       @imagesInternal = newImagesInternal
+
+  if oldFolded? and oldDefault == defaultFolded.get @data._id
+    unless oldFolded == messageFolded.get @data._id
+      messageFolded.set @data._id, oldFolded
+  else
+    messageFolded.set @data._id, defaultFolded.get @data._id
+
+#Session.setDefault 'images', {}
+images = {}
+imagesInternal = {}
+id2template = {}
+scrollToLater = null
+fileQuery = null
+
+updateFileQuery = _.debounce ->
+  fileQuery.stop() if fileQuery?
+  fileQuery = Messages.find
+    _id: $in: _.keys images
+  ,
+    fields: file: true
+  .observeChanges
+    added: (id, fields) ->
+      #console.log "#{id} added:", fields
+      images[id].file = fields.file
+      if images[id].file?
+        initImageInternal images[id].file, id
+        checkImageInternal images[id].file
+    changed: (id, fields) ->
+      #console.log "#{id} changed:", fields
+      if fields.file? and images[id].file != fields.file
+        if fileType(fields.file) in ['image', 'video']
+          forceImgReload urlToFile id
+        imagesInternal[images[id].file].image = null if images[id].file?
+        images[id].file = fields.file
+        if images[id].file?
+          initImageInternal images[id].file, id
+          checkImageInternal images[id].file
+, 250
+
+initImage = (id) ->
+  if id not of images
+    images[id] =
+      count: 0
+      file: null
+    updateFileQuery()
+
+initImageInternal = (id, image = null) ->
+  #console.log "initImageInternal #{id}, #{image}"
+  if id not of imagesInternal
+    imagesInternal[id] =
+      count: 0
+      image: image
+  else if image?
+    imagesInternal[id].image = image
+
+checkImage = (id) ->
+  return unless id of images
+  ## Image gets unnaturally folded if it's referenced at least once
+  ## and doesn't have any children (don't want to hide children, and this
+  ## can also lead to infinite loop if children has the image reference).
+  newDefault = images[id].naturallyFolded or
+    (not images[id].children and
+     (images[id].count > 0 or
+      (imagesInternal[images[id].file]? and
+       imagesInternal[images[id].file].count > 0)))
+  if newDefault != defaultFolded.get id
+    defaultFolded.set id, newDefault
+    messageFolded.set id, newDefault
+  ## No longer care about this image if it's not referenced and doesn't have
+  ## a rendered template.
+  if images[id].count == 0 and id not of id2template
+    delete images[id]
+    updateFileQuery()
+
+checkImageInternal = (id) ->
+  image = imagesInternal[id].image
+  #console.log "#{id} corresponds to #{image}"
+  checkImage image if image?
+
+messageDrag = (target, bodyToo = true, old) ->
+  return unless target
+  onDragStart = (e) =>
+    #url = "coauthor:#{@data._id}"
+    url = urlFor 'message',
+      group: @data.group
+      message: @data._id
+    e.dataTransfer.effectAllowed = 'linkMove'
+    e.dataTransfer.setData 'text/plain', url
+    e.dataTransfer.setData 'application/coauthor-id', @data._id
+    e.dataTransfer.setData 'application/coauthor-type', type
+  type = 'message'
+  if @data.file
+    type = fileType @data.file
+    #console.log @data.file, type
+    #if "class='odd-file'" not in formatted and
+    #   "class='bad-file'" not in formatted
+    #  url = formatted
+    if bodyToo
+      $(@find '.message-file')?.find('img, video, a, canvas')?.each (i, elt) =>
+        elt.removeEventListener 'dragstart', old if old?
+        elt.addEventListener 'dragstart', onDragStart
+  target.removeEventListener 'dragstart', old if old?
+  target.addEventListener 'dragstart', onDragStart
+  onDragStart
+
+## A message is "naturally" folded if it is flagged as minimized or deleted.
+## It still will be default-folded if it's an image referenced in another
+## message that is not naturally folded.
+export naturallyFolded = (data) -> data.minimized or data.deleted
+
+Template.submessage.onRendered ->
+  ## Random message background color (to show nesting).
+  #@firstNode.style.backgroundColor = '#' +
+  #  Math.floor(Math.random() * 25 + 255 - 25).toString(16) +
+  #  Math.floor(Math.random() * 25 + 255 - 25).toString(16) +
+  #  Math.floor(Math.random() * 25 + 255 - 25).toString(16)
+
+  ## Drag/drop support.
+  focusButton = $(@find '.message-left-buttons').find('.focusButton')[0]
+  @autorun =>
+    listener = messageDrag.call @, focusButton, true, listener
+
+  ## Scroll to this message if it's been requested.
+  if scrollToLater == @data._id
+    scrollToMessage @data._id
 
   ## Image rotation
   @autorun =>

  @lastTitle = null
  @savedTitles = []

  ## Fold naturally folded (minimized and deleted) messages
  ## by default on initial load.
  defaultFolded.set @data._id, natural = naturallyFolded @data
  messageFolded.set @data._id, true if natural

  @autorun =>
    data = Template.currentData()
    return unless data?

    #console.log 'automathjax'
    automathjax()

  ## Fold naturally folded (minimized and deleted) messages by default on
  ## initial load.  But only if not previously manually overridden.
  oldDefault = defaultFolded.get @data._id
  oldFolded = messageFolded.get @data._id
  defaultFolded.set @data._id, naturallyFolded @data

  ## Fold referenced attached files by default on initial load.
  #@$.children('.panel').children('.panel-body').find('a[href|="/file/"]')
