Browse code

"Upload file input"

Doug Le Tough authored on 02/12/2017 00:06:13
Showing 13 changed files
... ...
@@ -1,2 +1,3 @@
1 1
 SQLALCHEMY_TRACK_MODIFICATIONS = True
2 2
 SQLALCHEMY_DATABASE_URI = "postgresql://tetawebapp:tetawebapp@localhost/tetawebapp"
3
+UPLOADED_FILES_DEST = "./upload"
3 4
new file mode 100644
4 5
Binary files /dev/null and b/tetawebapp/static/images/upload.png differ
... ...
@@ -4,6 +4,9 @@ var light_red = "#FCD5DC";
4 4
 var light_green = "#D5FCD8";
5 5
 var base_bg = "#FFFFFF";
6 6
 var base_border = "#888888";
7
+var coloured_bg = "#FF5D00";
8
+var clear_bg = "#E5E5E5";
9
+var text_color = "#555555";
7 10
 
8 11
 /* **************************************************************************************
9 12
  * GLOBAL
... ...
@@ -26,6 +29,17 @@ function getcookie(cname) {
26 26
 }
27 27
 
28 28
 // Eye candies
29
+function valid_input(obj) {
30
+  // Valid input makes obj background to glow green for 2 seconds
31
+  // If obj borders were red, they get they normal color back
32
+  obj.style.backgroundColor = light_green;
33
+  obj.style.borderColor = base_border;
34
+  setTimeout( function() {
35
+    obj.style.backgroundColor = base_bg;
36
+    }
37
+  , 2000);
38
+}
39
+
29 40
 function invalid_input(obj) {
30 41
   // Invalid input makes obj borders and background to glow red for 2 seconds
31 42
   // Border color will stay red until a valid input is sent
... ...
@@ -37,17 +51,48 @@ function invalid_input(obj) {
37 37
   , 2000);
38 38
 }
39 39
 
40
-function valid_input(obj) {
40
+function valid_upload(obj) {
41 41
   // Valid input makes obj background to glow green for 2 seconds
42 42
   // If obj borders were red, they get they normal color back
43
-  obj.style.backgroundColor = light_green;
44
-  obj.style.borderColor = base_border;
43
+  obj.style.backgroundColor = green;
44
+  obj.style.borderColor = text_color;
45
+  obj.style.borderStyle = 'solid';
45 46
   setTimeout( function() {
46
-    obj.style.backgroundColor = base_bg;
47
+    obj.style.backgroundColor = clear_bg;
48
+    obj.style.borderStyle = 'none';
47 49
     }
48 50
   , 2000);
49 51
 }
50 52
 
53
+function invalid_upload(obj) {
54
+  // Invalid input makes obj borders and background to glow red for 2 seconds
55
+  // Border color will stay red until a valid input is sent
56
+  obj.style.backgroundColor = red;
57
+  obj.style.borderColor = text_color;
58
+  obj.style.borderStyle = 'solid';
59
+  setTimeout( function() {
60
+    obj.style.borderStyle = 'solid';
61
+    obj.style.backgroundColor = clear_bg;
62
+    obj.style.borderColor = red;
63
+    }
64
+  , 2000);
65
+}
66
+
67
+function lit(obj) {
68
+  // Lit bacground and border on obj (use by input type=file)
69
+  obj.style.backgroundColor = coloured_bg;
70
+  obj.style.borderColor = text_color;
71
+  obj.style.borderStyle = 'solid';
72
+}
73
+
74
+function unlit(obj) {
75
+  // Unlit bacground and border on obj (use by input type=file)
76
+  obj.style.backgroundColor = clear_bg;
77
+  obj.style.borderColor = clear_bg;
78
+  obj.style.borderStyle = 'none';
79
+}
80
+
81
+
51 82
 function verify_login() {
52 83
   // Verify login inputs
53 84
   login = document.getElementById('login');
... ...
@@ -140,7 +185,7 @@ function get_value_from_ajax(obj, url, err_code) {
140 140
   xhttp.onload = function(){
141 141
     if (xhttp.status != 200) {
142 142
       invalid_input(obj);
143
-      } 
143
+      }
144 144
   };
145 145
 
146 146
   xhttp.onreadystatechange = function() {
... ...
@@ -156,6 +201,44 @@ function get_value_from_ajax(obj, url, err_code) {
156 156
     }
157 157
   };
158 158
   xhttp.open('POST', url, true);
159
+  alert(xhttp.readyState);
159 160
   xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
160 161
   xhttp.send();
161 162
 }
163
+
164
+function upload_file_from_ajax(obj, url, err_code) {
165
+  // Upload files get from <obj> to the specified <url>
166
+  // if <errcode> is returned input is invalidated
167
+  var files = obj.files;
168
+  var icon_id = obj.id.substring(obj.id.lastIndexOf("_") + 1);
169
+  var icon_obj = document.getElementById("upload_icon_" + icon_id)
170
+  var xhttp = new XMLHttpRequest();
171
+  xhttp.onerror = function(){
172
+    invalid_upload(icon_obj);
173
+  };
174
+
175
+  xhttp.onload = function(){
176
+    if (xhttp.status != 200) {
177
+      invalid_upload(icon_obj);
178
+      } 
179
+  };
180
+
181
+  xhttp.onreadystatechange = function() {
182
+    if (xhttp.readyState == 4 && xhttp.status == 200) {
183
+      var response = xhttp.responseText;
184
+      if (response == err_code) {
185
+        invalid_upload(icon_obj);
186
+        return;
187
+      }
188
+      valid_upload(icon_obj);
189
+      return;
190
+    }
191
+  };
192
+  
193
+  xhttp.open('POST', url, true);
194
+  var formData = new FormData();
195
+  for (var i=0; i < files.length; i++){
196
+    formData.append("files", files[i], files[i].name);
197
+  }
198
+  xhttp.send(formData);
199
+}
... ...
@@ -25,4 +25,5 @@
25 25
     --save_icon: url(/static/images/save.png);
26 26
     --search_icon: url(/static/images/search.png);
27 27
     --trash_icon: url(/static/images/trash.png);
28
+    --upload_icon: url(/static/images/upload.png);
28 29
 }
... ...
@@ -254,12 +254,36 @@ input[type="submit"] {
254 254
 
255 255
 button:hover,
256 256
 input[type="button"]:hover,
257
-input[type="submit"]:hover {
257
+input[type="submit"]:hover,
258
+input[type="file"]:hover {
258 259
   background-color: var(--light-coloured-bg);
259 260
   color: var(--text-color);
260 261
   cursor: pointer;
261 262
 }
262 263
 
264
+div.file_upload {
265
+  display: inline-block;
266
+  position: relative;
267
+  width: 20px;
268
+  height: 20px;
269
+  margin: 0;
270
+  padding: 0;
271
+  border-radius: 2px;
272
+  border-style: solid;
273
+  border-width: 1px;
274
+  border-color: var(--clear-bg);
275
+}
276
+
277
+input[type="file"] {
278
+  position: absolute;
279
+  width: 18px;
280
+  height: 18px;
281
+  left: 0;
282
+  top: 1px;
283
+  opacity: 0;
284
+}
285
+
286
+
263 287
 input.add,
264 288
 input.edit,
265 289
 input.login,
... ...
@@ -267,7 +291,8 @@ input.logout,
267 267
 input.refresh,
268 268
 input.save,
269 269
 input.search,
270
-input.trash {
270
+input.trash,
271
+input.upload {
271 272
   width: 20px;
272 273
   height: 20px;
273 274
   margin: 0;
... ...
@@ -283,7 +308,8 @@ input.logout:hover,
283 283
 input.refresh:hover,
284 284
 input.save:hover,
285 285
 input.search:hover,
286
-input.trash:hover {
286
+input.trash:hover,
287
+input.upload:hover {
287 288
   border-color: var(--text-color);
288 289
   border-style: solid;
289 290
   border-width: 1px;
... ...
@@ -331,3 +357,8 @@ input.trash {
331 331
   background-repeat: no-repeat;
332 332
   background-position: center center;
333 333
 }
334
+input.upload {
335
+  background: var(--upload_icon);
336
+  background-repeat: no-repeat;
337
+  background-position: center center;
338
+}
... ...
@@ -25,4 +25,16 @@
25 25
           <input type='button' value="Try me" onclick='javascript:get_value_from_ajax(document.getElementById("value_receiver"), "/get_value_from_ajax", "TETA_ERR");'>
26 26
         </article>
27 27
       </section>
28
+      <article class='left'>
29
+        <h3>Upload files with AJAX</h3>
30
+        <p>Select files to upload</p>
31
+        <p>The response may randomly be an error response so you should try it more than once.</p>
32
+        <div class='file_upload'>
33
+          <!--
34
+            Input file is a tricky hack (see tetawebapp.css and tetawebapp.js)
35
+          -->
36
+          <input type='button' id='upload_icon_1' class='upload' title='Upload' value=' '/>
37
+          <input type='file' id='upload_input_1' multiple title='Upload' value='' onchange='javascript:upload_file_from_ajax(this, "/upload", "TETA_ERR");' onmouseover='javascript:lit(document.getElementById("upload_icon_1"));' onmouseout='javascript:unlit(document.getElementById("upload_icon_1"));'/>
38
+        </div>
39
+      </article>
28 40
       {% endblock %}
... ...
@@ -20,14 +20,21 @@
20 20
         <br/>
21 21
         <input type='button' value='And me !' />
22 22
         <br/>
23
-        <input type='button' class='add' title='add' value=' '/>
24
-        <input type='button' class='edit' title='edit' value=' '/>
25
-        <input type='button' class='login' title='login' value=' '/>
26
-        <input type='button' class='logout' title='logout' value=' '/>
27
-        <input type='button' class='refresh' title='refresh' value=' '/>
28
-        <input type='button' class='save' title='save' value=' '/>
29
-        <input type='button' class='search' title='search' value=' '/>
30
-        <input type='button' class='trash' title='trash' value=' '/>
23
+        <input type='button' class='add' title='Add' value=' '/>
24
+        <input type='button' class='edit' title='Edit' value=' '/>
25
+        <input type='button' class='login' title='Login' value=' '/>
26
+        <input type='button' class='logout' title='Logout' value=' '/>
27
+        <input type='button' class='refresh' title='Refresh' value=' '/>
28
+        <input type='button' class='save' title='Save' value=' '/>
29
+        <input type='button' class='search' title='Search' value=' '/>
30
+        <input type='button' class='trash' title='Trash' value=' '/>
31
+        <!--
32
+          Input file is a tricky hack (see tetawebapp.css and tetawebapp.js)
33
+        -->
34
+        <div class='file_upload'>
35
+          <input type='button' id='upload_icon_1' class='upload' title='Upload' value=' '/>
36
+          <input type='file' id='upload_input_1' name='files' multiple title='Upload' value='' onchange='javascript:upload_file_from_ajax(this, "/upload", "TETA_ERR");' onmouseover='javascript:lit(document.getElementById("upload_icon_1"));' onmouseout='javascript:unlit(document.getElementById("upload_icon_1"));'/>
37
+        </div>
31 38
         <br/>
32 39
         <pre>
33 40
 #!/bin/sh
... ...
@@ -224,7 +224,7 @@ def get_html_from_ajax():
224 224
   """ Return HTML code to an AJAX request
225 225
       It may generate a 404 http error for testing purpose """
226 226
   if int(random.random()*10) % 2:
227
-    # Randomlu generate 404 HTTP response
227
+    # Randomly generate 404 HTTP response
228 228
     return render_template('error.html'), 404
229 229
   return render_template('ajax_html.html')
230 230
 
... ...
@@ -236,7 +236,7 @@ def get_value_from_ajax():
236 236
   err_code = 'TETA_ERR'
237 237
   RND = int(random.random()*10)
238 238
   if RND % 2:
239
-    # Randomlu generate error
239
+    # Randomly generate error
240 240
     return err_code
241 241
   return str(RND)
242 242
 
... ...
@@ -250,6 +250,31 @@ def set_value_from_ajax(value):
250 250
     return 'True'
251 251
   return err_code
252 252
 
253
+@app.route("/upload", methods=['POST'])
254
+@check_session
255
+def upload():
256
+  """ Accept a value from an AJAX request
257
+      It may return an error code for testing purpose """
258
+  err_code = 'TETA_ERR'
259
+  RND = int(random.random()*10)
260
+  if RND % 2:
261
+    # Randomly generate error
262
+    print err_code
263
+    return err_code
264
+  uploaded_files = []
265
+  if len(request.files) > 0 and request.files['files']:
266
+    uploaded_files = request.files.getlist("files")
267
+  print "Uploaded files:"
268
+  for f in uploaded_files:
269
+    print '  [+] %s [%s]' % (f.filename, f.content_type)
270
+    # Befor saving you should:
271
+    # - Secure the filename
272
+    # - Check file size
273
+    # - Check content type
274
+    f.save(os.path.join(app.config['UPLOADED_FILES_DEST'], f.filename))
275
+    f.close()
276
+  return "OK"
277
+
253 278
 ########################################################################
254 279
 # Main
255 280
 ########################################################################
256 281
new file mode 100644
257 282
Binary files /dev/null and b/tetawebapp/upload/what_you_ride_final.xcf differ
258 283
new file mode 100644
259 284
Binary files /dev/null and b/tetawebapp/upload/what_you_ride_final2.png differ
260 285
new file mode 100644
261 286
Binary files /dev/null and b/tetawebapp/upload/what_you_ride_final2.xcf differ
262 287
new file mode 100644
263 288
Binary files /dev/null and b/tetawebapp/upload/what_you_ride_final3.png differ
264 289
new file mode 100644
265 290
Binary files /dev/null and b/tetawebapp/upload/what_you_ride_final3.xcf differ