chocolate
Version:
A full stack Node.js web framework built using Coffeescript
1,061 lines (954 loc) • 110 kB
text/coffeescript
# **Immediate** programing environment
Chocokup = require '../general/chocokup'
Doccolate = require '../general/doccolate'
exports.interface = (__) ->
exports.enter(__)
exports.enter = (__) ->
new Chocokup.App 'Chocolate Studio', with_coffee:yes, doccolate_style:Doccolate.options.default_style, snippets:__.config.get('snippets'), ->
style
type:"text/css"
media:"screen"
"""
.choco_title {
font-family: Times new roman;
font-size: 17px;
font-style: italic;
}
body {
font-family:Lucida Console,monospace;
font-size:9pt;
line-height: 12pt;
}
a.selected {
border-bottom: 1px double;
}
li.selected {
background-color:rgba(0,0,0,0.1);
}
.blurred {
-webkit-filter: blur(3px);
-moz-filter: blur(3px);
-o-filter: blur(3px);
-ms-filter: blur(3px);
filter: blur(3px);
}
.chocoblack code,
.chocomilk code {
font-size: 12px;
padding: 0 0.2em;
border: 1px solid #262836;
background: rgb(248, 248, 248);
display: inline-block;
-webkit-box-shadow: 0 0 4px rgb(92, 75, 68);
-moz-box-shadow: 0 0 4px rgb(92, 75, 68);
-o-box-shadow: 0 0 4px rgb(92, 75, 68);
box-shadow: 0 0 4px rgb(92, 75, 68);
padding: 2px 4px;
border-bottom-left-radius: 7px;
border-top-right-radius: 8px;
}
.panel.frame > .sizer {
outline: inherit;
}
.white {
background-color: rgba(255, 255, 255, 1);
color: rgba(0, 0, 0, 0.6);
}
.white .sizer {
outline: none;
}
.chocomilk {
background-color:rgb(245, 242, 232);
border: 2px solid rgba(255, 204, 0, 0.3);
color: rgb(92, 75, 68);
}
.chocomilk a, .chocomilk select {
color: rgb(92, 75, 68);
}
.white-background {
background-color: white;
}
.transparent-background {
background-color: transparent;
}
.round.frame > .sizer {
font-size: 9pt;
line-height: 12pt;
}
.padded {
padding: 8px;
}
.darkTheme .ace_editor.dimmed .ace_scroller {
background-color: dimgrey;
}
.lightTheme .ace_editor.dimmed .ace_scroller {
background-color: lightgrey;
}
.bite_style {
height: 7px;
width: 7px;
border-right: 1px solid white;
border-bottom: 1px solid white;
}
.ace_editor {
height: 100%;
}
#editor .ace_text-layer, #editor .ace_gutter {
font-size: 9pt;
}
#specolate-panel-editor .ace_text-layer, #specolate-panel-editor .ace_gutter {
font-size: 9pt;
}
#experiment-script-panel-editor .ace_text-layer, #experiment-markup-panel-editor .ace_text-layer,
#notes-panel .ace_text-layer {
font-size: 9pt;
line-height: 12pt;
font-weight: normal;
}
#help-panel .body {
padding: 12px;
}
#help-panel h1 {
font-size: 1.9em;
}
#help-panel h2 {
font-size: 1.1em;
}
#help-panel h3 {
font-size: 1.05em;
}
#notes-panel .panel .paper {
font-size: 11pt;
}
#source_select {
border: none;
vertical-align: middle;
}
#source_close, #source_exec {
border: 1px solid;
padding: 0px 3px;
cursor:pointer;
}
#toggle-login {
color: red;
}
#toggle-login.logged {
color: green;
}
#toggle-login.checking, #toggle-debug.checking {
color: yellow;
animation: blink-animation 1s steps(5, start) infinite;
-webkit-animation: blink-animation 1s steps(5, start) infinite;
}
@keyframes blink-animation {
to {
visibility: hidden;
}
}
@-webkit-keyframes blink-animation {
to {
visibility: hidden;
}
}
#toggle-debug {
color: green;
}
#toggle-debug.debugging {
color: red;
}
#input-login {
line-height: 2em;
}
/* darkTheme */
body.darkTheme {
background-color:#1a1c24;
color:#eaeaea;
}
.darkTheme #header > .panel {
border-bottom: 1px solid #171717;
}
.darkTheme .header, .darkTheme .footer {
background-color: #323244;
color: #eaeaea;
border-top: 1px solid #080808;
}
.darkTheme a, .darkTheme select {
color:#eaeaea;
font-weight: normal;
}
.darkTheme .sizer {
line-height: 2em;
border-left: 2px solid #262836;
margin: 1px;
outline: 1px solid #262836;
border-bottom-left-radius: 8px;
border-top-right-radius: 9px;
}
.darkTheme .chocoblack {
background-color: #1a1c24;
}
.darkTheme .round.frame {
padding: 6px 6px;
border-radius: 6px;
margin: 3px 3px;
}
.darkTheme .round.frame > .sizer {
width: 98%;
height: 98%;
top: 1%;
left: 1%;
border-style:none;
}
.darkTheme .frame.white.round, .darkTheme .frame.chocomilk.round {
-webkit-box-shadow: inset 0 0 20px #080706;
-moz-box-shadow: inset 0 0 20px #080706;
-o-box-shadow: inset 0 0 20px #080706;
box-shadow: inset 0 0 20px #080706;
}
.darkTheme .white {
border: 2px solid rgba(119, 110, 73, 0.3);
}
.darkTheme .grey {
background-color: #191919;
border: 2px solid #202020;
}
.darkTheme #source_select {
background-color: #4c433e;
color: #eaeaea;
}
.darkTheme #source_close, .darkTheme #source_exec {
border-color: #eaeaea;
color: #eaeaea;
}
/* lightTheme */
body.lightTheme {
background-color: #FBFBFB;
color: #0E0E0E;
}
.lightTheme .header, .lightTheme .footer {
background-color: #DAE1EC;
color: #46423D;
border-top: 1px solid;
}
.lightTheme a, .lightTheme select {
color: #312E29;
font-weight: normal;
}
.lightTheme .sizer {
border-right: 1px solid #C0C0C0;
}
.lightTheme .round.frame > .sizer > .panel {
padding: 4px;
}
.lightTheme .grey {
background-color: #F3F3F3;
}
.lightTheme #documentation-panel, .lightTheme #experiment-panel {
border-top: 1px solid #C0C0C0;
}
.lightTheme #source_select {
background-color: #FBFBFB;
color: #0E0E0E;
}
.lightTheme #source_close, .lightTheme #source_exec {
border-color: #424242;
color: #424242;
}
"""
style ->
text @params.doccolate_style
snippets = coffee : """
# Require Locco Interface
snippet locco_require_interface
\tInterface = require 'chocolate/general/locco/interface'\n
# Locco full Interface
snippet locco_interface_full
\tnew Interface${1:.Web.Html | .Web.App | .Web.Document | .Remote}
\t\tdefaults: -> ${2}
\t\tlocks: -> ${3}
\t\tcheck: (${4}) ->
\t\t\t${5:# body...}
\t\tsteps: (${6:$2}) ->
\t\t\t${7:# body...}
\t\trender: (${8:$2}) ->
\t\t\t${9:# body...}
# Locco full Interface.Web.Html
snippet locco_interface_html_full
\tnew Interface.Web.Html
\t\tdefaults: -> ${1}
\t\tlocks: -> ${2}
\t\tcheck: (${3}) ->
\t\t\t${4:# body...}
\t\tsteps: (${5}) ->
\t\t\t${6:# body...}
\t\trender: (${7}) ->
\t\t\t${8:# body...}
# Locco standard Interface.Web.Html
snippet locco_interface_html_standard
\tnew Interface.Web.Html (-> ${1}), ${2}->
\t\t${3:# body...}
# Locco minimal Interface.Web.Html
snippet locco_interface_html_minimal
\tnew Interface.Web.Html ->
\t\t${1:# body...}
# Chocodash require
snippet require_chocodash
\t_ = require 'chocolate/general/chocodash'\n
# Chocodash async
snippet chocodash_async_or_flow
\t_.flow (run) ->
\t\trun (end) ->
\t\t\t${1:end() | end.later}
"""
text "<script>_ = Chocodash; _ide = {}; _sofkey = #{if backdoor_key isnt '' then '"' + backdoor_key + '"' else 'null'};</script>\n"
text "<script>_ide.snippets = {studio:{applied:{}, modes:#{JSON.stringify(snippets)}}, user:{applied:{}, modes:#{if @params.snippets then JSON.stringify @params.snippets else '{}'}}}</script>"
script src:"/static/vendor/ace/ace.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/ext-searchbox.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/ext-language_tools.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/ext-whitespace.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/coffee.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/javascript.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/json.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/css.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/text.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/html.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/snippets/markdown.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-coffee.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-javascript.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-json.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-css.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-scss.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-text.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-html.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/mode-markdown.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/theme-coffee.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/ace/theme-coffee_white.js", type:"text/javascript", charset:"utf-8"
script src:"/static/lib/doccolate.js", type:"text/javascript", charset:"utf-8"
script src:"/static/lib/js2coffee.js", type:"text/javascript", charset:"utf-8"
script src:"/static/lib/htmlkup.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/datejs/date.js", type:"text/javascript", charset:"utf-8"
script src:"/static/vendor/mootools/mootools-core-uncompressed.js", type:"text/javascript", charset:"utf-8"
script src:"/static/lib/newnotes.js", type:"text/javascript", charset:"utf-8"
body '.lightTheme', ->
panel ->
header '#header', ->
panel proportion:'served', ->
panel ->
span '#.choco_title.float-margin-left', 'Chocolate.js'
panel ->
select '#source_select.hidden', onchange:'_ide.open_file()', ''
span '.float-right', ->
span '#source_exec.hidden', onclick:'_ide.exec_file()', '↗'
text ' '
span '#source_close.hidden', onclick:'_ide.close_file()', 'x'
a '#switch-invisible.float-margin-right', title:'Switch invisible caracters display', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchInvisible();", -> '...'
a '#switch-wrap.float-margin-right', title:'Switch wrap mode', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchWrap();", -> '↩'
a '#switch-unfold.float-margin-right', title:'Switch unfold', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchFoldAll(false);", -> '⤓'
a '#switch-foldall.float-margin-right', title:'Switch fold all', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchFoldAll(true);", -> '⤒'
a '#show-find.float-margin-right', title:'Show find dialog', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.showFindDialog();", -> '🔎'
panel ->
input '#input-login.float-margin-right.hidden', type:'password', onchange:'_ide.register_key()', ''
a '#toggle-login.float-margin-right', title:'Login/Logoff', style:'font-size: 15pt;text-decoration: none;', href:"#", onclick:"_ide.toggleLogin();", -> '•'
a '#toggle-debug.float-margin-right', title:'Debug/Run', style:'font-size: 13pt;text-decoration: none;', href:"#", onclick:"_ide.toggleDebug();", -> '▣'
a '#toggle-fullscreen.float-margin-right', title:'Switch fullscreen', style:'font-size: 15pt;text-decoration: none;', href:"#", onclick:"_ide.toggleFullscreen();", -> '«»'
a '#switch-panel.float-margin-right', title:'Switch side by side display', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchScreens();", -> '|||'
a '#switch-theme.float-margin-right', title:'Switch theme', style:'font-size: 9pt;text-decoration: none;', href:"#", onclick:"_ide.switchTheme();", -> '□'
body ->
panel '#main-panel', proportion:'served', ->
panel ->
footer ->
panel proportion:'third', ->
box -> a '#do-file-create', href:"#", onclick:"_ide.create_file();", -> 'Create'
box -> a '#do-git-commit', href:"#", onclick:"_ide.commit_to_git();", -> 'Commit'
box ->
a '#do-file-upload', href:"#", onclick:"_ide.upload_file('ask');", ->
text 'Upload'
form "#form-file-upload", action:"", method:"post", enctype:"multipart/form-data", target:"frame-file-upload", ->
input "#input-file-upload", name:"input-file-upload", type:'file', onchange:"_ide.upload_file('send');"
iframe "#frame-file-upload", name:"frame-file-upload", ->
body ->
panel proportion:'third', orientation:'vertical', ->
panel ->
header -> box 'Opened files'
body ->
box '#.chocoblack.round', -> body '#open_files_list', ''
panel ->
header ->
panel proportion:"half", orientation:"horizontal", ->
box -> a '#toggle-search', href:"#", onclick:"_ide.toggleNavigatePanel('search');", -> 'Search'
box -> a '#toggle-browse.selected', href:"#", onclick:"_ide.toggleNavigatePanel('browse');", -> 'Browse'
body ->
panel '#studio-search-panel.hidden', ->
panel ->
header -> input "#search_in_file_input", size:"70%", onchange:"_ide.search_in_files(this.value);", ->
body ->
box '#.chocoblack.round', -> body '#studio-search', ->
panel '#studio-browse-panel', ->
box '#.chocoblack.round', -> body ->
div ->
text '/'
span '#current_dir', ->
div '#dir_content', style:'margin-left:4px;', ->
panel ->
header -> box 'Log'
footer ->
panel proportion:'third', ->
box -> a '#do-file-rename', href:"#", onclick:"_ide.rename_file();", -> 'Rename'
box -> a '#do-file-move', href:"#", onclick:"_ide.move_file();", -> 'Move'
box -> a '#do-file-delete', href:"#", onclick:"_ide.delete_file();", -> 'Delete'
body ->
panel '#studio-messages-panel', ->
box '#.chocoblack.round', -> body '#studio-messages', ->
panel ->
footer ->
panel proportion:'third', ->
box -> a '#toggle-source.selected', href:"#", onclick:"_ide.toggleMainPanel('source');", -> 'Code'
panel proportion:'third', ->
box -> a '#toggle-shared', href:"#", onclick:"_ide.toggleMainPanel('shared');", -> 'Code & Lab'
box -> a '#toggle-specolate', href:"#", onclick:"_ide.toggleMainPanel('specolate');", -> 'Spec'
box -> a '#toggle-doccolate', href:"#", onclick:"_ide.toggleMainPanel('doccolate');", -> 'Doc'
box -> a '#toggle-experiment', href:"#", onclick:"_ide.toggleMainPanel('experiment');", -> 'Lab'
body ->
panel '#main-display', proportion:'half', orientation:'vertical', ->
panel '#main-editor.expand', ->
panel '#editor', ''
panel '#main-tabs.shrink', ->
panel '#experiment-panel', proportion:'half-served', orientation:'vertical', ->
panel proportion:'half', ->
panel ->
footer ->
panel proportion:'half', ->
box ->
a '#toggle-coffeescript.selected', href:"#", onclick:"_ide.toggleExperimentPanel('coffeescript');", -> 'Coffeescript'
text ' / '
a '#toggle-javascript', href:"#", onclick:"_ide.toggleExperimentPanel('javascript');", -> 'Javascript'
box ->
a '#toggle-chocodown', href:"#", onclick:"_ide.toggleExperimentPanel('chocodown');", -> 'Chocodown'
text ' / '
a '#toggle-html', href:"#", onclick:"_ide.toggleExperimentPanel('html');", -> 'Html'
body ->
box '#experiment-script-panel-main.chocoblack.round', -> panel '#experiment-script-panel-editor', ''
box '#experiment-markup-panel-main.chocoblack.round.hidden', -> panel '#experiment-markup-panel-editor', ''
panel ->
panel '#experiment-script-transpiled', ->
footer ->
panel proportion:'half', ->
box -> a '#toggle-script-output.selected', href:"#", onclick:"_ide.toggleExperimentPanel('script-output');", ->
span '#label-javascript-output', 'Javascript'
span '#label-coffeescript-output.hidden', 'Coffeescript'
box ->
panel "#toggle-debug-panel", proportion:'half-served', ->
panel ->
a '#toggle-debug', href:"#", onclick:"_ide.toggleExperimentPanel('debug');", -> 'Debug'
panel proportion:'half', ->
panel ->
a href:"#", title:"Reduce column width", onclick:"_ide.changeDebugColWidth(-1);", -> '-'
panel ->
a href:"#", title:"Increase column width", onclick:"_ide.changeDebugColWidth(1);", -> '+'
body ->
panel '#experiment-script-output-panel-main', ->
box '#.white.round', -> body '#experiment-script-output-panel.source-code.dl-s-default', ->
panel '#experiment-debug-panel-main.hidden', ->
box '#.chocoblack.round', -> panel '#experiment-debug-panel.source-code', ''
panel '#experiment-markup-transpiled.hidden', ->
footer ->
panel proportion:'half', ->
box ->
panel proportion:'half-served', ->
panel ->
a '#toggle-markup-output.selected', href:"#", onclick:"_ide.toggleExperimentPanel('markup-output');", ->
span '#label-chocodown-output', 'Html'
span '#label-html-output.hidden', 'Chocokup'
panel '#experiment-markup-options', proportion:'half', ->
panel ->
a href:"#", title:"Indented Chocokup", onclick:"_ide.toggleFormatChocokup(true);", -> '↘'
panel ->
a href:"#", title:"Raw Chocokup", onclick:"_ide.toggleFormatChocokup(false);", -> '→'
box -> a '#toggle-dom', href:"#", onclick:"_ide.toggleExperimentPanel('dom');", -> 'Dom'
body ->
panel '#experiment-markup-output-panel-main', ->
box '#.white.round', -> body '#experiment-markup-output-panel.source-code', ->
panel '#experiment-dom-panel-main.hidden', ->
box '#.white.round', -> panel '#.padded', ->
iframe '#experiment-dom-panel.expand.fullscreen.white-background', frameborder:'0', ->
panel -> box '#.grey.round', -> body '#experiment-run-panel.source-code', ''
panel '#documentation-panel.hidden', ->
box '#.white.round', ->
iframe '#documentation-doccolate-panel.expand.fullscreen.transparent-background', frameborder:'0', ->
panel '#specolate-panel.hidden', proportion:'half-served', orientation:'vertical', ->
panel ->
header ->
panel 'Spec'
box -> a '#run-specolate.float-margin-right', href:"#", onclick:"_ide.run_specolate();", -> 'Run'
body ->
box '#specolate-panel-main.chocoblack.round', -> panel '#specolate-panel-editor', ''
panel -> box '#.grey.round', -> body '#specolate-result-panel.source-code', ''
iframe '#specolate-run-panel.hidden', src:'/-/server/studio?iframe_body', ->
panel '#help-display.hidden', proportion:'full', ->
header ->
panel '#help-title', -> ''
panel '#doclosehelpdisplay', -> a '#close-help-display.float-margin-right', style:'text-decoration: none;', href:"#", onclick:"_ide.close_help_panel();", -> 'x'
body ->
panel '#help-display-body', ->
panel ->
footer ->
panel proportion:'third', ->
box -> a '#toggle-git.selected', href:"#", onclick:"_ide.toggleServicesPanel('git');", -> 'Git'
box -> a '#toggle-notes', href:"#", onclick:"_ide.toggleServicesPanel('notes');", -> 'Notes'
box -> a '#toggle-help', href:"#", onclick:"_ide.toggleServicesPanel('help');", -> 'Help'
body ->
panel '#git-panel', ->
body ->
panel '#git-panel-history', ->
panel proportion:'half', orientation:'vertical', ->
panel '#git-code.expand', ->
box '#.chocoblack.round', -> body '#code-git-history', ->
panel '#git-spec.shrink', ->
header -> box -> 'Spec'
body ->
box '#.chocoblack.round', -> body '#spec-git-history', ->
panel '#git-panel-diff.hidden', ->
panel proportion:'half', orientation:'vertical', ->
panel '#git-diff-code.overflow.expand', ->
box '#.chocoblack.round', -> body '#code-git-diff', ->
panel '#git-diff-spec.overflow.shrink', ->
header -> box -> 'Spec'
body ->
box '#.chocoblack.round', -> body '#spec-git-diff', ->
panel '#git-panel-status.hidden.overflow', ->
footer ->
panel proportion:'third', ->
box -> a '#toggle-git-history.selected', href:"#", onclick:"_ide.toggleServicesPanel('git', 'history');", -> 'History'
box -> a '#toggle-git-diff', href:"#", onclick:"_ide.toggleServicesPanel('git', 'diff');", -> 'Diff'
box -> a '#toggle-git-status', href:"#", onclick:"_ide.toggleServicesPanel('git', 'status');", -> 'Status'
panel '#notes-panel.hidden', ''
panel '#help-panel.hidden', ->
panel ->
header '#.inline', ->
panel proportion:'third', ->
box -> a '#toggle-help-chocolate.selected', href:"#", onclick:"_ide.toggleHelpPanel('chocolate');", -> 'Chocolate'
box -> a '#toggle-help-coffeescript', href:"#", onclick:"_ide.toggleHelpPanel('coffeescript');", -> 'Coffeescript'
box -> a '#toggle-help-chocokup', href:"#", onclick:"_ide.toggleHelpPanel('chocokup');", -> 'Chocokup'
header '#.inline', ->
panel proportion:'third', ->
box -> a '#toggle-help-specolate', href:"#", onclick:"_ide.toggleHelpPanel('specolate');", -> 'Specolate'
box -> a '#toggle-help-doccolate', href:"#", onclick:"_ide.toggleHelpPanel('doccolate');", -> 'Doccolate'
box -> a '#toggle-help-newnotes', href:"#", onclick:"_ide.toggleHelpPanel('newnotes');", -> 'Newnotes'
header '#.inline', ->
panel proportion:'third', ->
box -> a '#toggle-help-chocodown', href:"#", onclick:"_ide.toggleHelpPanel('chocodown');", -> 'Chocodown'
box -> a '#toggle-help-litejq', href:"#", onclick:"_ide.toggleHelpPanel('litejq');", -> 'litejQ'
box -> a '#toggle-help-node', href:"#", onclick:"_ide.toggleHelpPanel('node');", -> 'Node'
body '#.with-3-headers', ->
footer -> panel '#help-selector-panel.hidden', ->
select '#help-selector', onchange:"_ide.select_help_panel(true);", ->
body ->
box '#.chocomilk.round', -> panel ->
iframe '#help-frame-panel.expand fullscreen', frameborder: '0', ->
coffeescript ->
sofkey = _sofkey
editor = lab_markup_editor = debug_editor = lab_script_editor = specolate_editor = null
ace_theme = if $(document.body).hasClass('lightTheme') then 'ace/theme/coffee_white' else 'ace/theme/coffee'
debug_experiment_sync = null
sources =
opened : []
# codes : { path, doc, from_history , modified, modifiedDate }
codes : {}
specs : {}
current : ''
available : {}
searched: {}
isOpening : false
frames =
help : {}
codeMode = 'opened'
debugColumnWidth = 7
formatChocokup = off
console_log = console.log
console.log = (text) ->
_ide.display_message text
console_log.apply console, arguments
translate = (text) -> text
# Display opened source files list
_ide.get_extension = (path) ->
if (path = path.substr(1 + path.indexOf '/')).indexOf('.') is -1 then '' else '.' + path.split('.')[-1..][0]
_ide.get_basename = (path) ->
path.split('/')[-1..][0]
_ide.is_spec_file = (path) ->
suffix = '.spec'
index = path.lastIndexOf '.'
index = path.length if index < 0
result = path.substr(index - suffix.length, suffix.length) is '.spec'
result = path.substr(index) is '.spec' unless result
result
_ide.get_spec_filename = (path) ->
return '' if path is ''
return path.replace ext, '.spec' + ext if (ext = _ide.get_extension path) isnt ''
return path + '.spec'
_ide.has_spec_file = (path) ->
item = sources.codes[path]
return item.has_spec_file if item?
false
_ide.get_current_dir = ->
if (dir = document.id('current_dir').get 'text') is '' then '.' else dir
_ide.iframe_infos = (iframe) ->
doc = (iframe.contentDocument || iframe.contentWindow.document)
doc_element = doc.documentElement || doc.body.parentNode || doc.body
win = iframe.contentWindow
scroll =
if win.pageXOffset isnt undefined
doc:win, attr: x:'pageXOffset', y:'pageYOffset'
else
doc:doc_element, attr: x:'scrollLeft', y:'scrollTop'
scrollX = scroll.doc[scroll.attr.x]
scrollY = scroll.doc[scroll.attr.y]
{win, doc, doc_element, scrollX, scrollY}
_ide.iframe_write = (iframe, text, scroll) ->
{doc, win, scrollX, scrollY} = _ide.iframe_infos iframe
iframeDoc = doc
iframeDoc.open()
iframeDoc.write text
iframeDoc.close()
unless scroll?
win.scrollTo scrollX, scrollY
else
_ide.iframe_scrollTo iframe, scroll.left , scroll.top, scroll.elemW, scroll.elemH
_ide.iframe_scrollTo = (iframe, x, y, elemW, elemH) ->
{doc, doc_element, scrollX, scrollY} = _ide.iframe_infos iframe
container = doc.getElementById('docco_container') ? doc_element
ratioX = (container.clientWidth - doc.body.clientWidth) / elemW
ratioY = (container.clientHeight - doc.body.clientHeight) / elemH
new_scrollX = if x < 0 or elemW < 0 then scrollX else x * ratioX
new_scrollY = if y < 0 or elemH < 0 then scrollY else y * ratioY
iframe.contentWindow.scrollTo new_scrollX, new_scrollY
_ide.display_message = (message) ->
new Element('div').set('html', ('<p>' + new Date().toString translate 'dd/MM/yyyy HH:mm:ss') + '<br/> ' + message + '</p>').inject document.id('studio-messages'), 'top'
_ide.display_help_panel = (name, path) ->
path = '' if path is '-'
_ide.toggleMainDisplay 'help' if path isnt ''
selected_frame = frames.help[path]?.frame
for own help_path, help of frames.help
if help.frame isnt selected_frame then help.frame.addClass 'hidden' else help.frame.removeClass 'hidden'
document.id('help-title').set 'text', path
document.id('help-display-body').adopt (frames.help[path] = name: name, frame: new Element('iframe', src:path, frameborder:0, class:'expand fullscreen white-background')).frame unless selected_frame or path is ''
help_selector = document.id('help-selector')
help_selector.empty()
(help_selector.adopt new Element 'option', selected:(if path is help_path then on else off), value: help_path, text: help.name) for own help_path, help of frames.help
document.id('help-selector-panel')[(if help_selector.length <= 1 then 'add' else 'remove') + 'Class'] 'hidden'
_ide.select_help_panel = (is_on_click) ->
help_selector = document.id('help-selector')
_ide.display_help_panel help_selector.getSelected().get('text')[0], help_selector.getSelected().get('value')[0]
_ide.close_help_panel = ->
path = document.id('help-title').get 'text'
frames.help[path].frame.dispose()
delete frames.help[path]
new_help = {name: '', path: ''}
for own path, help of frames.help then new_help = name: help.name, path: path
_ide.display_help_panel new_help.name, new_help.path
_ide.toggleMainDisplay 'main' if document.id('help-selector').length is 0
_ide.display_opened_files_list = ->
codes = []
codes.push item for own item of sources.codes
codes.sort()
content = []
current_steps = []
for item in codes
steps = item.split '/'
for step, i in steps when i < steps.length-1
if step isnt current_steps[i]
current_steps = current_steps[0...i]
for j in [i...steps.length-1]
current_steps[j] = steps[j]
content.push "<div style='margin-top:4px;margin-left:#{j*8}px;'><a href='#' onclick=\"javascript:_ide.goto_dir('#{current_steps.join('/')}');\">#{steps[j]}</a></div>"
line = """<div style='margin-left:#{(steps.length-1)*8}px;'>"""
line += """<a href="#" onclick="javascript:_ide.close_file('#{item}');">x</a> """
line += """<a href="#" onclick="javascript:_ide.save_file('#{item}');">*</a> """ if sources.codes[item].modified
line += """<a href="#" onclick="javascript:_ide.display_code_file('#{item}');">#{steps[steps.length-1]}</a> """
line += """<a href="#" onclick="javascript:_ide.display_synchro_conflict_message('#{item}');">!</a> """ if sources.codes[item].has_synchro_conflict
if _ide.has_spec_file item
spec_item = _ide.get_spec_filename item
line += '['
line += """<a href="#" onclick="javascript:_ide.save_file('#{spec_item}');">*</a> """ if sources.specs[spec_item].modified
line += """<a href="#" onclick="javascript:_ide.display_code_file('#{item}'); _ide.toggleMainPanel('specolate')">spec</a>"""
line += '] '
line += "</div>"
content.push line
document.id('open_files_list').set 'html', content
_ide.display_opened_files_select = ->
codes = []
codes.push item for own item of sources.codes
codes.sort()
content = []
for item in codes
if_selected = if sources.current is item then ' selected="selected"' else ''
content.push "<option value='#{item}'#{if_selected}>/#{item + if sources.codes[item].modified then '*' else ''}</option>"
selector = document.id('source_select').set 'html', content
selector[(if content.length > 0 then 'remove' else 'add') + 'Class'] 'hidden'
$$("#source_select > option[value='#{sources.current}']").setProperty 'selected', 'selected'
_ide.has_modified_file = ->
for path in [sources.codes, sources.specs]
for own k,v of path then if v.modified then return yes
no
_ide.switch_login = (switched) ->
if not switched?
document.id("toggle-login").removeClass('logged').addClass 'checking'
document.id("toggle-debug").addClass 'checking'
else
document.id("toggle-login").removeClass 'checking'
document.id("toggle-debug").removeClass 'checking'
document.id("toggle-login")["#{if switched is on then 'add' else 'remove'}Class"] 'logged'
document.id("main-panel")["#{if switched is off then 'add' else 'remove'}Class"] 'blurred'
_ide.sync_exec_windows = (count) ->
for path, window_ of _ide.exec_file.paths when window_?
if count > 0
window_.document.body.innerHTML = """
<table style="font-size:120pt; width:100%; height:100%; text-align:center; vertical-align:middle">
<tr>
<td>#{count}</td>
</tr>
</table>
"""
else
if window_.closed then delete _ide.exec_file.paths[path]
else _ide.exec_file path
_ide.check_connected = (timeout = 0) ->
try_reconnect = not _ide.check_online.connected
if timeout > 0 then _ide.switch_login()
start = Date.now()
new Request
url: (if sofkey? then '/!/' + sofkey else '') + '/-/server/studio?connected&how=raw'
noCache: yes
timeout: timeout
onSuccess: (data) ->
_ide.switch_login (_ide.check_online.connected = if data is "connected" then on else off)
_ide.sync_exec_windows() if try_reconnect and _ide.check_online.connected
onFailure: (xhr) ->
unless timeout > 0
_ide.switch_login (_ide.check_online.connected = off)
onTimeout: () ->
unless timeout > 0
_ide.switch_login (_ide.check_online.connected = off)
.get()
_ide.check_online = (timeout = 30000, delay = 1500) ->
count = 0
index = 0
_ide.check_online.connected = off
timer = setInterval ( ->
index++
count += delay
if count < timeout and (index <= 1 or _ide.check_online.connected isnt yes)
_ide.sync_exec_windows(index) ; _ide.check_connected delay
else
clearInterval timer
), delay
_ide.register_key = ->
new Request
data: key:document.id("input-login").value
noCache: yes
url: (if sofkey? then '/!/' + sofkey else '') + '/-/server/interface?register_key&how=raw'
onSuccess: (data) =>
_ide.check_connected()
document.id("input-login").addClass('hidden').set 'value', ''
onFailure: (xhr) ->
.post()
_ide.logoff = ->
new Request
noCache: yes
url: (if sofkey? then '/!/' + sofkey else '') + '/-/server/interface?forget_keys&how=raw'
onSuccess: (data) =>
_ide.check_connected()
onFailure: (xhr) ->
.post()
_ide.debug = (onoff) ->
new Request.JSON
noCache: yes
url: (if sofkey? then '/!/' + sofkey else '') + '/-/server/config?debug&' + onoff
onSuccess: ({protocol, port}) ->
if onoff
document.id("toggle-debug").addClass 'debugging'
else
document.id("toggle-debug").removeClass 'debugging'
_ide.check_online()
if onoff
_ide.debug.window = window.open()
_ide.debug.window.document.body.innerHTML = """
<div>establish ssh connection: ssh -L 9229:localhost:9229 user@remote.example.com</div>
<div>then open chrome://inspect#devices</div>
"""
else
_ide.debug.window.close()
onFailure: (xhr) ->
.get()
_ide.goto_dir = (new_dir, callback) ->
parent_dir = if (tmp_ = new_dir.split('/')[0...-1].join('/')) is '' then '.' else tmp_
new Request.JSON
url: (if sofkey? then '/!/' + sofkey else '') + '/-/server/file?getDirContent&' + new_dir + '&how=raw'
onSuccess: (directory) ->
return if directory.error?
rel_new_dir = if new_dir is '.' then '' else new_dir + '/'
sources.available = {}
content = ["""<div><a href="#" onclick="javascript:_ide.goto_dir('#{parent_dir}');">..</a></div>""" if new_dir isnt '.']
for item in directory when item.name[0] isnt '.' # and (item.isDir or item.extension in ['.coffee', '.litcoffee', '.css', '.js', '.json', '.html', '.txt', '.markdown', '.md'])
unless _ide.is_spec_file item.name
content.push ('<div>' + """<a href="#" onclick="javascript:#{if item.isDir then '_ide.goto_dir' else '_ide.open_file'}('#{(if new_dir isnt '.' then (new_dir + '/') else '') + item.name}');">#{item.name}</a>""" + '</div>')
else sources.available[rel_new_dir + item.name.replace '.spec', '']?.has_spec_file = true
sources.available[rel_new_dir + item.name] = { name:item.name, extension:item.extension, modifiedDate:item.modifiedDate, has_spec_file:false } if item.isFile
document.id('dir_content').set 'html', content
document.id('current_dir').set 'text', if new_dir isnt '.' then new_dir else ''
_ide.get_git_status()
callback?()
onFailure: (xhr) ->
_ide.display_message "Error with _ide.goto_dir(#{new_dir}) : #{xhr.status}"
.get()
_ide.load_file = (path, file, from_history) ->
is_spec = _ide.is_spec_file path
if not is_spec and not sources.codes[path]?
# Create or recycle an editor to display source file
if sources.opened.length >= 10
delete sources.codes[sources.opened[0]]
delete sources.opened[0]
sources.opened = sources.opened[1..]
sources.opened.push path
doc = _ide.create_session file, path
item = sources.available[path] ? name:_ide.get_basename(path), extension:_ide.get_extension(path), modifiedDate:sources.searched[path]?.modifiedDate ? 0, has_spec_file:false
sources[if is_spec then 'specs' else 'codes'][path] = { path, doc, from_history:from_history ? false, modified:from_history ? false, modifiedDate:item.modifiedDate, has_spec_file:item.has_spec_file }
_ide.save_sources_opened()
doc
_ide.display_code_file = (path, overwrite) ->
_ide.toggleMainDisplay 'main'
editor.setSession if path is '' then _ide.create_session '' else sources.codes[path].doc
document.id('source_exec')[(if path is '' then 'add' else 'remove') + 'Class'] 'hidden'
document.id('source_close')[(if path is '' then 'add' else 'remove') + 'Class'] 'hidden'
sources.current = path
# Switch to Source display if current display is Experiment
_ide.toggleMainPanel 'source' if document.id('toggle-experiment').hasClass 'selected'
editor.focus()
# Refresh file History panel if display file is not from History
_ide.get_file_git_history path unless overwrite
_ide.get_file_diff path
_ide.on_file_status_changed()
_ide.on_content_changed init:yes
_ide.display_spec_file _ide.get_spec_filename path
if path != '' then $$("#source_select > option[value='#{path}']").setProperty 'selected', 'selected'
editor.getSession().on 'changeScrollTop', (scroll) ->
unless document.id('documentation-panel').hasClass 'hidden'
iframe = document.id('documentation-doccolate-panel')
_ide.iframe_scrollTo iframe, -1, scroll, -1, editor.getSession().getScreenLength() * editor.renderer.lineHeight - editor.renderer.scroller.clientHeight
_ide.display_spec_file = (path, overwrite) ->
# Load spec file in editor if present
item = sources.specs[path]
unless item? then path = ''
specolate_editor.setSession if path is '' then _ide.create_session '' else item.doc
document.id('specolate-result-panel').set 'text', if path is '' or item.spec_run_result is undefined then '' else item.spec_run_result.join '\n'
_ide.on_file_status_changed yes
_ide.on_content_changed is_spec:yes, init:yes
_ide.create_session = (source, path) ->
EditSession = require("ace/edit_session").EditSession
UndoManager = require("ace/undomanager").UndoManager
mode = switch _ide.get_extension path ? ''
when '.coffee', '.chocokup', '.ck' then 'coffee'
when '.js' then 'javascript'
when '.json' then 'json'
when '.css' then 'css'
when '.scss' then 'scss'
when '.html' then 'html'
when '.txt' then 'text'
when '.markdown', '.md', '.chocodown', '.cd', '.litcoffee' then 'markdown'
else 'text'
Mode = require("ace/mode/#{mode}").Mode
doc = new EditSession source
doc.setUndoManager new UndoManager()
doc.setMode new Mode()
snippetManager = require("ace/snippets").snippetManager
snippetMode = require("ace/snippets/#{mode}")
for type in ['studio', 'user']
if _ide.snippets[type].modes[mode]? and _ide.snippets[type].applied[mode] isnt on
snippetMode.snippetText ?= ""
snippetMode.snippetText += "\n#{_ide.snippets[type].modes[mode]}"
snippetManager.unregister _ide.current_snippet
_ide.current_snippet = snippetManager.parseSnippetFile(snippetMode.snippetText ? "")
snippetManager.register _ide.current_snippet
doc.setUseSoftTabs true
if path? and path isnt ''
unless _ide.is_spec_file path
doc.on 'change', ->
source = sources.codes[sources.current]
if source?
if not source.modified
source.modified = true
sources.opened = (item for item in sources.opened when item isnt sources.current)
_ide.on_file_status_changed()
_ide.on_content_changed init:yes
true
else
doc.on 'change', ->
sources.codes[sources.current].has_spec_file = yes
source = sources.specs[_ide.get_spec_filename sources.current]
if source?
if not source.modified
source.modified = true
_ide.on_file_status_changed yes
_ide.on_content_changed is_spec:yes
true
doc
_ide.create_file = ->
cur_dir = _ide.get_current_dir()
if filename = prompt translate("Current directory is /#{cur_dir}") + '\n\n' + translate "Enter a filename"
if _ide.get_extension(filename) is '' then filename += '.coffee'
new Request
url: '/' + (if sofkey? then '!/' + sofkey else '') + "#{cur_dir}/#{filename}?so=move&how=raw"
onSuccess: (responseText) ->
_ide.goto_dir cur_dir, ->
_ide.open_file "#{cur_dir}/#{filename}"
_ide.display_message translate "File #{cur_dir}/#{filename} was created"
onFailure: (xhr) ->
_ide.display_message "Error with _ide.create_file() : #{xhr.status}"
.get()
_ide.check_online()
return
_ide.upload_file = (step) ->
cur_dir = _ide.get_current_dir()
form = document.getElementById('form-file-upload')
input = document.getElementById('input-file-upload')
iframe = document.getElementById('frame-file-upload')
on_iframe_load = -> _ide.upload_file 'done'
filename = _ide.get_basename input.value.replace /\\/g, '/'
switch step
when 'ask'
input.click()
when 'send'
if input.value isnt ''
iframe.addEvent 'load', on_iframe_load
form.action = '/' + (if sofkey? then '!/' + sofkey else '') + "#{cur_dir}/#{filename}?so=move&how=raw"
form.submit()
when 'done'
iframe.removeEvents 'load'
form.action = ''
input.value = ''
_ide.goto_dir cur_dir, ->
_ide.open_file "#{cur_dir}/#{filename}"
_ide.display_message translate "File /#{cur_dir}/#{filename} was uploaded"
_ide.move_file = ->
cur_dir = _ide.get_current_dir()
filename = _ide.get_basename sources.current
if sources.current is "#{cur_dir}/#{filename}"
alert translate "This file is already in /#{cur_dir} directory"
return
if filename is '' or not _ide.will_close_file sources.current then return
move_one = (source, dest, callback) ->
new Request
url: '/' + (if sofkey? then '!/' + sofkey else '') + "#{dest}?so=move&what=#{source}&how=raw"
onSuccess: (responseText) -> callback?()
onFailure: (xhr) -> _ide.display_message "Error with _ide.move_file.move_one() : #{xhr.status}"
.get()
_ide.check_online()
return
if confirm translate("Current file is /#{sources.current}") + '\n\n' + translate "Confirm that you want to move this file to /#{cur_dir}"
source = sources.current
dest = cur_dir + '/' + filename
if _ide.has_spec_file source then move_one _ide.get_spec_filename(source), _ide.get_spec_filename(dest)
move_one source, dest, ->
_ide.close_file sources.current, yes
_ide.goto_dir cur_dir, ->
_ide.open_file "#{cur_dir}/#{filename}"
_ide.dis