packages feed

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>