Compare commits
	
		
			39 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c2f4de822f | |||
| ffd4c03d9c | |||
| 2e08ac06ca | |||
| 6d739972de | |||
| e36fd43f9b | |||
| 35bbc6c61b | |||
| 987c704730 | |||
| 9669f2aa0b | |||
| 99139e360d | |||
| 696a92096d | |||
| f125c23fb9 | |||
| c50d6c4bfe | |||
| 5edea74333 | |||
| 1882a94e65 | |||
| 1309293705 | |||
| d24c3d4895 | |||
| 5e9fcc09c8 | |||
| fb7f1dd3a5 | |||
| 2f4fe0a55f | |||
| a3fc9092e3 | |||
| 6eb48bf72f | |||
| 40aa6c8917 | |||
| 24febefba4 | |||
| 57d9b4d324 | |||
| 3ca73e3221 | |||
| 27cf4cf0c0 | |||
| ef6b680b7e | |||
| 188ca7e679 | |||
| b8f1b26aba | |||
| ac768524ee | |||
| a5008ab455 | |||
| 9436dcd43e | |||
| f543347b1c | |||
| 582854878b | |||
| 642ee5a485 | |||
| 19b20daded | |||
| 270e6a9397 | |||
| ef5351a075 | |||
| 01ac021c7e | 
							
								
								
									
										8
									
								
								.hgtags
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								.hgtags
									
									
									
									
									
								
							@@ -1 +1,9 @@
 | 
				
			|||||||
e2250a7fd29052ea767f18e1459cabea4cd7efd3 release-1.0.0
 | 
					e2250a7fd29052ea767f18e1459cabea4cd7efd3 release-1.0.0
 | 
				
			||||||
 | 
					b8975b9e75648a7c2a5003c67db92cf2216e01c0 release-1.0.1
 | 
				
			||||||
 | 
					c7b699105bd166e7a01aa0e678d34624680bf81e release-1.1.0
 | 
				
			||||||
 | 
					c7b699105bd166e7a01aa0e678d34624680bf81e release-1.1.0
 | 
				
			||||||
 | 
					0000000000000000000000000000000000000000 release-1.1.0
 | 
				
			||||||
 | 
					0000000000000000000000000000000000000000 release-1.1.0
 | 
				
			||||||
 | 
					cfb1e028fd0627614aa01184893f9f29f20a347e release-1.1.0
 | 
				
			||||||
 | 
					cfb1e028fd0627614aa01184893f9f29f20a347e release-1.1.0
 | 
				
			||||||
 | 
					0000000000000000000000000000000000000000 release-1.1.0
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
				
			|||||||
