As much as I try, I cannot seem to get this Coffeescript code to look beautiful (I'd like to think it is possible). I have tried both Javascript and Coffeescript. Just to be clear, this code works fine, but it is hard to read, for reasons that I am unable to pinpoint.
How can it be refactored, reorganized, and what changes to coding style can be made to make it more appealing to read?
define [
"plugins/ui/ui",
"./js/highlight"
], (ui, highlight) ->
editor = {}
jQuery ($) ->
# A widget to view source code.
$.widget 'core.editor',
_create: ->
$editor = $(this.element)
$editor
.addClass('editor')
.append($('<ul spellcheck="false" contenteditable> <li></li> </ul>'))
# Move the gutter along with the editable area.
this.lines().bind 'scroll', (event) ->
$this = $(this)
$this.siblings(".gutter").css(top: $this.scrollTop() * -1)
# Highlight the sourceview using the given language.
# The language's JSON rule file is loaded.
highlight: (language) ->
this.language = language
require ["text!plugins/editor/js/#{ language }.json"], (json) =>
this._rules = JSON.parse(json)
return
# Update the `left` of the `<ul>` based on the gutter width.
# Each time the number of digits in the gutter changes, it becomes wider or
# narrower, and the editor needs the shift accordingly.
updateGutterWidth: () ->
# The `8` is the gutter's left padding.
this.lines().css(left: this.gutter().width() + 8)
# Add or remove line numbers if the number of lines has changed.
# `change` is a modification the the line count (In case the character was not yet
# typed).
updateLineNumbers: (change = 0) ->
$gutter = this.gutter()
count = this.lines().children("li").length
current = $gutter.children("span").length
count += change
# Add lines
if (count > current)
for i in [current..(count - 1)]
ele = document.createElement("span")
ele.innerText = "#{ i + 1 }"
$gutter[0].appendChild(ele)
# Remove lines
else if (current > count)
for j in [count..(current - 1)]
$gutter.children("span:last-child").remove()
this.updateGutterWidth() if current != count
return
# Set whether or not the gutter should be visible.
lineNumbers: (bool) ->
if bool == true and !this.number
$(this.element)
.prepend('<div class="gutter"></div>')
this.lines()
.css(left: 20)
this.updateLineNumbers()
else if bool == false and this.number
this.gutter().remove()
$(this.element)
.css(left: 1)
this.number = bool
# Return the gutter (a jQuery object).
gutter: () ->
this._gutter ?= $(this.element).children("div.gutter")
return this._gutter
# Return a jQuery `<ul>`. Each `<li>` is a line of the source viewer.
lines: ->
return $(this.element).children('ul')
# A hash of syntax highlighting rules.
rules: ->
return this._rules
# Re-highlight the text.
$(".editor > ul").live 'keyup', (event) ->
# 13: Enter
# 37, 38, 39, 40: Arrow Keys
# 33, 34: Page up / down
# 16, 17, 18, 91: Shift, Ctrl, Alt, Meta
# 35, 36: Home / end
if !(event.which in [13, 37, 38, 39, 40, 33, 34, 16, 17, 18, 91, 35, 36]) and !event.altKey and !event.ctrlKey
# Prevent an annoying error when backspacing to the beginning of a line.
selection = window.getSelection()
# Store the cursor position before highlighting.
cursorPos = selection.getRangeAt(0)
if cursorPos.getClientRects()[0]
clickx = cursorPos.getClientRects()[0].left
clicky = cursorPos.getClientRects()[0].top
# Highlight
$li = $(selection.focusNode).closest("li")
rules = $li.closest(".editor").editor('rules')
highlight.highlight($li, rules)
# Restore cursor position.
cursorPos = document.caretRangeFromPoint(clickx, clicky)
window.getSelection().addRange(cursorPos)
# Line numbering update.
$(".editor > ul").live 'keydown', (event) ->
# Redo line numbering for Enter, Backspace, Delete.
if (event.which in [13, 8, 46])
$this = $(this)
newline = switch event.which
when 13 then 1
when 8 then -1
else 0
$this.parent().editor('updateLineNumbers', newline)
# Correction
setTimeout(() ->
$this.parent().editor('updateLineNumbers', 0)
, 300)
# ##################### MAIN ##########################
$(".frame").frame('tabs').last().tab("content")
.append("<div id='sourceview'></div>")
$("#sourceview")
.css
position: 'absolute'
left: 1
right: 1
top: 1
bottom: 1
.editor()
.editor('theme', 'plugins/editor/themes/idlefingers.css')
.editor("highlight", "javascript")
.editor("lineNumbers", true)
return editor