Browse Source

Basic save functionality with editable file names, beginning of work to enable loading of files too

master
Lewis Hemens 5 years ago
parent
commit
a5c63cdfb1
4 changed files with 140 additions and 31 deletions
  1. 12
    5
      index.html
  2. 38
    0
      jquery.jeditable.min.js
  3. 28
    17
      js-compiled.js
  4. 62
    9
      js-lib/drive-controller.js

+ 12
- 5
index.html View File

@@ -9,10 +9,11 @@
9 9
 
10 10
 * {
11 11
   font-weight: bold;
12
+  font-family: sans-serif;
12 13
   font-size: 0.95em;
13 14
 }
14 15
 
15
-#draw-tools, #file-tools, #edit-tools {
16
+#draw-tools, #file-tools, #edit-tools, #drive-tools {
16 17
   display: inline-block;
17 18
   position: relative;
18 19
   float: left;
@@ -93,6 +94,10 @@ button {
93 94
   border-bottom: 1px solid #444;
94 95
 }
95 96
 
97
+#drive-textarea {
98
+  margin: 9px;
99
+}
100
+
96 101
 #logo pre {
97 102
   margin: 0px;
98 103
   display: none;
@@ -135,11 +140,15 @@ textarea {
135 140
   <button id="export-button" class="tool">Export</button>
136 141
   <button id="import-button" class="tool">Import</button>
137 142
   <button id="save-button" class="tool">Save</button>
143
+  <button id="save-button" class="tool">Open</button>
138 144
 </div>
139 145
 <div id="edit-tools">
140 146
   <button id="clear-button" class="tool">Clear</button>
141 147
   <button id="undo-button" class="tool">Undo</button>
142 148
 </div>
149
+<div id="drive-tools">
150
+  <div id="drive-filename" class="edit"></div>
151
+</div>
143 152
 
144 153
 <div id="export-button-dialog" class="dialog">
145 154
   <textarea id="export-area"></textarea>
@@ -150,13 +159,11 @@ textarea {
150 159
   <button class="close-dialog-button">Close</button>
151 160
   <button id="import-submit-button">Submit</button>
152 161
 </div>
153
-<div id="authorize-dialog" class="dialog">
154
-  <button id="authorize-button">Authorize</button>
155
-  <button class="close-dialog-button">Close</button>
156
-</div>
157 162
 <canvas id="ascii-canvas"></canvas>
163
+<script src="https://apis.google.com/js/api.js"></script>
158 164
 <script src="https://apis.google.com/js/client.js"></script>
159 165
 <script src="jquery-1.9.1.min.js"></script>
166
+<script src="jquery.jeditable.min.js"></script>
160 167
 <script src="js-compiled.js"></script>
161 168
 </body>
162 169
 </html>

+ 38
- 0
jquery.jeditable.min.js View File

@@ -0,0 +1,38 @@
1
+
2
+(function($){$.fn.editable=function(target,options){if('disable'==target){$(this).data('disabled.editable',true);return;}
3
+if('enable'==target){$(this).data('disabled.editable',false);return;}
4
+if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;}
5
+var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);}
6
+settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);}
7
+$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
8
+if(self.editing){return;}
9
+if(false===onedit.apply(this,[settings,self])){return;}
10
+e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');}
11
+if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;}
12
+if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}}
13
+if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');}
14
+self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('<form />');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}}
15
+if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}}
16
+var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);}
17
+$.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;}
18
+content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();}
19
+input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});}
20
+form.submit(function(e){if(t){clearTimeout(t);}
21
+e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);}
22
+if('PUT'==settings.method){submitdata['_method']='put';}
23
+$(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);}
24
+self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}}
25
+$(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);}
26
+if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('<input type="hidden"></input>');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('<button type="submit" />');submit.html(settings.submit);}
27
+$(this).append(submit);}
28
+if(settings.cancel){if(settings.cancel.match(/>$/)){var cancel=$(settings.cancel);}else{var cancel=$('<button type="cancel" />');cancel.html(settings.cancel);}
29
+$(this).append(cancel);$(cancel).click(function(event){if($.isFunction($.editable.types[settings.type].reset)){var reset=$.editable.types[settings.type].reset;}else{var reset=$.editable.types['defaults'].reset;}
30
+reset.apply(form,[settings,original]);return false;});}}},text:{element:function(settings,original){var input=$('<input />');if(settings.width!='none'){input.width(settings.width);}
31
+if(settings.height!='none'){input.height(settings.height);}
32
+input.attr('autocomplete','off');$(this).append(input);return(input);}},textarea:{element:function(settings,original){var textarea=$('<textarea />');if(settings.rows){textarea.attr('rows',settings.rows);}else if(settings.height!="none"){textarea.height(settings.height);}
33
+if(settings.cols){textarea.attr('cols',settings.cols);}else if(settings.width!="none"){textarea.width(settings.width);}
34
+$(this).append(textarea);return(textarea);}},select:{element:function(settings,original){var select=$('<select />');$(this).append(select);return(select);},content:function(data,settings,original){if(String==data.constructor){eval('var json = '+data);}else{var json=data;}
35
+for(var key in json){if(!json.hasOwnProperty(key)){continue;}
36
+if('selected'==key){continue;}
37
+var option=$('<option />').val(key).append(json[key]);$('select',this).append(option);}
38
+$('select',this).children().each(function(){if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){$(this).attr('selected','selected');}});}}},addInputType:function(name,input){$.editable.types[name]=input;}};$.fn.editable.defaults={name:'value',id:'id',type:'text',width:'auto',height:'auto',event:'click.editable',onblur:'cancel',loadtype:'GET',loadtext:'Loading...',placeholder:'Click to edit',loaddata:{},submitdata:{},ajaxoptions:{}};})(jQuery);