# Makefile for contented
 | 
					# Makefile for contented
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VERSION:=1.0.1
 | 
					VERSION:=1.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES:=Makefile \
 | 
					SOURCES:=Makefile \
 | 
				
			||||||
	static \
 | 
						static \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								Server.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								Server.go
									
									
									
									
									
								
							@@ -23,6 +23,8 @@ type ServerOptions struct {
 | 
				
			|||||||
	DataDirectory      string
 | 
						DataDirectory      string
 | 
				
			||||||
	DBPath             string
 | 
						DBPath             string
 | 
				
			||||||
	BandwidthLimit     int64
 | 
						BandwidthLimit     int64
 | 
				
			||||||
 | 
						TrustXForwardedFor bool
 | 
				
			||||||
 | 
						EnableHomepage     bool
 | 
				
			||||||
	ServerPublicProperties
 | 
						ServerPublicProperties
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,7 +77,13 @@ func (this *Server) handleAbout(w http.ResponseWriter) {
 | 
				
			|||||||
	this.serveJsonObject(w, this.opts.ServerPublicProperties)
 | 
						this.serveJsonObject(w, this.opts.ServerPublicProperties)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func remoteIP(r *http.Request) string {
 | 
					func (this *Server) remoteIP(r *http.Request) string {
 | 
				
			||||||
 | 
						if this.opts.TrustXForwardedFor {
 | 
				
			||||||
 | 
							if xff := r.Header.Get("X-Forwarded-For"); len(xff) > 0 {
 | 
				
			||||||
 | 
								return xff
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return strings.TrimRight(strings.TrimRight(r.RemoteAddr, "0123456789"), ":")
 | 
						return strings.TrimRight(strings.TrimRight(r.RemoteAddr, "0123456789"), ":")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,10 +120,10 @@ func (this *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
		// Blanket allow (headers already set)
 | 
							// Blanket allow (headers already set)
 | 
				
			||||||
		w.WriteHeader(200)
 | 
							w.WriteHeader(200)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else if r.Method == "GET" && r.URL.Path == `/` {
 | 
						} else if r.Method == "GET" && r.URL.Path == `/` && this.opts.EnableHomepage {
 | 
				
			||||||
		http.Redirect(w, r, `/index.html`, http.StatusFound)
 | 
							http.Redirect(w, r, `/index.html`, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else if static, err := Asset(r.URL.Path[1:]); err == nil && r.Method == "GET" {
 | 
						} else if static, err := Asset(r.URL.Path[1:]); err == nil && r.Method == "GET" && (this.opts.EnableHomepage || r.URL.Path != `/index.html`) {
 | 
				
			||||||
		http.ServeContent(w, r, r.URL.Path[1:], this.startTime, bytes.NewReader(static))
 | 
							http.ServeContent(w, r, r.URL.Path[1:], this.startTime, bytes.NewReader(static))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								TODO.txt
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								TODO.txt
									
									
									
									
									
								
							@@ -8,6 +8,6 @@ TODO
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Nicer preview page after uploading
 | 
					- Nicer preview page after uploading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Option to disable manual uploading from the landing page
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Gallery preview (multiple element hashid)
 | 
					- Gallery preview (multiple element hashid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Prevent selecting around the toggle buttons (firefox for android)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,11 @@ You can use contented as a standalone upload server, or you can use the SDK to e
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
=FEATURES=
 | 
					=FEATURES=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Drag and drop uploader, or fallback classic uploader, or pastebin-style uploader
 | 
					- Drag and drop upload
 | 
				
			||||||
- Multiple files upload
 | 
					- Multiple files upload
 | 
				
			||||||
- Pastebin upload
 | 
					- Pastebin upload
 | 
				
			||||||
 | 
					- Custom drawing upload ([url=https://github.com/Leimi/drawingboard.js]via[/url])
 | 
				
			||||||
 | 
					- Ctrl-V upload
 | 
				
			||||||
- SDK-oriented design for embedding, including CORS support
 | 
					- SDK-oriented design for embedding, including CORS support
 | 
				
			||||||
- Mobile friendly HTML interface
 | 
					- Mobile friendly HTML interface
 | 
				
			||||||
- Preserves uploaded filename and content-type metadata
 | 
					- Preserves uploaded filename and content-type metadata
 | 
				
			||||||
@@ -24,6 +26,8 @@ You can use contented as a standalone upload server, or you can use the SDK to e
 | 
				
			|||||||
        Directory for stored content (default "")
 | 
					        Directory for stored content (default "")
 | 
				
			||||||
  -db string
 | 
					  -db string
 | 
				
			||||||
        Path for metadata database (default "contented.db")
 | 
					        Path for metadata database (default "contented.db")
 | 
				
			||||||
 | 
					  -enableHomepage
 | 
				
			||||||
 | 
					        Enable homepage (disable for embedded use only) (default true)
 | 
				
			||||||
  -listen string
 | 
					  -listen string
 | 
				
			||||||
         (default "127.0.0.1:80")
 | 
					         (default "127.0.0.1:80")
 | 
				
			||||||
  -max int
 | 
					  -max int
 | 
				
			||||||
@@ -32,8 +36,12 @@ You can use contented as a standalone upload server, or you can use the SDK to e
 | 
				
			|||||||
        Maximum upload speed in bytes/sec (set zero for unlimited)
 | 
					        Maximum upload speed in bytes/sec (set zero for unlimited)
 | 
				
			||||||
  -title string
 | 
					  -title string
 | 
				
			||||||
        Title used in web interface (default "contented")
 | 
					        Title used in web interface (default "contented")
 | 
				
			||||||
 | 
					  -trustXForwardedFor
 | 
				
			||||||
 | 
					        Trust X-Forwarded-For reverse proxy headers
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you are hosting behind a reverse proxy, remember to set its post body size parameter appropriately (e.g. `client_max_body_size` for nginx).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
=USAGE (HTTP)=
 | 
					=USAGE (HTTP)=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The server responds on the following URLs:
 | 
					The server responds on the following URLs:
 | 
				
			||||||
@@ -44,7 +52,7 @@ The server responds on the following URLs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
=USAGE (EMBEDDING FOR WEB)=
 | 
					=USAGE (EMBEDDING FOR WEB)=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Your webpage should load the SDK from the contented server, then call the `contented.init` function to display the upload widget over the top of an existing DOM element. Your callback will be passed an array of file IDs of any uploaded items. The SDK depends on jQuery.
 | 
					Your webpage should load the SDK from the contented server, then call the `contented.init` function to display the upload widget over the top of an existing DOM element. Your callback will be passed an array of file IDs of any uploaded items.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`<script type="text/javascript" src="SERVER_ADDR/sdk.js"></script>
 | 
					`<script type="text/javascript" src="SERVER_ADDR/sdk.js"></script>
 | 
				
			||||||
contented.init("#target", function(/* String[] */ items) {});
 | 
					contented.init("#target", function(/* String[] */ items) {});
 | 
				
			||||||
@@ -52,9 +60,23 @@ contented.init("#target", function(/* String[] */ items) {});
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
=CHANGELOG=
 | 
					=CHANGELOG=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2017-10-15: 1.1.0
 | 
				
			||||||
 | 
					- Feature: Drawing mode
 | 
				
			||||||
 | 
					- Feature: Ctrl+V image upload
 | 
				
			||||||
 | 
					- Feature: Option to trust X-Forwarded-For headers when using a reverse proxy
 | 
				
			||||||
 | 
					- Feature: Add `getDownloadURL`, `getInfoJSONURL`, `getPreviewURL` SDK methods
 | 
				
			||||||
 | 
					- Feature: Option to disable uploading via the homepage
 | 
				
			||||||
 | 
					- Feature: Add button to repeat when uploading from homepage
 | 
				
			||||||
 | 
					- Enhancement: Automatically load library dependencies
 | 
				
			||||||
 | 
					- Enhancement: Display homepage widget using the full screen size
 | 
				
			||||||
 | 
					- Include drawingboard.js 0.4.6 (MIT license)
 | 
				
			||||||
 | 
					- Fix a cosmetic issue with javascript console output
 | 
				
			||||||
 | 
					- Fix a cosmetic issue with error messages if an upload failed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2017-10-08: 1.0.1
 | 
					2017-10-08: 1.0.1
 | 
				
			||||||
- Fix an issue with CORS preflight requests
 | 
					- Fix an issue with CORS preflight requests
 | 
				
			||||||
- Fix an issue with index URLs
 | 
					- Fix an issue with index URLs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2017-10-08: 1.0.0
 | 
					2017-10-08: 1.0.0
 | 
				
			||||||
- Initial public release
 | 
					- Initial public release
 | 
				
			||||||
 | 
					- Include jQuery 1.12.4 (MIT license)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ func main() {
 | 
				
			|||||||
	appTitle := flag.String("title", "contented", "Title used in web interface")
 | 
						appTitle := flag.String("title", "contented", "Title used in web interface")
 | 
				
			||||||
	maxUploadMb := flag.Int("max", 8, "Maximum size of uploaded files in MiB (set zero for unlimited)")
 | 
						maxUploadMb := flag.Int("max", 8, "Maximum size of uploaded files in MiB (set zero for unlimited)")
 | 
				
			||||||
	maxUploadSpeed := flag.Int("speed", 0, "Maximum upload speed in bytes/sec (set zero for unlimited)")
 | 
						maxUploadSpeed := flag.Int("speed", 0, "Maximum upload speed in bytes/sec (set zero for unlimited)")
 | 
				
			||||||
 | 
						trustXForwardedFor := flag.Bool("trustXForwardedFor", false, "Trust X-Forwarded-For reverse proxy headers")
 | 
				
			||||||
 | 
						enableHomepage := flag.Bool("enableHomepage", true, "Enable homepage (disable for embedded use only)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,6 +27,8 @@ func main() {
 | 
				
			|||||||
		DataDirectory:      *dataDir,
 | 
							DataDirectory:      *dataDir,
 | 
				
			||||||
		DBPath:             *dbPath,
 | 
							DBPath:             *dbPath,
 | 
				
			||||||
		BandwidthLimit:     int64(*maxUploadSpeed),
 | 
							BandwidthLimit:     int64(*maxUploadSpeed),
 | 
				
			||||||
 | 
							TrustXForwardedFor: *trustXForwardedFor,
 | 
				
			||||||
 | 
							EnableHomepage:     *enableHomepage,
 | 
				
			||||||
		ServerPublicProperties: contented.ServerPublicProperties{
 | 
							ServerPublicProperties: contented.ServerPublicProperties{
 | 
				
			||||||
			AppTitle:       *appTitle,
 | 
								AppTitle:       *appTitle,
 | 
				
			||||||
			MaxUploadBytes: int64(*maxUploadMb) * 1024 * 1024,
 | 
								MaxUploadBytes: int64(*maxUploadMb) * 1024 * 1024,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
func (this *Server) handleView(w http.ResponseWriter, r *http.Request, fileID string) {
 | 
					func (this *Server) handleView(w http.ResponseWriter, r *http.Request, fileID string) {
 | 
				
			||||||
	err := this.handleViewInternal(w, r, r.URL.Path[len(downloadUrlPrefix):])
 | 
						err := this.handleViewInternal(w, r, r.URL.Path[len(downloadUrlPrefix):])
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("%s View failed: %s\n", r.RemoteAddr, err.Error())
 | 
							log.Printf("%s View failed: %s\n", this.remoteIP(r), err.Error())
 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
			http.Error(w, "File not found", 404)
 | 
								http.Error(w, "File not found", 404)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								static/drawingboard-0.4.6.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								static/drawingboard-0.4.6.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								static/drawingboard-0.4.6.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								static/drawingboard-0.4.6.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -7,9 +7,23 @@
 | 
				
			|||||||
		<style type="text/css">
 | 
							<style type="text/css">
 | 
				
			||||||
html, body {
 | 
					html, body {
 | 
				
			||||||
	font-family: sans-serif;
 | 
						font-family: sans-serif;
 | 
				
			||||||
 | 
						margin:0;
 | 
				
			||||||
 | 
						width:100%;
 | 
				
			||||||
 | 
						height:100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#padder {
 | 
				
			||||||
 | 
						height:100%;
 | 
				
			||||||
 | 
						position:relative;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#surrogate-area {
 | 
					#surrogate-area {
 | 
				
			||||||
    height:300px;
 | 
					    position:absolute;
 | 
				
			||||||
 | 
					    top:10px;
 | 
				
			||||||
 | 
					    bottom:10px;
 | 
				
			||||||
 | 
					    left:10px;
 | 
				
			||||||
 | 
					    right:10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					button.again {
 | 
				
			||||||
 | 
						margin-top:2em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/* hide close button */
 | 
					/* hide close button */
 | 
				
			||||||
.contented-close {
 | 
					.contented-close {
 | 
				
			||||||
@@ -18,9 +32,11 @@ html, body {
 | 
				
			|||||||
		</style>
 | 
							</style>
 | 
				
			||||||
	</head>
 | 
						</head>
 | 
				
			||||||
	<body>
 | 
						<body>
 | 
				
			||||||
 | 
							<div id="padder">
 | 
				
			||||||
			<div id="surrogate-area">
 | 
								<div id="surrogate-area">
 | 
				
			||||||
				Loading...
 | 
									Loading...
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        <script type="text/javascript" src="/jquery-1.12.4.min.js"></script>
 | 
					        <script type="text/javascript" src="/jquery-1.12.4.min.js"></script>
 | 
				
			||||||
		<script type="text/javascript" src="/sdk.js"></script>
 | 
							<script type="text/javascript" src="/sdk.js"></script>
 | 
				
			||||||
@@ -45,11 +61,16 @@ contented.init("#surrogate-area", function(items) {
 | 
				
			|||||||
    for (var i = 0; i < items.length; ++i) {
 | 
					    for (var i = 0; i < items.length; ++i) {
 | 
				
			||||||
        $table.append($("<tr>").append([
 | 
					        $table.append($("<tr>").append([
 | 
				
			||||||
            $("<td>").text(items[i]),
 | 
					            $("<td>").text(items[i]),
 | 
				
			||||||
            $("<td>").html("<a target='_blank' href='/get/" + items[i] + "'>get</a>"),
 | 
					            $("<td>").html("<a target='_blank' href='" + contented.getDownloadURL(items[i]) + "'>get</a>"),
 | 
				
			||||||
            $("<td>").html("<a target='_blank' href='/info/" + items[i] + "'>info</a>")
 | 
					            $("<td>").html("<a target='_blank' href='" + contented.getInfoJSONURL(items[i]) + "'>info</a>"),
 | 
				
			||||||
        ]))
 | 
					        ]))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    $("#surrogate-area").html($table);
 | 
					    $("#surrogate-area").html([
 | 
				
			||||||
 | 
							$table,
 | 
				
			||||||
 | 
							$("<button>").addClass("again").text("Again...").click(function() {
 | 
				
			||||||
 | 
								window.location.href = window.location.href;
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
		</script>
 | 
							</script>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										337
									
								
								static/sdk.js
									
									
									
									
									
								
							
							
						
						
									
										337
									
								
								static/sdk.js
									
									
									
									
									
								
							@@ -1,29 +1,48 @@
 | 
				
			|||||||
;
 | 
					;
 | 
				
			||||||
var contented = (function ($, currentScriptPath) {
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var contented = (function() {
 | 
				
			||||||
	"use strict";
 | 
						"use strict";
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
    var baseURL = currentScriptPath.replace('sdk.js', '');
 | 
						// @ref https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob 
 | 
				
			||||||
 | 
						if (!HTMLCanvasElement.prototype.toBlob) {
 | 
				
			||||||
 | 
							Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
 | 
				
			||||||
 | 
								value: function (callback, type, quality) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var formatBytes = function(bytes) {
 | 
									var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
 | 
				
			||||||
        if (bytes < 1024) {
 | 
										len = binStr.length,
 | 
				
			||||||
            return bytes + " B";
 | 
										arr = new Uint8Array(len);
 | 
				
			||||||
        } else if (bytes < (1024*1024)) {
 | 
					
 | 
				
			||||||
            return (bytes / 1024).toFixed(1) + " KiB";
 | 
									for (var i = 0; i < len; i++ ) {
 | 
				
			||||||
        } else if (bytes < (1024*1024*1024)) {
 | 
										arr[i] = binStr.charCodeAt(i);
 | 
				
			||||||
            return (bytes / (1024*1024)).toFixed(1) + " MiB";
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return (bytes / (1024*1024*1024)).toFixed(1) + " GiB";
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									callback( new Blob( [arr], {type: type || 'image/png'} ) );
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var getCurrentScriptPath = function () {
 | 
				
			||||||
 | 
					        // Determine current script path
 | 
				
			||||||
 | 
					        // @ref https://stackoverflow.com/a/26023176
 | 
				
			||||||
 | 
					        var scripts = document.querySelectorAll('script[src]');
 | 
				
			||||||
 | 
					        var currentScript = scripts[scripts.length - 1].src;
 | 
				
			||||||
 | 
					        var currentScriptChunks = currentScript.split('/');
 | 
				
			||||||
 | 
					        var currentScriptFile = currentScriptChunks[currentScriptChunks.length - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return currentScript.replace(currentScriptFile, '');
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
    /**
 | 
						var currentScriptPath = getCurrentScriptPath();
 | 
				
			||||||
     * supportsDrop returns whether drag-and-drop is supported by this browser.
 | 
						var baseURL = currentScriptPath.replace('sdk.js', '');
 | 
				
			||||||
     *
 | 
						
 | 
				
			||||||
     * @return bool
 | 
						return {
 | 
				
			||||||
     */
 | 
							"loaded": false,
 | 
				
			||||||
    var supportsDrop = function () {
 | 
							
 | 
				
			||||||
        return ('ondrop' in window && 'FormData' in window && 'FileReader' in window);
 | 
							"baseURL": baseURL,
 | 
				
			||||||
    }
 | 
							
 | 
				
			||||||
 | 
							"__preInit": [],
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		* initArea shows the contented upload widget over the top of a target DOM element.
 | 
							* initArea shows the contented upload widget over the top of a target DOM element.
 | 
				
			||||||
@@ -32,6 +51,82 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
		* @param Function   onUploaded    Called with an array of upload IDs
 | 
							* @param Function   onUploaded    Called with an array of upload IDs
 | 
				
			||||||
		* @param Function   onClose       Called when the widget is being destroyed
 | 
							* @param Function   onClose       Called when the widget is being destroyed
 | 
				
			||||||
		*/
 | 
							*/
 | 
				
			||||||
 | 
							"init": function(elementSelector, onUploaded, onClose) {
 | 
				
			||||||
 | 
								contented.__preInit.push([elementSelector, onUploaded, onClose]);
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							* supportsDrop returns whether drag-and-drop is supported by this browser.
 | 
				
			||||||
 | 
							*
 | 
				
			||||||
 | 
							* @return bool
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							"supportsDrop": function() {
 | 
				
			||||||
 | 
								return ('ondrop' in window && 'FormData' in window && 'FileReader' in window);
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							"getPreviewURL": function(id) {
 | 
				
			||||||
 | 
								return baseURL + "get/" + id; // n.b. there's no better preview URL yet
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"getDownloadURL": function(id) {
 | 
				
			||||||
 | 
								return baseURL + "get/" + id;
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"getInfoJSONURL": function(id) {
 | 
				
			||||||
 | 
								return baseURL + "info/" + id;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;(function() {
 | 
				
			||||||
 | 
						"use strict";
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						var loadScript = function(url, onLoad) {
 | 
				
			||||||
 | 
							var script = document.createElement('script');
 | 
				
			||||||
 | 
							script.onload = onLoad;
 | 
				
			||||||
 | 
							script.src = url;
 | 
				
			||||||
 | 
							document.head.appendChild(script);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						var loadScripts = function(urls, onLoad) {
 | 
				
			||||||
 | 
							// load sequentially
 | 
				
			||||||
 | 
							var i = 0;
 | 
				
			||||||
 | 
							var loadNext = function() {
 | 
				
			||||||
 | 
								if (i === urls.length) {
 | 
				
			||||||
 | 
									onLoad();
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var url = urls[i];
 | 
				
			||||||
 | 
								i += 1;
 | 
				
			||||||
 | 
								loadScript(url, loadNext);
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							loadNext();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					    var formatBytes = function(bytes) {
 | 
				
			||||||
 | 
							var k = 1024, m = (1024*1024), g = (1024*1024*1024);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					        if (bytes < k) {
 | 
				
			||||||
 | 
					            return bytes + " B";
 | 
				
			||||||
 | 
					        } else if (bytes < m) {
 | 
				
			||||||
 | 
					            return (bytes / k).toFixed(1) + " KiB";
 | 
				
			||||||
 | 
					        } else if (bytes < g) {
 | 
				
			||||||
 | 
					            return (bytes / m).toFixed(1) + " MiB";
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return (bytes / g).toFixed(1) + " GiB";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// @ref https://stackoverflow.com/a/2117523
 | 
				
			||||||
 | 
						var guid = function uuidv4() {
 | 
				
			||||||
 | 
							return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
 | 
				
			||||||
 | 
								var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
 | 
				
			||||||
 | 
								return v.toString(16);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var afterScriptsLoaded = function() {		
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var initArea = function (elementSelector, onUploaded, onClose) {
 | 
							var initArea = function (elementSelector, onUploaded, onClose) {
 | 
				
			||||||
			onUploaded = onUploaded || function () { };
 | 
								onUploaded = onUploaded || function () { };
 | 
				
			||||||
			onClose = onClose || function () { };
 | 
								onClose = onClose || function () { };
 | 
				
			||||||
@@ -44,44 +139,45 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
			// <input type="hidden" name="MAX_FILE_SIZE" value="` + ret.MaxUploadBytes + `" /> 
 | 
								// <input type="hidden" name="MAX_FILE_SIZE" value="` + ret.MaxUploadBytes + `" /> 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Create a new div for ourselves on top of the existing area
 | 
								// Create a new div for ourselves on top of the existing area
 | 
				
			||||||
        $.get(baseURL + "about", function (ret) {
 | 
								$.get(contented.baseURL + "about", function (ret) {
 | 
				
			||||||
				
 | 
									
 | 
				
			||||||
				var extraText = "";
 | 
									var extraText = "";
 | 
				
			||||||
				if (ret.MaxUploadBytes > 0) {
 | 
									if (ret.MaxUploadBytes > 0) {
 | 
				
			||||||
					extraText = " (max " + formatBytes(ret.MaxUploadBytes) + ")";
 | 
										extraText = " (max " + formatBytes(ret.MaxUploadBytes) + ")";
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $.get(baseURL + "widget.html", function (widgetHtml) {
 | 
									$.get(contented.baseURL + "widget.html", function (widgetHtml) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var $f = $("<div>").html(widgetHtml);
 | 
										var $f = $("<div>").html(widgetHtml);
 | 
				
			||||||
					$f.find(".contented-extratext").text(extraText);
 | 
										$f.find(".contented-extratext").text(extraText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var ourClose = function () {
 | 
										// Tab buttons
 | 
				
			||||||
                    $f.remove(); // remove from dom
 | 
					 | 
				
			||||||
                    onClose(); // upstream close
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                $f.find(".contented-close").click(function () {
 | 
					 | 
				
			||||||
                    ourClose();
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
 | 
										var hasSetupDrawingBoardYet = false;
 | 
				
			||||||
					var setType = function (type) {
 | 
										var setType = function (type) {
 | 
				
			||||||
						$f.find(".contented-upload-type").removeClass("contented-upload-type-active");
 | 
											$f.find(".contented-upload-type").removeClass("contented-upload-type-active");
 | 
				
			||||||
						$f.find(".contented-upload-type[data-upload-type=" + type + "]").addClass("contented-upload-type-active");
 | 
											$f.find(".contented-upload-type[data-upload-type=" + type + "]").addClass("contented-upload-type-active");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						$f.find(".contented-upload-if").removeClass("contented-active");
 | 
											$f.find(".contented-upload-if").removeClass("contented-active");
 | 
				
			||||||
						$f.find(".contented-if-" + type).addClass("contented-active");
 | 
											$f.find(".contented-if-" + type).addClass("contented-active");
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											if (type == "drag") {
 | 
				
			||||||
 | 
												enablePasteHandler();
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												disablePasteHandler();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											if (type == "drawing" && !hasSetupDrawingBoardYet) {
 | 
				
			||||||
 | 
												setupDrawingBoard();
 | 
				
			||||||
 | 
												hasSetupDrawingBoardYet = true;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					};
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					$f.find(".contented-upload-type").click(function () {
 | 
										$f.find(".contented-upload-type").click(function () {
 | 
				
			||||||
						setType($(this).attr('data-upload-type'));
 | 
											setType($(this).attr('data-upload-type'));
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!supportsDrop()) {
 | 
										// Widget positioning
 | 
				
			||||||
                    // switch default
 | 
					 | 
				
			||||||
                    setType('file');
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                //
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var $element = $(element);
 | 
										var $element = $(element);
 | 
				
			||||||
					var offset = $element.offset();
 | 
										var offset = $element.offset();
 | 
				
			||||||
@@ -98,6 +194,8 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
						'max-height': $element.height() + "px"
 | 
											'max-height': $element.height() + "px"
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Drag and drop support
 | 
				
			||||||
 | 
										
 | 
				
			||||||
					$f.find('.contented').on('dragover dragenter', function (e) {
 | 
										$f.find('.contented').on('dragover dragenter', function (e) {
 | 
				
			||||||
						e.preventDefault();
 | 
											e.preventDefault();
 | 
				
			||||||
						e.stopPropagation();
 | 
											e.stopPropagation();
 | 
				
			||||||
@@ -122,6 +220,8 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
						handleUploadFrom($(".contented-file-selector")[0].files);
 | 
											handleUploadFrom($(".contented-file-selector")[0].files);
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Pastebin
 | 
				
			||||||
 | 
										
 | 
				
			||||||
					$f.find('.contented-paste-upload').on('click', function(e) {
 | 
										$f.find('.contented-paste-upload').on('click', function(e) {
 | 
				
			||||||
						e.preventDefault();
 | 
											e.preventDefault();
 | 
				
			||||||
						e.stopPropagation();
 | 
											e.stopPropagation();
 | 
				
			||||||
@@ -129,7 +229,132 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
						handleUploadFrom([blob]);
 | 
											handleUploadFrom([blob]);
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Ctrl+V uploads
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										var pasteHandler = function(e) {
 | 
				
			||||||
 | 
											e.preventDefault();
 | 
				
			||||||
 | 
											e.stopPropagation();
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											var items = (e.clipboardData || e.originalEvent.clipboardData).items;
 | 
				
			||||||
 | 
											var items_length = items.length;
 | 
				
			||||||
 | 
											var blobs = [];
 | 
				
			||||||
 | 
											var handled = 0;
 | 
				
			||||||
 | 
											var haveHandled = function() {
 | 
				
			||||||
 | 
												handled += 1;
 | 
				
			||||||
 | 
												if (handled == items_length) {
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
													if (blobs.length > 0) {
 | 
				
			||||||
 | 
														handleUploadFrom( blobs );
 | 
				
			||||||
 | 
													} else {
 | 
				
			||||||
 | 
														// alert("Pasted 0 files");
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											for (var i = 0; i < items.length; ++i) {
 | 
				
			||||||
 | 
												var item = items[i];
 | 
				
			||||||
 | 
												var mimeType = item.type;
 | 
				
			||||||
 | 
												if (item.kind === 'file') {
 | 
				
			||||||
 | 
													blobs.push(item.getAsFile());
 | 
				
			||||||
 | 
													haveHandled();
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
												} else if (item.kind === 'string') {
 | 
				
			||||||
 | 
													item.getAsString(function(s) {
 | 
				
			||||||
 | 
														blobs.push( new Blob([s], {type : mimeType}) );
 | 
				
			||||||
 | 
														haveHandled();
 | 
				
			||||||
 | 
													});
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
												} else {
 | 
				
			||||||
 | 
													// file|string are the only supported types in
 | 
				
			||||||
 | 
													// all browsers at the time of writing
 | 
				
			||||||
 | 
													// Ignore future possibilities
 | 
				
			||||||
 | 
													haveHandled();
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										var enablePasteHandler = function() {
 | 
				
			||||||
 | 
											document.addEventListener('paste', pasteHandler);
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										var disablePasteHandler = function() {
 | 
				
			||||||
 | 
											document.removeEventListener('paste', pasteHandler);
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										// Embed in DOM, load default area
 | 
				
			||||||
 | 
										
 | 
				
			||||||
					$("body").append($f);
 | 
										$("body").append($f);
 | 
				
			||||||
 | 
										if (!contented.supportsDrop()) {
 | 
				
			||||||
 | 
											setType('file');
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											setType('drag');
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										// Drawing board
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										var setupDrawingBoard = function() {
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											$("head").append(
 | 
				
			||||||
 | 
												'<link rel="stylesheet" type="text/css" href="' + contented.baseURL + 'drawingboard-0.4.6.min.css">'
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											var db_id = "contented-drawing-area-" + guid();
 | 
				
			||||||
 | 
											var $db = $("<div>").attr('id', db_id);
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											DrawingBoard.Control.ContentedUpload = DrawingBoard.Control.extend({
 | 
				
			||||||
 | 
												name: 'upload',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												initialize: function() {
 | 
				
			||||||
 | 
													var $el = this.$el;
 | 
				
			||||||
 | 
													
 | 
				
			||||||
 | 
													$el.append('<button class="contented-drawingboard-upload">Upload</button>');
 | 
				
			||||||
 | 
													$el.on('click', '.contented-drawingboard-upload', $.proxy(function(e) {
 | 
				
			||||||
 | 
														e.preventDefault();
 | 
				
			||||||
 | 
														e.stopPropagation();
 | 
				
			||||||
 | 
														
 | 
				
			||||||
 | 
														$el.prop('disabled', true);
 | 
				
			||||||
 | 
														$el.text('Saving...');
 | 
				
			||||||
 | 
														
 | 
				
			||||||
 | 
														$db.find("canvas")[0].toBlob(function(theBlob) {
 | 
				
			||||||
 | 
															handleUploadFrom([ theBlob ]);
 | 
				
			||||||
 | 
														});
 | 
				
			||||||
 | 
													}, this));
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											$db.css({
 | 
				
			||||||
 | 
												//'width': $f.find(".contented-content-area").width(),
 | 
				
			||||||
 | 
												'height': $f.find(".contented-content-area").height(),
 | 
				
			||||||
 | 
												'overflow': 'hidden'
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
											$f.find(".contented-drawing-area").append($db);
 | 
				
			||||||
 | 
											var db = new DrawingBoard.Board(db_id, {
 | 
				
			||||||
 | 
												'controls': [
 | 
				
			||||||
 | 
													'Color',
 | 
				
			||||||
 | 
													'Size',
 | 
				
			||||||
 | 
													'DrawingMode',
 | 
				
			||||||
 | 
													'Navigation',
 | 
				
			||||||
 | 
													'ContentedUpload'
 | 
				
			||||||
 | 
												],
 | 
				
			||||||
 | 
												'controlsPosition': 'center',
 | 
				
			||||||
 | 
												'enlargeYourContainer': false,
 | 
				
			||||||
 | 
												'webStorage': false,
 | 
				
			||||||
 | 
												'droppable': false // don't mess with existing drop support
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
 | 
											
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Close button
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
										var ourClose = function () {
 | 
				
			||||||
 | 
											$f.remove(); // remove from dom
 | 
				
			||||||
 | 
											disablePasteHandler();
 | 
				
			||||||
 | 
											onClose(); // upstream close
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										$f.find(".contented-close").click(function () {
 | 
				
			||||||
 | 
											ourClose();
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Progress bar
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
					var setProgressCaption = function(message) {
 | 
										var setProgressCaption = function(message) {
 | 
				
			||||||
						$f.find(".contented-if-progress label").text(message);
 | 
											$f.find(".contented-if-progress label").text(message);
 | 
				
			||||||
@@ -138,6 +363,8 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
						$f.find(".contented-progress-element").css('width', (frc * 100) + "%");
 | 
											$f.find(".contented-progress-element").css('width', (frc * 100) + "%");
 | 
				
			||||||
					};
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Common upload handler
 | 
				
			||||||
 | 
										
 | 
				
			||||||
					var handleUploadFrom = function(files) {
 | 
										var handleUploadFrom = function(files) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						setProgressCaption("Uploading, please wait...");
 | 
											setProgressCaption("Uploading, please wait...");
 | 
				
			||||||
@@ -155,7 +382,7 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
						// ajax request
 | 
											// ajax request
 | 
				
			||||||
						$.ajax({
 | 
											$.ajax({
 | 
				
			||||||
                        url: baseURL + "upload",
 | 
												url: contented.baseURL + "upload",
 | 
				
			||||||
							type: "POST",
 | 
												type: "POST",
 | 
				
			||||||
							data: ajaxData,
 | 
												data: ajaxData,
 | 
				
			||||||
							dataType: 'json', // response type
 | 
												dataType: 'json', // response type
 | 
				
			||||||
@@ -167,7 +394,6 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
								xhr.upload.addEventListener(
 | 
													xhr.upload.addEventListener(
 | 
				
			||||||
									'progress',
 | 
														'progress',
 | 
				
			||||||
									function(ev) {
 | 
														function(ev) {
 | 
				
			||||||
                                    console.log([ev.lengthComputable, ev.loaded, ev.total]);
 | 
					 | 
				
			||||||
										if (ev.lengthComputable) {
 | 
															if (ev.lengthComputable) {
 | 
				
			||||||
											setProgressCaption("Uploading (" + formatBytes(ev.loaded) + " / " + formatBytes(ev.total) + ")...");
 | 
																setProgressCaption("Uploading (" + formatBytes(ev.loaded) + " / " + formatBytes(ev.total) + ")...");
 | 
				
			||||||
											setProgressPercentage(ev.total == 0 ? 0 : ev.loaded / ev.total);
 | 
																setProgressPercentage(ev.total == 0 ? 0 : ev.loaded / ev.total);
 | 
				
			||||||
@@ -178,44 +404,47 @@ var contented = (function ($, currentScriptPath) {
 | 
				
			|||||||
								return xhr;
 | 
													return xhr;
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
							complete: function () {
 | 
												complete: function () {
 | 
				
			||||||
                            setProgressCaption("Upload complete.");
 | 
					 | 
				
			||||||
								setProgressPercentage(1);
 | 
													setProgressPercentage(1);
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
							success: function (data) {
 | 
												success: function (data) {
 | 
				
			||||||
 | 
													setProgressCaption("Upload completed successfully.");
 | 
				
			||||||
								onUploaded(data);
 | 
													onUploaded(data);
 | 
				
			||||||
								ourClose();
 | 
													ourClose();
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
							error: function () {
 | 
												error: function () {
 | 
				
			||||||
                            setProgressCaption("Upload failed.");
 | 
													setProgressCaption("Upload failed!");
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
 | 
										// .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
    //
 | 
							// Update fields in global variable
 | 
				
			||||||
    return {
 | 
							contented.init = initArea;
 | 
				
			||||||
        'supportsDrop': supportsDrop,
 | 
							contented.loaded = true;
 | 
				
			||||||
        'init': initArea
 | 
							
 | 
				
			||||||
 | 
							// Call initArea for all pre-initialised elements
 | 
				
			||||||
 | 
							for (var i = 0; i < contented.__preInit.length; ++i) {
 | 
				
			||||||
 | 
								initArea(contented.__preInit[i][0], contented.__preInit[i][1], contented.__preInit[i][2]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
})(
 | 
						// Load scripts
 | 
				
			||||||
    jQuery,
 | 
						var needScripts = [];
 | 
				
			||||||
    (function () {
 | 
						if (typeof jQuery === "undefined") {
 | 
				
			||||||
        "use strict";
 | 
							needScripts.push(contented.baseURL + "jquery-1.12.4.min.js");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (typeof DrawingBoard === "undefined") {
 | 
				
			||||||
 | 
							needScripts.push(contented.baseURL + "drawingboard-0.4.6.min.js");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        // Determine current script path
 | 
						loadScripts(needScripts, afterScriptsLoaded);
 | 
				
			||||||
        // @ref https://stackoverflow.com/a/26023176
 | 
					 | 
				
			||||||
        var scripts = document.querySelectorAll('script[src]');
 | 
					 | 
				
			||||||
        var currentScript = scripts[scripts.length - 1].src;
 | 
					 | 
				
			||||||
        var currentScriptChunks = currentScript.split('/');
 | 
					 | 
				
			||||||
        var currentScriptFile = currentScriptChunks[currentScriptChunks.length - 1];
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        return currentScript.replace(currentScriptFile, '');
 | 
					 | 
				
			||||||
})()
 | 
					})()
 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
.contented .contented-upload-type-selector {
 | 
					.contented .contented-upload-type-selector {
 | 
				
			||||||
    display:block;
 | 
					    display:block;
 | 
				
			||||||
    margin-bottom: 1em;
 | 
					    margin-bottom: 1em;
 | 
				
			||||||
 | 
					    -webkit-user-select: none;
 | 
				
			||||||
    user-select: none; 
 | 
					    user-select: none; 
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.contented .contented-upload-type {
 | 
					.contented .contented-upload-type {
 | 
				
			||||||
@@ -66,7 +67,7 @@
 | 
				
			|||||||
.contented-upload-if {
 | 
					.contented-upload-if {
 | 
				
			||||||
    display:none;
 | 
					    display:none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.contented-if-paste {
 | 
					.contented-if-paste, .contented-if-drawing {
 | 
				
			||||||
    height:100%;
 | 
					    height:100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.contented-upload-if.contented-active {
 | 
					.contented-upload-if.contented-active {
 | 
				
			||||||
@@ -87,12 +88,14 @@
 | 
				
			|||||||
    border-radius:8px;
 | 
					    border-radius:8px;
 | 
				
			||||||
    background:lightgrey;
 | 
					    background:lightgrey;
 | 
				
			||||||
    position:relative;
 | 
					    position:relative;
 | 
				
			||||||
 | 
					    overflow:hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.contented-progress-element {
 | 
					.contented-progress-element {
 | 
				
			||||||
    position:absolute;
 | 
					    position:absolute;
 | 
				
			||||||
    background:darkgreen;
 | 
					    background:darkgreen;
 | 
				
			||||||
    left:0;
 | 
					    left:0;
 | 
				
			||||||
    width:0%;
 | 
					    width:0%;
 | 
				
			||||||
 | 
					    height:100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
<div class="contented">
 | 
					<div class="contented">
 | 
				
			||||||
@@ -122,11 +125,17 @@
 | 
				
			|||||||
                <path fill="#000000" d="M19,20H5V4H7V7H17V4H19M12,2A1,1 0 0,1 13,3A1,1 0 0,1 12,4A1,1 0 0,1 11,3A1,1 0 0,1 12,2M19,2H14.82C14.4,0.84 13.3,0 12,0C10.7,0 9.6,0.84 9.18,2H5A2,2 0 0,0 3,4V20A2,2 0 0,0 5,22H19A2,2 0 0,0 21,20V4A2,2 0 0,0 19,2Z" />
 | 
					                <path fill="#000000" d="M19,20H5V4H7V7H17V4H19M12,2A1,1 0 0,1 13,3A1,1 0 0,1 12,4A1,1 0 0,1 11,3A1,1 0 0,1 12,2M19,2H14.82C14.4,0.84 13.3,0 12,0C10.7,0 9.6,0.84 9.18,2H5A2,2 0 0,0 3,4V20A2,2 0 0,0 5,22H19A2,2 0 0,0 21,20V4A2,2 0 0,0 19,2Z" />
 | 
				
			||||||
            </svg>
 | 
					            </svg>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        <div class="contented-upload-type" data-upload-type="drawing" title="Drawing">
 | 
				
			||||||
 | 
								<svg viewBox="0 0 24 24">
 | 
				
			||||||
 | 
									<path fill="#000000" d="M16.84,2.73C16.45,2.73 16.07,2.88 15.77,3.17L13.65,5.29L18.95,10.6L21.07,8.5C21.67,7.89 21.67,6.94 21.07,6.36L17.9,3.17C17.6,2.88 17.22,2.73 16.84,2.73M12.94,6L4.84,14.11L7.4,14.39L7.58,16.68L9.86,16.85L10.15,19.41L18.25,11.3M4.25,15.04L2.5,21.73L9.2,19.94L8.96,17.78L6.65,17.61L6.47,15.29" />
 | 
				
			||||||
 | 
								</svg>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <div class="contented-content-area">
 | 
					    <div class="contented-content-area">
 | 
				
			||||||
        <div class="contented-upload-if contented-if-drag contented-active">
 | 
					        <div class="contented-upload-if contented-if-drag contented-active">
 | 
				
			||||||
            <label>Drop files to upload <span class="contented-extratext"></span></label>
 | 
					            <label>Drop files or Ctrl-V to upload <span class="contented-extratext"></span></label>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="contented-upload-if contented-if-file">
 | 
					        <div class="contented-upload-if contented-if-file">
 | 
				
			||||||
@@ -140,6 +149,10 @@
 | 
				
			|||||||
            <button class="contented-paste-upload">Upload »</button>
 | 
					            <button class="contented-paste-upload">Upload »</button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="contented-upload-if contented-if-drawing">
 | 
				
			||||||
 | 
								<div class="contented-drawing-area"></div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        <div class="contented-upload-if contented-if-progress">
 | 
					        <div class="contented-upload-if contented-if-progress">
 | 
				
			||||||
            <label>...</label>
 | 
					            <label>...</label>
 | 
				
			||||||
            <div class="contented-progress-bar"><div class="contented-progress-element"></div></div>
 | 
					            <div class="contented-progress-bar"><div class="contented-progress-element"></div></div>
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										14
									
								
								upload.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								upload.go
									
									
									
									
									
								
							@@ -18,15 +18,17 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (this *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
 | 
					func (this *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						remoteIP := this.remoteIP(r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := r.ParseMultipartForm(this.opts.MaxUploadBytes * 2)
 | 
						err := r.ParseMultipartForm(this.opts.MaxUploadBytes * 2)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("%s Invalid request: %s\n", r.RemoteAddr, err.Error())
 | 
							log.Printf("%s Invalid request: %s\n", remoteIP, err.Error())
 | 
				
			||||||
		http.Error(w, "Invalid request", 400)
 | 
							http.Error(w, "Invalid request", 400)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if r.MultipartForm == nil || r.MultipartForm.File == nil || len(r.MultipartForm.File["f"]) < 1 {
 | 
						if r.MultipartForm == nil || r.MultipartForm.File == nil || len(r.MultipartForm.File["f"]) < 1 {
 | 
				
			||||||
		log.Printf("%s Invalid request: no multipart content\n", r.RemoteAddr)
 | 
							log.Printf("%s Invalid request: no multipart content\n", remoteIP)
 | 
				
			||||||
		http.Error(w, "Invalid request", 400)
 | 
							http.Error(w, "Invalid request", 400)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -36,14 +38,14 @@ func (this *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	for _, fhs := range r.MultipartForm.File["f"] {
 | 
						for _, fhs := range r.MultipartForm.File["f"] {
 | 
				
			||||||
		f, err := fhs.Open()
 | 
							f, err := fhs.Open()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("%s Internal error: %s\n", r.RemoteAddr, err.Error())
 | 
								log.Printf("%s Internal error: %s\n", remoteIP, err.Error())
 | 
				
			||||||
			http.Error(w, "Internal error", 500)
 | 
								http.Error(w, "Internal error", 500)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		path, err := this.handleUploadFile(f, fhs, remoteIP(r))
 | 
							path, err := this.handleUploadFile(f, fhs, remoteIP)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Printf("%s Upload failed: %s\n", r.RemoteAddr, err.Error())
 | 
								log.Printf("%s Upload failed: %s\n", remoteIP, err.Error())
 | 
				
			||||||
			http.Error(w, "Upload failed", 500)
 | 
								http.Error(w, "Upload failed", 500)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,7 +54,7 @@ func (this *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	jb, err := json.Marshal(ret)
 | 
						jb, err := json.Marshal(ret)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Printf("%s Internal error: %s\n", r.RemoteAddr, err.Error())
 | 
							log.Printf("%s Internal error: %s\n", remoteIP, err.Error())
 | 
				
			||||||
		http.Error(w, "Internal error", 500)
 | 
							http.Error(w, "Internal error", 500)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user