<commit_before># General outline of how this works:
#
# 1. Xray metadata code is inserted during asset compilation.
#    a. For Backbone.Views, JS is inserted that will record the Backbone.View
#       constructor with its metadata in window.XrayData
#    b. For templates, <script> tags are inserted at the beginning and the end
#       of the template.
#
# 2. After DOM is loaded, go through XrayData, hooking into Backbone.View to
#    add view instances to Xray.elements as they're instantiated. NOTE: This
#    means Xray has to be included into a page before any app code runs so its
#    DOM loaded callback can happen first. Not a big deal.
#
# 3. Xray is invoked via keyboard shortcut
#    a. Go through the DOM looking for template script tags. Create Elements
#       representing them. (regenerate on each invocation?)
#    b. Turn created Xray.elements into boxes and display them in the overlay.

window.Xray = {}

# Container for Xray.Element instances
Xray.elements = []

# Initialize Xray - hook into Backbone.View to create Xray.Elements as the views
# are instantiated.
Xray.init = ->
  return if Xray.initialized
  Xray.initialized = true

  if window.XrayData and window.Backbone?.View
    _delegateEvents = Backbone.View::delegateEvents
    Backbone.View::delegateEvents = ->
      _delegateEvents.apply(this, arguments)
      if info = Xray.constructorInfo(this.constructor)
        Xray.add this.el, JSON.parse(info)
    _remove = Backbone.View::remove
    Backbone.View::remove = ->
      _remove.apply(this, arguments)
      Xray.remove this.el

Xray.constructorInfo = (constructor) ->
  for own info, func of window.XrayData
    return info if func is constructor

# Scans the document for templates, creating Xray.Elements for them.
Xray.addTemplateElements = ->
  for beginScript in $('script[type="xray-template-start"]')
    path = $(beginScript).attr('data-xray-path')
    # This could very well be multiple elements. Xray.add() supports adding
    # a jQuery object wrapping multiple elements for this reason.
    el = $(beginScript).nextUntil('script[type="xray-template-end"]')
    continue if Xray.findElement(el)
    Xray.add el,
      name: path.split('/').slice(-1)[0]
      path: path

# Open the given filesystem path by calling out to Xray's server.
# TODO: error handling of any kind, XSS warnings
Xray.open = (path) ->
  $.post "http://localhost:62010/open", path

# Add a DOM element with associated metadata to be tracked by Xray
Xray.add = (el, info = {}) ->
  console.log info
  Xray.elements.push new Xray.Element(el, info)

# Remove a DOM element from Xray
Xray.remove = (el) ->
  if el instanceof Xray.Element
    Xray.elements.splice(Xray.elements.indexOf(el), 1)
  else
    Xray.remove Xray.findElement(el)

Xray.findElement = (el) ->
  el = el[0] if el instanceof jQuery
  for element in Xray.elements
    return element if element.el == el
  null

# Show the Xray overlay
Xray.show = ->
  console.log 'X-raying'
  Xray.Overlay.instance().show()

# Hide the Xray overlay
Xray.hide = ->
  console.log 'Hiding X-ray'
  Xray.Overlay.instance().hide()

# Wraps a DOM element that Xray is tracking
class Xray.Element
  constructor: (el, @attrs = {}) ->
    @el = if el instanceof jQuery then el[0] else el
    @$el = $(el)
    @name = @attrs.name
    @path = @attrs.path

  isVisible: ->
    @$el.is(':visible')

  makeBox: ->
    bbox = @_computeBoundingBox()
    @$box = $('<div>').css
      position   : 'absolute'
      background : 'rgba(255,255,255,0.8)'
      color      : '#999'
      fontFamily : '"Helvetica Neue", sans-serif'
      zIndex     : 99999
      top        : bbox.top
      left       : bbox.left
      width      : bbox.width
      height     : bbox.height
    @$box.click => Xray.open @path
    @$box.append @name
