reload-0.0.0.1: web/src/file-editor.html
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/juicy-ace-editor/juicy-ace-editor.html">
<link rel="import" href="../bower_components/paper-card/paper-card.html">
<link rel="import" href="../bower_components/iron-ajax/iron-ajax.html">
<dom-module id="file-editor">
<script src="../bower_components/ace-builds/src-min-noconflict/ext-language_tools.js" type="text/javascript" charset="utf-8"></script>
<style>
:host {
display: block;
padding: 10px;
}
.card {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
padding: 0;
margin: 0;
border-radius: 5px;
background-color: #fff;
color: #757575;
position:absolute;
bottom: 0px;
top: 60px;
right: 0px;
left: 0px;
}
juicy-ace-editor {
position:absolute;
bottom: 0px;
top: 4px;
right: 0px;
left: 0px;
visibility: hidden;
}
</style>
<template>
<iron-ajax id="ajax" url="/file/{{path}}" handle-as="text" on-response="handleResponse"></iron-ajax>
<iron-ajax id="ajaxInfo" url="/info/{{path}}" handle-as="json" on-response="handleInfo"></iron-ajax>
<iron-ajax id="ajaxComplete" url="/complete/{{path}}" handle-as="json" on-response="handleComplete"></iron-ajax>
<iron-ajax id="ajaxFormat" url="/format/{{path}}" handle-as="json" method="POST"></iron-ajax>
<iron-ajax id="ajaxPut" url="/file/{{path}}" handle-as="text" method="PUT"></iron-ajax>
<div class="card" on-tap="handleTap">
<juicy-ace-editor id="editor" mode$="{{mode}}" softtabs="true" tabsize="2" on-change="textChange">
</juicy-ace-editor>
</div>
</template>
<script>
Polymer({
is: 'file-editor',
mode: "",
properties: {
'path': {
type: String,
observer: "pathChanged"
},
'mime': {
type: String,
observer: "mimeChanged"
} ,
'type': {
type: String
}
},
pathChanged: function(){
this.unlisten(this.$.editor, 'change', 'textChange');
this.editing=false;
this.$.editor.onChange=function(){};
this.$.editor.value="";
if (this.path){
this.$.editor.editor.setReadOnly("process"===this.type);
if ("process"!=this.type){
this.$.ajax.generateRequest();
} else {
this.editing=true;
}
this.$.editor.style.visibility='visible';
} else {
this.$.editor.style.visibility='hidden';
}
},
mimeChanged: function(){
this.mode="ace/mode/text";
var mode=this.mime;
if (mode.indexOf("haskell")>-1){
mode="ace/mode/haskell";
} else if (mode.indexOf("cabal")>-1){
mode="ace/mode/haskell_cabal";
} else if (mode.indexOf("yaml")>-1){
mode="ace/mode/yaml";
} else if (mode.indexOf("json")>-1){
mode="ace/mode/json";
} else if (this.path && this.path.endsWith(".md")>-1){
mode="ace/mode/markdown";
}
this.mode=mode;
},
statusChanged: function(e){
this.status=e.detail;
this.updateStatus();
},
handleResponse: function(e){
var ed=this.$.editor;
var s=ed.editor.getSession();
s.setValue(e.detail.response);
this.resetEditor();
this.setDetails();
this.listen(this.$.editor, 'change', 'textChange');
this.editing=true;
this.updateStatus();
},
handleInfo: function(e){
var r=e.detail.response;
var editor=this.$.editor.editor;
if (r && r.length>0){
var s=r.join("\n");
if (s){
var Tooltip = ace.require("ace/tooltip").Tooltip;
this.tooltip=new Tooltip(editor.container);
var c=editor.getCursorPosition();
var sc=editor.renderer.textToScreenCoordinates(c.row,c.column);
this.tooltip.show(s,sc.pageX,sc.pageY);
}
}
},
handleComplete: function(e){
var r=e.detail.response;
if (r && this.completeCallback){
this.completeCallback(null, r.map(function(w) {
return {name: w, value: w, score: Number.MAX_VALUE, meta: "ghci"}
}));
this.completeCallback=null;
}
},
handleTap: function(e){
if (this.tooltip){
this.tooltip.hide();
this.tooltip=null;
}
},
textChange: function(e){
//console.log(e.detail);
var ed=this.$.editor;
this.$.ajaxPut.body=ed.value;
this.$.ajaxPut.generateRequest();
if (this.path==="reload.json"){
try {
var c=JSON.parse(ed.value);
this.fire("config-changed",c);
this.setConfig(c);
} catch (e){
// not valid JSON
}
}
},
fileOpened: function(e){
if (e && e.detail){
this.details=e.detail.details;
if (e.detail.path==this.path){
this.setDetails();
}
this.type=e.detail.type;
this.path=e.detail.path;
this.mime=e.detail.mime;
} else {
this.type=null;
this.details=null;
this.path=null;
this.mime="text/plain";
}
},
setDetails(){
if (this.details){
if (this.details.line){
var ed=this.$.editor;
ed.editor.clearSelection( );
ed.editor.scrollToLine(this.details.line-1,true,true);
ed.editor.moveCursorTo(this.details.line-1,this.details.column-1);
}
}
},
ready: function(){
this.editing=false;
this.status={};
this.positions = {};
var ed=this.$.editor;
ed.editor.setHighlightSelectedWord(true);
ed.editor.setOption("scrollPastEnd", true);
var langTools =ace.require("ace/ext/language_tools");
ed.editor.setOptions({
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: false
});
var me=this;
var ghciCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (me.mime==='text/x-haskell'){
session.$selectLongWords = true;
var Selection=ace.require("ace/selection").Selection;
var sel=new Selection(session);
sel.setSelectionRange(session.getSelection().getRange());
sel.moveCursorToPosition(editor.getCursorPosition());
sel.selectWordLeft();
var prev=editor.getSession().getTextRange(sel.getRange());
while (prev && prev.length>0 && prev.indexOf(' ')==-1 && sel.getRange().start.column>1){
sel.selectWordLeft();
prev=editor.getSession().getTextRange(sel.getRange());
}
if (prev && prev.startsWith("import")){
prefix=prev;
}
console.log("completions for:"+prefix,":previous:"+prev);
var aj=me.$.ajaxComplete;
me.completeCallback=callback;
aj.url="/complete/"+me.path+"?word="+encodeURIComponent(prefix);
aj.generateRequest();
} else {
callback(null, []);
}
}
}
langTools.addCompleter(ghciCompleter);
this.tooltip=null;
ed.editor.commands.addCommand({
name: "info",
bindKey: {win: "Ctrl-I", mac: "Command-I"},
exec: function(editor) {
me.info();
}
});
//ed.editor.resize();
var s=ed.editor.getSession();
s.on('changeScrollTop',this.captureScrollTop.bind(this));
s.getSelection().on('changeCursor',this.captureCursor.bind(this));
},
captureScrollTop: function(){
if (this.path && this.editing){
var s=this.$.editor.editor.getSession();
var pos=this.positions[this.path];
if (!pos){
pos={};
this.positions[this.path]=pos;
}
pos.scrollTop=s.getScrollTop();
}
},
captureCursor: function(){
if (this.path && this.editing){
var ed=this.$.editor.editor;
var cp=ed.getCursorPosition();
var pos=this.positions[this.path];
if (!pos){
pos={};
this.positions[this.path]=pos;
}
pos.cursor=cp;
}
},
info: function(){
var aj=this.$.ajaxInfo;
var editor=this.$.editor.editor;
if (this.mime==='text/x-haskell'){
editor.getSelection().selectWord();
var word=editor.getSession().getTextRange(editor.getSelection().getRange());
//console.log(word);
aj.url="/info/"+this.path+"?word="+encodeURIComponent(word);
aj.generateRequest();
}
},
format: function(){
var aj=this.$.ajaxFormat;
if (this.mime==='text/x-haskell'){
aj.generateRequest();
}
},
updateStatus: function(){
var st=this.status[this.path];
var ed=this.$.editor;
ed.editor.getSession().clearAnnotations();
if (st){
var anns=[];
for (var i=0;i<st.messages.length;i++){
var msg=st.messages[i];
var type=msg.severity.toLowerCase();
anns.push({
row: msg.line-1,
column: msg.column-1,
text: msg.message.join("\n").trim(),
type: type
});
}
ed.editor.getSession().setAnnotations(anns);
}
var pos=this.positions[this.path];
if (pos){
if (pos.scrollTop){
ed.editor.getSession().setScrollTop(pos.scrollTop);
}
if (pos.cursor){
ed.editor.moveCursorToPosition(pos.cursor);
}
}
},
addLine: function(text){
var ed=this.$.editor;
var session=ed.editor.getSession();
session.insert({
row: session.getLength(),
column: 0
}, "\n" + text);
},
resetEditor: function(){
var ed=this.$.editor;
ed.editor.clearSelection( );
ed.editor.moveCursorTo(0,0);
ed.editor.focus();
},
setValue: function(text){
var ed=this.$.editor;
ed.editor.getSession().setValue(text);
this.resetEditor();
},
setConfig: function(c){
if (c && c.editor){
var ed=this.$.editor;
for (var i in c.editor){
var val = c.editor[i];
if (i==="theme"){
if (val.indexOf("/")==-1){
val="ace/theme/"+val.toLowerCase().replace(' ','_');
}
}
ed.setAttribute(i,val);
}
}
},
reloadFile: function(d){
if (d.reload===this.path){
this.pathChanged();
}
}
});
</script>
</dom-module>