+ 28
- 17
js-compiled.js View File

@@ -492,29 +492,40 @@ function X(a) {
492 492
   }.bind(this));
493 493
 }
494 494
 function ha(a) {
495
-  window.gapi.auth.authorize({client_id:"125643747010-9s9n1ne2fnnuh5v967licfkt83r4vba5.apps.googleusercontent.com", scope:"https://www.googleapis.com/auth/drive", immediate:!1}, function(b) {
496
-    b && !b.error ? a(!0) : (window.alert(b.error), a(!1));
495
+  window.gapi.auth.authorize({client_id:"125643747010-9s9n1ne2fnnuh5v967licfkt83r4vba5.apps.googleusercontent.com", scope:"https://www.googleapis.com/auth/drive", immediate:!0}, function(b) {
496
+    b && !b.error ? a(!0) : window.gapi.auth.authorize({client_id:"125643747010-9s9n1ne2fnnuh5v967licfkt83r4vba5.apps.googleusercontent.com", scope:"https://www.googleapis.com/auth/drive", immediate:!1}, function(b) {
497
+      a(b && !b.error);
498
+    });
497 499
   });
498 500
 }
501
+function ia(a, b) {
502
+  a.file = b;
503
+  $("#drive-filename").text(b.title);
504
+  $("#drive-filename").editable(function(a) {
505
+    this.file.title = a;
506
+    this.save();
507
+    $("#drive-filename").off();
508
+    return a;
509
+  }.bind(a), {type:"text", submit:"OK"});
510
+}
499 511
 X.prototype.save = function() {
500 512
   window.gapi.client.load("drive", "v2", function() {
501 513
     ha(function(a) {
502
-      a && ia(this).execute(function(a) {
503
-        window.console.log(a);
504
-      });
514
+      a && ja(this).execute(function(a) {
515
+        ia(this, a);
516
+      }.bind(this));
505 517
     }.bind(this));
506 518
   }.bind(this));
507 519
 };
508
-function ia(a) {
509
-  a = U(a.state);
510
-  a = "\r\n---------314159265358979323846\r\nContent-Type: application/json\r\n\r\n" + JSON.stringify({title:"Untitled ASCII Diagram", mimeType:"text/plain"}) + "\r\n---------314159265358979323846\r\nContent-Type: text/plain\r\n\r\n" + a + "\r\n---------314159265358979323846--";
511
-  return window.gapi.client.request({path:"/upload/drive/v2/files", method:"POST", params:{uploadType:"multipart"}, headers:{"Content-Type":'multipart/mixed; boundary="-------314159265358979323846"'}, body:a});
520
+function ja(a) {
521
+  var b = U(a.state), b = "\r\n---------314159265358979323846\r\nContent-Type: application/json\r\n\r\n" + JSON.stringify({title:null == a.file ? "Untitled ASCII Diagram" : a.file.title, mimeType:"text/plain"}) + "\r\n---------314159265358979323846\r\nContent-Type: text/plain\r\n\r\n" + b + "\r\n---------314159265358979323846--";
522
+  return window.gapi.client.request({path:"/upload/drive/v2/files" + (null == a.file ? "" : "/" + a.file.id), method:null == a.file ? "POST" : "PUT", params:{uploadType:"multipart"}, headers:{"Content-Type":'multipart/mixed; boundary="-------314159265358979323846"'}, body:b});
512 523
 }
513
-;function ja(a) {
524
+;function ka(a) {
514 525
   this.b = a;
515 526
   this.o();
516 527
 }
517
-ja.prototype.o = function() {
528
+ka.prototype.o = function() {
518 529
   var a = this.b.view.canvas;
519 530
   $(a).bind("mousewheel", function(a) {
520 531
     a = this.b.view.zoom * (0 < a.originalEvent.wheelDelta ? 1.1 : 0.9);
@@ -549,7 +560,7 @@ function Y(a) {
549 560
   this.s = this.k = !1;
550 561
   this.o();
551 562
 }
552
-function ka(a, b) {
563
+function la(a, b) {
553 564
   a.A = b;
554 565
   a.D = $.now();
555 566
   a.k = !1;
@@ -580,7 +591,7 @@ Y.prototype.o = function() {
580 591
   $(a).bind("touchstart", function(a) {
581 592
     a.preventDefault();
582 593
     if (1 == a.originalEvent.touches.length) {
583
-      ka(this, new f(a.originalEvent.touches[0].pageX, a.originalEvent.touches[0].pageY));
594
+      la(this, new f(a.originalEvent.touches[0].pageX, a.originalEvent.touches[0].pageY));
584 595
     } else {
585 596
       if (1 < a.originalEvent.touches.length) {
586 597
         var c = new f(a.originalEvent.touches[0].pageX, a.originalEvent.touches[0].pageY);
@@ -611,9 +622,9 @@ Y.prototype.o = function() {
611 622
     W(this.b);
612 623
   }.bind(this));
613 624
 };
614
-var Z = new S, la = new x(Z), ma = new V(la, Z);
615
-new Y(ma);
616
-new ja(ma);
625
+var Z = new S, ma = new x(Z), na = new V(ma, Z);
626
+new Y(na);
627
+new ka(na);
617 628
 new X(Z);
618
-la.animate();
629
+ma.animate();
619 630
 

+ 62
- 9
js-lib/drive-controller.js View File

@@ -2,6 +2,8 @@
2 2
 var CLIENT_ID = '125643747010-9s9n1ne2fnnuh5v967licfkt83r4vba5.apps.googleusercontent.com';
3 3
 /** @const */
4 4
 var SCOPES = 'https://www.googleapis.com/auth/drive';
5
+/** @const */
6
+var DEVELOPER_KEY = 'AIzaSyBbKO_v9p-G9StQjYmtUYLP6Px4MkGions';
5 7
 
6 8
 /**
7 9
  * 
@@ -10,9 +12,10 @@ var SCOPES = 'https://www.googleapis.com/auth/drive';
10 12
 ascii.DriveController = function(state) {
11 13
   /** @type {ascii.State} */
12 14
   this.state = state;
15
+  // This is a file resource, as defined by the Drive API.
13 16
   /** @type {Object} */
14 17
   this.file = null;
15
-  // Let's just hope this happens before anyone clicks save/open.
18
+
16 19
   $('#save-button').click(function(e) {
17 20
       this.save();
18 21
   }.bind(this));
@@ -25,18 +28,62 @@ ascii.DriveController.prototype.checkAuth = function(callback) {
25 28
   window['gapi']['auth']['authorize']({
26 29
       'client_id': CLIENT_ID,
27 30
       'scope': SCOPES,
28
-      'immediate': false},
31
+      'immediate': true},
29 32
       function(result) {
30 33
         if (result && !result.error) {
31 34
           callback(true);
32 35
         } else {
33
-          window.alert(result.error);
34
-          callback(false);
36
+          window['gapi']['auth']['authorize']({
37
+              'client_id': CLIENT_ID,
38
+              'scope': SCOPES,
39
+              'immediate': false},
40
+              function(result) {
41
+                callback(result && !result.error);
42
+              });
35 43
         }
36 44
       });
37 45
 };
38 46
 
39 47
 /**
48
+ * Handles a file resource being returned from Drive.
49
+ */
50
+ascii.DriveController.prototype.handleFile = function(file) {
51
+  this.file = file;
52
+  $('#drive-filename').text(file['title']);
53
+  $('#drive-filename')['editable'](function(value, settings) {
54
+      this.file['title'] = value;
55
+      this.save();
56
+      // Remove the event handler.
57
+      $('#drive-filename').off();
58
+      return value;
59
+    }.bind(this),
60
+    { 
61
+      type    : 'text',
62
+      submit  : 'OK',
63
+    });
64
+};
65
+
66
+
67
+/**
68
+ * Loads the picker.
69
+ * TODO: Implement this...
70
+ */
71
+ascii.DriveController.prototype.load = function() {
72
+/*
73
+  window['gapi']['client']['load']('picker',
74
+     {'callback': function() {
75
+    var picker = new window['google']['picker']['PickerBuilder']().
76
+              addView(google.picker.ViewId.PHOTOS).
77
+              setOAuthToken(oauthToken).
78
+              setDeveloperKey(developerKey).
79
+              setCallback(pickerCallback).
80
+              build();
81
+          picker.setVisible(true);
82
+}});
83
+*/
84
+};
85
+
86
+/**
40 87
  * Saves the current diagram to drive.
41 88
  */
42 89
 ascii.DriveController.prototype.save = function() {
@@ -44,8 +91,8 @@ ascii.DriveController.prototype.save = function() {
44 91
       this.checkAuth(function(authed) {
45 92
           if (authed) {
46 93
             this.getSaveRequest().execute(function(result) {
47
-                window.console.log(result);
48
-            });
94
+                this.handleFile(result);
95
+            }.bind(this));
49 96
           }
50 97
       }.bind(this))
51 98
   }.bind(this));
@@ -58,8 +105,10 @@ ascii.DriveController.prototype.getSaveRequest = function() {
58 105
   var delimiter = "\r\n--" + boundary + "\r\n";
59 106
   var close_delim = "\r\n--" + boundary + "--";
60 107
 
108
+  var title = this.file == null ? 'Untitled ASCII Diagram' : this.file['title'];
109
+
61 110
   var metadata = {
62
-      'title': 'Untitled ASCII Diagram',
111
+      'title': title,
63 112
       'mimeType': 'text/plain'
64 113
   };
65 114
 
@@ -73,9 +122,13 @@ ascii.DriveController.prototype.getSaveRequest = function() {
73 122
       text +
74 123
       close_delim;
75 124
 
125
+  // Choose upload path and method depending on whether we have create a file already.
126
+  var fileId = this.file == null ? '' : '/' + this.file['id'];
127
+  var method = this.file == null ? 'POST' : 'PUT';
128
+
76 129
   return window['gapi']['client']['request']({
77
-      'path': '/upload/drive/v2/files',
78
-      'method': 'POST',
130
+      'path': '/upload/drive/v2/files' + fileId,
131
+      'method': method,
79 132
       'params': {'uploadType': 'multipart'},
80 133
       'headers': {
81 134
         'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'

Loading…
Cancel
Save