mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
19231dbcad
* Bump version to 2.0.0; bump dependencies versions * Make v2 docs the primary docs; jettison the v1 docs’ source: whenever the v1 docs need to be rebuild in the future, that can be done on the `1` branch and copied over; simplify folder tree * Updated v1 docs that reflect that v2 is out and have updated paths to reflect that the v2 docs are now the primary docs, and the v1 docs only live under /v1/ * Add Google Analytics; track navigation, editing code and running code * 2.0.0 changelog * Fix link to root docs * No more @next; installing local copy should be --save-dev * Analytics on the browser-based tests page should prove fascinating . . . * Update annotated source * Add note to changelog clarifying scope
178 lines
7.2 KiB
CoffeeScript
178 lines
7.2 KiB
CoffeeScript
unless window.location.origin # Polyfill `location.origin` for IE < 11
|
||
window.location.origin = "#{window.location.protocol}//#{window.location.hostname}"
|
||
|
||
$(document).ready ->
|
||
# 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/
|
||
$('body').scrollspy
|
||
target: '#contents'
|
||
offset: Math.round $('main').css('padding-top').replace('px', '')
|
||
|
||
initializeScrollspyFromHash = (hash) ->
|
||
$("#contents a.active[href!='#{hash}']").removeClass 'show'
|
||
|
||
$(window).on 'activate.bs.scrollspy', (event, target) -> # Why `window`? https://github.com/twbs/bootstrap/issues/20086
|
||
# 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 or navigation
|
||
window.history.pushState {}, $target.text(), $target.prop('href')
|
||
# Track this as a new pageview; we only want '/#hash', not 'http://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
|
||
# Update the hash with the current code
|
||
link = "try:#{encodeURIComponent coffee}"
|
||
window.history.pushState {}, 'CoffeeScript', "#{location.href.split('#')[0]}##{link}"
|
||
# Save this to the user’s localStorage
|
||
try
|
||
if window.localStorage?
|
||
window.localStorage.setItem 'tryCoffeeScriptCode', coffee
|
||
catch exception
|
||
output = CoffeeScript.compile coffee, bare: yes
|
||
lastCompilationElapsedTime = Math.max(200, Date.now() - lastCompilationStartTime)
|
||
catch exception
|
||
output = "#{exception}"
|
||
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].getValue()
|
||
else
|
||
$(textareas[index]).val()
|
||
js = "#{js}\nalert(#{unescape run});" unless run is yes
|
||
eval js
|
||
gtag 'event', 'run_code',
|
||
event_category: 'engagement'
|
||
event_label: $(@).closest('[data-example]').data('example')
|
||
|
||
clearHash = ->
|
||
window.history.pushState '', document.title, window.location.pathname
|
||
|
||
$(window).on 'hashchange', ->
|
||
# Get rid of dangling # in the address bar
|
||
clearHash() if window.location.hash is ''
|
||
|
||
# Try CoffeeScript
|
||
toggleTry = (checkLocalStorage = no) ->
|
||
initializeTryEditors() if $('#try .CodeMirror').length is 0
|
||
if checkLocalStorage and window.localStorage?
|
||
try
|
||
coffee = window.localStorage.getItem 'tryCoffeeScriptCode'
|
||
if coffee?
|
||
editors[0].setValue coffee
|
||
catch exception
|
||
$('#try, #try-link').toggleClass 'show'
|
||
setTimeout clearHash, 200 unless $('#try').hasClass('show')
|
||
closeTry = ->
|
||
$('#try, #try-link').removeClass 'show'
|
||
window.history.pushState '', document.title, window.location.pathname
|
||
|
||
$('[data-toggle="try"]').click toggleTry
|
||
$('[data-close="try"]').click closeTry
|
||
|
||
|
||
# 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()
|
||
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()
|