1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
unless window.location.origin # Polyfill `location.origin` for IE < 11
window.location.origin = "#{window.location.protocol}//#{window.location.hostname}"
# Initialize Google Analytics
window.GA_TRACKING_ID = 'UA-106156830-1'
window.dataLayer ?= []
window.gtag = ->
window.dataLayer.push arguments
return
window.gtag 'js', new Date()
window.gtag 'config', window.GA_TRACKING_ID
# Initialize the CoffeeScript docs interactions
$(document).ready ->
CoffeeScript.patchStackTrace()
# Format dates for the user’s locale, e.g. 'December 24, 2009' or '24 décembre 2009'
$('time').each (index, el) ->
date = el.dateTime or $(el).text()
formattedDate = new Date(date).toLocaleDateString undefined, # undefined to use browser locale
year: 'numeric'
month: 'long'
day: 'numeric'
$(el).text formattedDate.toString()
# Mobile navigation
toggleSidebar = ->
$('.navbar-toggler, .sidebar').toggleClass 'show'
$('[data-toggle="offcanvas"]').click toggleSidebar
$('[data-action="sidebar-nav"]').click (event) ->
if $('.navbar-toggler').is(':visible')
event.preventDefault()
toggleSidebar()
setTimeout ->
window.location = event.target.href
, 260 # Wait for the sidebar to slide away before navigating
gtag 'event', 'sidebar_navigate',
event_category: 'navigation'
event_label: event.target.href.replace window.location.origin, ''
# Initialize Scrollspy for sidebar navigation; https://getbootstrap.com/docs/4.0/components/scrollspy/
# See also http://www.codingeverything.com/2014/02/BootstrapDocsSideBar.html and http://jsfiddle.net/KyleMit/v6zhz/
$('.main').scrollspy
target: '#contents'
offset: Math.round $('main').css('padding-top').replace('px', '')
initializeScrollspyFromHash = (hash) ->
$("#contents a.active[href!='#{hash}']").removeClass 'show'
$('.main').on 'activate.bs.scrollspy', (event, target) ->
# We only want one active link in the nav
$("#contents a.active[href!='#{target.relatedTarget}']").removeClass 'show'
$target = $("#contents a[href='#{target.relatedTarget}']")
return if $target.prop('href') is "#{window.location.origin}/#try"
# Update the browser address bar on scroll, without adding to the history; clicking the sidebar links will automatically add to the history
replaceState $target.prop('href')
# Track this as a new pageview; we only want '/#hash', not 'https://coffeescript.org/#hash'
gtag 'config', GA_TRACKING_ID,
page_path: $target.prop('href').replace window.location.origin, ''
# Initialize CodeMirror for code examples; https://codemirror.net/doc/manual.html
# Defer this until a code example is clicked or focused, to avoid unnecessary computation/slowness
textareas = []
editors = []
lastCompilationElapsedTime = 200
$('textarea').each (index) ->
textareas[index] = @
$(@).data 'index', index
initializeEditor = ($textarea) ->
index = $textarea.data 'index'
mode = if $textarea.hasClass('javascript-output') then 'javascript' else 'coffeescript'
editors[index] = editor = CodeMirror.fromTextArea $textarea[0],
mode: mode
theme: 'twilight'
indentUnit: 2
tabSize: 2
lineWrapping: on
lineNumbers: off
inputStyle: 'contenteditable'
readOnly: mode isnt 'coffeescript' # Can’t use 'nocursor' if we want the JavaScript to be copyable
viewportMargin: Infinity
# Whenever the user edits the CoffeeScript side of a code example, update the JavaScript output
# If the editor is Try CoffeeScript, also update the hash and save this code in localStorage
if mode is 'coffeescript'
pending = null
editor.on 'change', (instance, change) ->
clearTimeout pending
pending = setTimeout ->
lastCompilationStartTime = Date.now()
try
coffee = editor.getValue()
if index is 0 and $('#try').hasClass('show') # If this is the editor in Try CoffeeScript and it’s still visible
if $('#try').hasClass('show')
# Update the hash with the current code
link = "try:#{encodeURIComponent coffee}"
replaceState "#{window.location.href.split('#')[0]}##{link}"
# Save this to the user’s localStorage
try
if window.localStorage?
window.localStorage.setItem 'tryCoffeeScriptCode', coffee
catch exception
js = CoffeeScript.compile coffee, bare: yes, inlineMap: true
# Inline map is added to adjust stack trace line numbers but we strip it from the displayed JS for visual clarity.
output = js.replace /(\n\/\/# [^\n]*){2}$/, ""
lastCompilationElapsedTime = Math.max(200, Date.now() - lastCompilationStartTime)
catch exception
output = "#{exception}"
editors[index + 1].js = js
editors[index + 1].setValue output
gtag 'event', 'edit_code',
event_category: 'engagement'
event_label: $textarea.closest('[data-example]').data('example')
, lastCompilationElapsedTime
# Fix the code editors’ handling of tab-indented code
editor.addKeyMap
'Tab': (cm) ->
if cm.somethingSelected()
cm.indentSelection 'add'
else if /^\t/m.test cm.getValue()
# If any lines start with a tab, treat this as tab-indented code
cm.execCommand 'insertTab'
else
cm.execCommand 'insertSoftTab'
'Shift-Tab': (cm) ->
cm.indentSelection 'subtract'
'Enter': (cm) ->
cm.options.indentWithTabs = /^\t/m.test cm.getValue()
cm.execCommand 'newlineAndIndent'
$('.placeholder-code').one 'mouseover', (event) ->
$textarea = $(@).prev 'textarea'
$(@).remove()
initializeEditor $textarea
# Initialize the sibling column too
$siblingColumn = $ $textarea.parent().siblings()[0]
$siblingColumn.children('.placeholder-code').remove()
initializeEditor $ $siblingColumn.children('textarea')[0]
initializeTryEditors = ->
initializeEditor $ '#try-coffeescript-coffee'
initializeEditor $ '#try-coffeescript-js'
# Handle the code example buttons
$('[data-action="run-code-example"]').click ->
run = $(@).data 'run'
index = $("##{$(@).data('example')}-js").data 'index'
js = if editors[index]?
editors[index].js
else
$(textareas[index]).val()
js = "#{js}\nalert(#{unescape run});" unless run is yes
window.eval js
gtag 'event', 'run_code',
event_category: 'engagement'
event_label: $(@).closest('[data-example]').data('example')
# Try CoffeeScript
previousHash = null
toggleTry = (checkLocalStorage) ->
$('#try, #try-link').toggleClass 'show'
if $('#try').hasClass('show')
previousHash = window.location.hash if window.location.hash
initializeTryEditors() if $('#try .CodeMirror').length is 0
if checkLocalStorage and window.localStorage?
try
coffee = window.localStorage.getItem 'tryCoffeeScriptCode'
if coffee?
editors[0].setValue coffee
else
replaceState '#try'
catch exception
replaceState '#try'
else
replaceState '#try'
else
if previousHash then replaceState(previousHash) else clearHash()
closeTry = ->
$('#try, #try-link').removeClass 'show'
if previousHash then replaceState(previousHash) else clearHash()
$('[data-toggle="try"]').click (event) ->
event.preventDefault()
toggleTry yes
$('[data-close="try"]').click closeTry
$('[data-action="scroll-to-top"]').click (event) ->
return if $('#try').hasClass('show')
$('.main')[0].scrollTop = 0
setTimeout clearHash, 10
clearHash = ->
window.history.replaceState {}, document.title, window.location.pathname
replaceState = (newURL) ->
newURL = "#{window.location.pathname}#{newURL}" if newURL?.indexOf('#') is 0
window.history.replaceState {}, document.title, (newURL or '')
$(window).on 'hashchange', ->
# Get rid of dangling # in the address bar
clearHash() if window.location.hash is ''
# Configure the initial state
if window.location.hash?
if window.location.hash is '#try'
toggleTry yes
else if window.location.hash.indexOf('#try') is 0
initializeTryEditors() if $('#try .CodeMirror').length is 0
editors[0].setValue decodeURIComponent window.location.hash[5..]
toggleTry no
else if window.location.hash is ''
clearHash()
else
initializeScrollspyFromHash window.location.hash
if window.location.hash.length > 1
# Initializing the code editors might’ve thrown off our vertical scroll position
document.getElementById(window.location.hash.slice(1).replace(/try:.*/, '')).scrollIntoView()
|