<commit_msg>Use HTML comments instead of script tags to delineate templates<commit_after># General outline of how this works:
#
# 1. Xray metadata code is inserted during asset compilation.
#    a. For Backbone.Views, JS is inserted that will record the Backbone.View
#       constructor with its metadata in window.XrayData
#    b. For templates, HTML comments are inserted at the beginning and the end
#       of the template.
#
# 2. After DOM is loaded, go through XrayData, hooking into Backbone.View to
#    add view instances to Xray.elements as they're instantiated. NOTE: This
#    means Xray has to be included into a page before any app code runs so its
#    DOM loaded callback can happen first. Not a big deal.
#
# 3. Xray is invoked via keyboard shortcut
#    a. Go through the DOM looking for template script tags. Create Elements
#       representing them. (regenerate on each invocation?)
#    b. Turn created Xray.elements into boxes and display them in the overlay.

window.Xray = {}

# Container for Xray.Element instances
Xray.elements = []

# Initialize Xray - hook into Backbone.View to create Xray.Elements as the views
# are instantiated.
Xray.init = ->
  return if Xray.initialized
  Xray.initialized = true

  if window.XrayData and window.Backbone?.View
    _delegateEvents = Backbone.View::delegateEvents
    Backbone.View::delegateEvents = ->
      _delegateEvents.apply(this, arguments)
      if info = Xray.constructorInfo(this.constructor)
        Xray.add this.el, JSON.parse(info)
    _remove = Backbone.View::remove
    Backbone.View::remove = ->
      _remove.apply(this, arguments)
      Xray.remove this.el

Xray.constructorInfo = (constructor) ->
  for own info, func of window.XrayData
    return info if func is constructor

# Scans the document for templates, creating Xray.Elements for them.
Xray.addTemplateElements = ->
  comments = $('*').contents().filter ->
    this.nodeType == 8 and this.data[0..10] == " XRAY START"
  for comment in comments
    [_, id, path] = comment.data.match(/^ XRAY START (\d+) (.*) $/)
    $templateContents = new jQuery
    el = comment.nextSibling
    until !el or (el.nodeType == 8 and el.data == " XRAY END #{id} ")
      $templateContents.push el if el.nodeType == 1
      el = el.nextSibling
    Xray.add $templateContents,
      name: path.split('/').slice(-1)[0]
      path: path

# Open the given filesystem path by calling out to Xray's server.
# TODO: error handling of any kind, XSS warnings
Xray.open = (path) ->
  $.post "http://localhost:62010/open", path

# Add a DOM element with associated metadata to be tracked by Xray
Xray.add = (el, info = {}) ->
  unless Xray.findElement(el)
    Xray.elements.push new Xray.Element(el, info)

# Remove a DOM element from Xray
Xray.remove = (el) ->
  if el instanceof Xray.Element
    Xray.elements.splice(Xray.elements.indexOf(el), 1)
  else
    Xray.remove Xray.findElement(el)

Xray.findElement = (el) ->
  el = el[0] if el instanceof jQuery
  for element in Xray.elements
    return element if element.el == el
  null

# Show the Xray overlay
Xray.show = ->
  Xray.Overlay.instance().show()

# Hide the Xray overlay
Xray.hide = ->
  Xray.Overlay.instance().hide()

# Wraps a DOM element that Xray is tracking
class Xray.Element
  constructor: (el, attrs = {}) ->
    @el = if el instanceof jQuery then el[0] else el
    @$el = $(el)
    @name = attrs.name
    @path = attrs.path

  isVisible: ->
    @$el.is(':visible')

  makeBox: ->
    bbox = @_computeBoundingBox()
    @$box = $('<div>').css
      position   : 'absolute'
      background : 'rgba(255,255,255,0.8)'
      color      : '#666'
      fontFamily : '"Helvetica Neue", sans-serif'
      fontSize   : '13px'
      zIndex     : 99999
      top        : bbox.top
      left       : bbox.left
      width      : bbox.width
      height     : bbox.height
    @$box.click => Xray.open @path
    @$box.append @name

{'fraction_non_alphanumeric': 0.10852612425266442, 'fraction_numerical': 0.009357941252924357, 'mean_word_length': 3.0078125, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4724483', 'n_tokens_mistral': 2442, 'n_tokens_neox': 2373, 'n_words': 812}