├── .gitignore ├── README.md ├── app.js ├── bower.json ├── config.example.js ├── front ├── js │ ├── manager.js │ └── uploader.js └── scss │ ├── base.scss │ ├── home.scss │ ├── index.scss │ └── reset.scss ├── gulpfile.js ├── lib └── genToken.js ├── package.json └── public ├── css └── index.css ├── index.html └── js ├── lib └── zepto.min.js ├── manager.js └── uploader.js /.gitignore: -------------------------------------------------------------------------------- 1 | config.js 2 | node_modules 3 | bower_components 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 小巧的前端七牛上传工具 2 | ---------------------- 3 | 4 | 介绍 5 | ---- 6 | `不依赖任何第三方库` 7 | 8 | 9 | 如何使用 10 | --------- 11 | **客户端** 12 | ```javascript 13 | var options = { 14 | //must 15 | domain: '七牛分配给你的域名', 16 | 17 | //must 18 | tokenUrl: '你的服务器上获取uptoken的访问地址', 19 | maxImgSize: '最大图片大小', //option 20 | 21 | // option , 比如: 'font-qn-uper/'. 访问地址就是:http:domain/prefix/filename 22 | prefix: '自定义的路径', 23 | 24 | //option, 默认5000ms 25 | timeout: '请求超时时间' , 26 | 27 | //option, 默认480px 28 | maxMobileWidth: '在手机上最大显示宽度', 29 | 30 | //option, 默认960px 31 | maxPcWidth: '在pc端最大显示宽度', 32 | 33 | //option, 格式比如: "jpg, png, jpeg" 34 | imageType: "文件类型" 35 | } 36 | var ins = new fontQnUper(options); 37 | $('#upload').on('change', function() { 38 | var file = this.files[0]; 39 | 40 | // 错误捕捉 41 | ins.errHandle = function(e) { 42 | console.log(e); 43 | } 44 | 45 | ins.post(file, function(result) { 46 | /*result datas 47 | { 48 | hash: "", 49 | key: "", 50 | fullImageUrl: "完整的上传图片", 51 | mobileImageUrl:"手机上显示的图片", 52 | pcImageUrl:"pc端显示的图片" 53 | } 54 | */ 55 | }); 56 | // 上传进度, total: 一共上传的数据, loaded: 已经上传的数据(bytes) 57 | ins.progress = function(total,loaded){ 58 | //do something 59 | } 60 | }); 61 | ``` 62 | 63 | 案例 64 | ==== 65 | 66 | 我自己的基于`Ghost`的博客系统的前端上传图片 67 | https://github.com/DgTechOrg/Customize-Ghost 68 | 69 | **配置文件说明** 70 | 71 | > 三个参数, 分别是: `BUCKET_NAME`, `ACCESS_KEY`, `SECRET_KEY` 72 | 就是你定义的空间以及七牛提供给你的访问秘钥 73 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const url = require('url'); 5 | const express = require('express'); 6 | const app = express(); 7 | const config = require('./config'); 8 | const path = require('path'); 9 | const genToken = require('./lib/genToken'); 10 | 11 | app.use(express.static(path.join(__dirname, 'public'))); 12 | // app.get('/', function(req, res) { 13 | 14 | // }); 15 | 16 | app.get('/token', function(req, res) { 17 | res.writeHead(200, { 18 | 'Content-Type':'text/json', 19 | 'Expires': 0, 20 | 'Pragma': 'no-cache' 21 | }); 22 | var retJson = { 23 | uptoken: genToken() 24 | } 25 | res.end(JSON.stringify(retJson)); 26 | }); 27 | 28 | http.createServer(app).listen(config.port, function() { 29 | console.log('server run at: ', config.port); 30 | }); 31 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-qn-uper", 3 | "version": "1.0.1", 4 | "homepage": "https://github.com/struCoder/front-qn-uper", 5 | "description": "", 6 | "main": "", 7 | "moduleType": [], 8 | "license": "MIT", 9 | "private": true, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /config.example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | port: 9002, 5 | ACCESS_KEY: "your qiniu ACCESS_KEY", 6 | SECRET_KEY: 'your qiniu SECRET_KEY', 7 | BUCKET_NAME: 'your qiniu BUCKET_NAME' 8 | } 9 | -------------------------------------------------------------------------------- /front/js/manager.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var $fileBtn = $('#file-btn'); 3 | var $show = $('#result-show'); 4 | 5 | var options = { 6 | domain: 'http://7xjbiz.com1.z0.glb.clouddn.com', 7 | tokenUrl: '/token', 8 | prefix: 'temp/' 9 | } 10 | 11 | var ins = new frontQnUper(options); 12 | $('#upload').on('change', function() { 13 | ins.prefix = $('#prefix').val() || 'temp/'; 14 | var file = this.files[0]; 15 | //process 16 | ins.progress = function(total, loaded) { 17 | $fileBtn.val('上传进度: ' + (loaded / total).toFixed(0) * 100 + '%'); 18 | if (loaded === total) { 19 | $fileBtn.val('请稍等...'); 20 | } 21 | } 22 | ins.errHandle = function(e) { 23 | alert(e) 24 | } 25 | 26 | ins.post(file, function(result) { 27 | var resultDOM = []; 28 | 29 | for(var i in result) { 30 | resultDOM.push([ 31 | '
', 32 | '', 33 | result[i], 34 | '', 35 | '
' 36 | ].join('')) 37 | } 38 | $show.append(resultDOM.join('')); 39 | setTimeout(function() { 40 | $fileBtn.val('上传图片'); 41 | }, 1500); 42 | }); 43 | }) 44 | })(); 45 | -------------------------------------------------------------------------------- /front/js/uploader.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var STR_RAND = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 3 | var DEFAULT_IMG = ['jpg', 'jpeg', 'gif', 'png', 'bmp']; 4 | var DEFAULT_SIZE = 10 * 1024; // 10MB 5 | 6 | var genRand = function(len) { 7 | len = len || 16; 8 | var resultStr = ''; 9 | var length = STR_RAND.length; 10 | var random = null; 11 | for (var i = 0; i < len; i++) { 12 | random = Math.floor(Math.random() * length); 13 | resultStr += STR_RAND.substring(random - 1, random); 14 | } 15 | return resultStr; 16 | } 17 | 18 | var createAjax = function() { 19 | var xmlhttp = {}; 20 | if (window.XMLHttpRequest) { 21 | xmlhttp = new XMLHttpRequest(); 22 | } else { 23 | xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 24 | } 25 | xmlhttp.timeout = this.timeout; 26 | return xmlhttp; 27 | } 28 | 29 | var request = function(options, cb) { 30 | var self = this; 31 | var xhr = createAjax(); 32 | xhr.open(options.method, options.url, true); 33 | xhr.onload = function() { 34 | if (xhr.status === 200) { 35 | try { 36 | var jsonResult = JSON.parse(xhr.responseText); 37 | } catch (e) { 38 | e.msg = 'parse text to json error'; 39 | cb(e); 40 | } 41 | cb(null, jsonResult); 42 | } 43 | } 44 | 45 | xhr.ontimeout = function() { 46 | cb('timeout'); 47 | } 48 | 49 | xhr.onerror = function(e) { 50 | e.msg = 'network error not frontQnUper self error'; 51 | cb(e); 52 | } 53 | if (options.onProgress) { 54 | xhr.upload.onprogress = function(e) { 55 | self.progress(e.total, e.loaded); 56 | } 57 | } 58 | xhr.send(options.method === 'POST' ? options.data : null); 59 | } 60 | 61 | var qnUpload = function(options) { 62 | if (Object.prototype.toString.call(options) !== '[object Object]') { 63 | throw new Error('options must be Object') 64 | } 65 | if (options.imageType) { 66 | this.imageTypeArr = options.imageType.split(','); 67 | } else { 68 | this.imageTypeArr = DEFAULT_IMG; 69 | } 70 | 71 | this.domain = options.domain; //must 72 | this.url = options.tokenUrl; // must 73 | this.prefix = options.prefix || 'font-qn-uper/'; 74 | this.timeout = options.timeout || 5000; // By default 5000ms 75 | this.maxMobileWidth = options.maxWidth || 480; 76 | this.maxPcWidth = options.maxPcWidth || 960; 77 | this.defaultSize = parseInt(options.maxImgSize, 10) || 10 * 1024; 78 | this.uploadUrl = 'http://upload.qiniu.com/?token='; 79 | // this._getToken() 80 | } 81 | 82 | qnUpload.prototype.checkType = function(cb) { 83 | var errInfo; 84 | var fileName = this.file.name; 85 | var fileSize = this.file.size / 1024; 86 | var imgExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase(); 87 | if (this.imageTypeArr.indexOf(imgExt) === -1) { 88 | errInfo = '图片格式为下面的一种: ' + this.imageTypeArr.toString(); 89 | cb(errInfo); 90 | } else if (fileSize > this.defaultSize) { 91 | errInfo = '图片大小因控制在' + this.defaultSize + ' 内'; 92 | cb(errInfo); 93 | } else { 94 | cb(); 95 | } 96 | }; 97 | 98 | qnUpload.prototype._getToken = function(cb) { 99 | var self = this; 100 | var options = { 101 | method: 'GET', 102 | url: this.url 103 | } 104 | if (typeof cb === 'function') { 105 | request(options, cb); 106 | } else { 107 | throw new Error('when get uptoken the cb must be Function'); 108 | } 109 | } 110 | 111 | qnUpload.prototype._postPrepare = function(cb) { 112 | var self = this; 113 | this.checkType(function(err) { 114 | if (err && typeof self.errHandle === 'function') { 115 | return self.errHandle(err); 116 | } 117 | self._getToken(function(err, tokenInfo) { 118 | if (err && typeof self.errHandle === 'function') { 119 | return self.errHandle(e); 120 | } 121 | self.token = tokenInfo; 122 | if (typeof cb === 'function') { 123 | cb(); 124 | } 125 | }); 126 | }); 127 | } 128 | 129 | qnUpload.prototype.post = function(file, cb) { 130 | this.file = file; 131 | var self = this; 132 | var randName = genRand(); 133 | this._postPrepare(function() { 134 | var data = new FormData(); 135 | data.append('file', file); 136 | data.append('key', self.prefix + randName); 137 | var postUrl = self.uploadUrl + self.token.uptoken + '&rand=' + Math.random(); // avoid cache 138 | var options = { 139 | method: 'POST', 140 | url: postUrl, 141 | onProgress: true, 142 | data: data 143 | } 144 | request.call(self, options, function(err, returnObj) { 145 | if (err && typeof errHandle === 'function') { 146 | return errHandle(err); 147 | } 148 | var imageUrlInfo = {}; 149 | imageUrlInfo.fullImageUrl = self.domain + '/' + returnObj.key; 150 | imageUrlInfo.mobileImageUrl = self.domain + '/' + returnObj.key + '?imageView2/0/w/' + self.maxMobileWidth 151 | imageUrlInfo.pcImageUrl = self.domain + '/' + returnObj.key + '?imageView2/2/w/' + self.maxPcWidth; 152 | cb(imageUrlInfo); 153 | }); 154 | }); 155 | } 156 | window.frontQnUper = qnUpload; 157 | })(); 158 | -------------------------------------------------------------------------------- /front/scss/base.scss: -------------------------------------------------------------------------------- 1 | input[type="text"], input[type="button"], input[type="file"] { 2 | font-weight: 400; 3 | width: 100%; 4 | font-size: 14px; 5 | padding: .75rem 0; 6 | line-height: inherit; 7 | border-radius: 0; 8 | text-indent: 8px; 9 | outline: none; 10 | border: 1px solid #41A6EF; 11 | } 12 | 13 | input[type="button"] { 14 | background-color: #41A6EF; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /front/scss/home.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 80%; 3 | height: auto; 4 | margin: 0 auto; 5 | margin-top: 10%; 6 | border: 4px dashed #aaa; 7 | padding: 20px; 8 | 9 | .margin-auto { 10 | position: relative; 11 | width: 95%; 12 | margin: 0 auto; 13 | } 14 | .upload-input { 15 | width: 50%; 16 | input { 17 | margin-bottom: 30px; 18 | } 19 | .select-prefix { 20 | input { 21 | display: inline-block; 22 | } 23 | .prefix-btn { 24 | width: 28%; 25 | color: #fff; 26 | } 27 | } 28 | // .upload-group { 29 | // opacity: 0; 30 | // &.show { 31 | // opacity: 1; 32 | // } 33 | // } 34 | .file { 35 | opacity: 0; 36 | z-index: 100; 37 | cursor: pointer; 38 | } 39 | .file-btn { 40 | position: absolute; 41 | top: 74px; 42 | z-index: -1; 43 | color: #fff; 44 | } 45 | } 46 | 47 | .result { 48 | .pic-url { 49 | padding: 4px; 50 | margin-bottom: 1px; 51 | border: 1px solid rgba(65, 166, 239, 0.48); 52 | width: 100%; 53 | height: auto; 54 | word-break: break-all; 55 | word-wrap: break-word; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /front/scss/index.scss: -------------------------------------------------------------------------------- 1 | @import 'reset'; 2 | @import 'base'; 3 | @import 'home'; 4 | -------------------------------------------------------------------------------- /front/scss/reset.scss: -------------------------------------------------------------------------------- 1 | html, body { margin: 0; padding: 0; } 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, cite, code, del, dfn, em, img, q, s, samp, small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: normal;font-style: normal; font-size: 100%; /*line-height: 1;*/ font-family: inherit; } 3 | table { border-collapse: collapse; border-spacing: 0;} 4 | //ol, ul { list-style: none; } 5 | q:before, q:after, blockquote:before, blockquote:after { content: ""; } 6 | //sd 7 | 8 | // Normalize.css 9 | // Pulling in select resets form the normalize.css project 10 | // -------------------------------------------------- 11 | 12 | // Display in IE6-9 and FF3 13 | // ------------------------- 14 | // Source: http://github.com/necolas/normalize.css 15 | html { 16 | font-size: 100%; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | } 20 | // Focus states 21 | a:focus { 22 | outline: thin dotted; 23 | } 24 | // Hover & Active 25 | a:hover, 26 | a:active { 27 | outline: 0; 28 | } 29 | 30 | // Display in IE6-9 and FF3 31 | // ------------------------- 32 | // Source: http://github.com/necolas/normalize.css 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | nav, 42 | section { 43 | display: block; 44 | } 45 | 46 | // Display block in IE6-9 and FF3 47 | // ------------------------- 48 | // Source: http://github.com/necolas/normalize.css 49 | audio, 50 | canvas, 51 | video { 52 | display: inline-block; 53 | *display: inline; 54 | *zoom: 1; 55 | } 56 | 57 | // Prevents modern browsers from displaying 'audio' without controls 58 | // ------------------------- 59 | // Source: http://github.com/necolas/normalize.css 60 | audio:not([controls]) { 61 | display: none; 62 | } 63 | 64 | // Prevents sub and sup affecting line-height in all browsers 65 | // ------------------------- 66 | // Source: http://github.com/necolas/normalize.css 67 | sub, 68 | sup { 69 | font-size: 75%; 70 | line-height: 0; 71 | position: relative; 72 | vertical-align: baseline; 73 | } 74 | sup { 75 | top: -0.5em; 76 | } 77 | sub { 78 | bottom: -0.25em; 79 | } 80 | 81 | // Img border in a's and image quality 82 | // ------------------------- 83 | // Source: http://github.com/necolas/normalize.css 84 | img { 85 | border: 0; 86 | -ms-interpolation-mode: bicubic; 87 | } 88 | 89 | // Forms 90 | // ------------------------- 91 | // Source: http://github.com/necolas/normalize.css 92 | 93 | // Font size in all browsers, margin changes, misc consistency 94 | button, 95 | input, 96 | select, 97 | textarea { 98 | padding: 0; 99 | font-size: 100%; 100 | margin: 0; 101 | vertical-align: baseline; 102 | *vertical-align: middle; 103 | } 104 | button, 105 | input { 106 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet 107 | *overflow: visible; // Inner spacing ie IE6/7 108 | } 109 | button::-moz-focus-inner, 110 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 111 | border: 0; 112 | padding: 0; 113 | } 114 | button, 115 | input[type="button"], 116 | input[type="reset"], 117 | input[type="submit"] { 118 | cursor: pointer; // Cursors on all buttons applied consistently 119 | -webkit-appearance: button; // Style clicable inputs in iOS 120 | } 121 | input[type="search"] { // Appearance in Safari/Chrome 122 | -webkit-appearance: textfield; 123 | -webkit-box-sizing: content-box; 124 | -moz-box-sizing: content-box; 125 | box-sizing: content-box; 126 | } 127 | input[type="search"]::-webkit-search-decoration { 128 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 129 | } 130 | textarea { 131 | overflow: auto; // Remove vertical scrollbar in IE6-9 132 | vertical-align: top; // Readability and alignment cross-browser 133 | } 134 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const changed = require('gulp-changed'); 3 | const uglify = require('gulp-uglify'); 4 | const sass = require('gulp-sass'); 5 | 6 | 7 | gulp.task('copy-js', function() { 8 | return gulp.src('./front/js/*.js') 9 | .pipe(uglify()) 10 | .pipe(gulp.dest('./public/js')) 11 | }) 12 | gulp.task('copy-zepto', function() { 13 | return gulp.src('./bower_components/zepto/zepto.min.js') 14 | .pipe(changed('./public/js/lib')) 15 | .pipe(gulp.dest('./public/js/lib')) 16 | }); 17 | 18 | gulp.task('sass', function() { 19 | return gulp.src('./front/scss/index.scss') 20 | .pipe(sass.sync()) 21 | .pipe(gulp.dest('./public/css')) 22 | }); 23 | 24 | gulp.task('watch-js', function() { 25 | return gulp.watch('./front/js/*.js', ['copy-js']); 26 | }); 27 | 28 | gulp.task('watch-sass', function() { 29 | return gulp.watch('./front/scss/*.scss', ['sass']); 30 | }); 31 | 32 | gulp.task('watch', ['watch-sass', 'watch-js']); 33 | 34 | gulp.task('copy', ['copy-zepto', 'copy-js']); 35 | 36 | 37 | gulp.task('default', ['copy', 'sass', 'watch']); 38 | 39 | gulp.task('pro', ['copy', 'sass']); 40 | -------------------------------------------------------------------------------- /lib/genToken.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('crypto'); 4 | const config = require('../config'); 5 | 6 | function getFlags() { 7 | //对这个方法只做简单上传到bucket就好 8 | var returnObj = { 9 | scope: config.BUCKET_NAME, 10 | deadline: 3600 + Math.floor(Date.now() / 1000) 11 | } 12 | return returnObj; 13 | } 14 | 15 | function urlsafeBase64Encode (jsonFlags) { 16 | var encoded = new Buffer(jsonFlags).toString('base64'); 17 | return base64ToUrlSafe(encoded); 18 | } 19 | 20 | function base64ToUrlSafe (val) { 21 | return val.replace(/\//g, '_').replace(/\+/g, '-'); 22 | } 23 | 24 | function hmacSha1 (encodedFlags, secretKey) { 25 | var hmac = crypto.createHmac('sha1', secretKey); 26 | return hmac.update(encodedFlags).digest('base64'); 27 | } 28 | 29 | module.exports = function() { 30 | var flags = getFlags(); 31 | var encodedFlags = urlsafeBase64Encode(JSON.stringify(flags)); 32 | var encoded = hmacSha1(encodedFlags, config.SECRET_KEY); 33 | var encodedSign = base64ToUrlSafe(encoded); 34 | var tokenInfo = config.ACCESS_KEY + ':' + encodedSign + ':' + encodedFlags; 35 | return tokenInfo; 36 | } 37 | // WebApp.connectHandlers.use('/cmeteor-token', function(req, res) { 38 | // var flags = getFlags(); 39 | // var encodedFlags = urlsafeBase64Encode(JSON.stringify(flags)); 40 | // var encoded = hmacSha1(encodedFlags, config.SECRET_KEY); 41 | // var encodedSign = base64ToUrlSafe(encoded); 42 | // var tokenInfo = { 43 | // uptoken: config.ACCESS_KEY + ':' + encodedSign + ':' + encodedFlags 44 | // } 45 | // res.writeHead(200, { 46 | // 'Content-Type':'text/json', 47 | // 'Expires': 0, 48 | // 'Pragma': 'no-cache' 49 | // }); 50 | // res.end(JSON.stringify(tokenInfo)); 51 | // }); 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-qn-uper", 3 | "version": "1.0.0", 4 | "description": "upload file", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/struCoder/front-qn-uper.git" 12 | }, 13 | "author": "zdwloveschina@gmail.com", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/struCoder/front-qn-uper/issues" 17 | }, 18 | "homepage": "https://github.com/struCoder/front-qn-uper#readme", 19 | "dependencies": { 20 | "express": "^4.13.3" 21 | }, 22 | "devDependencies": { 23 | "gulp": "^3.9.0", 24 | "gulp-changed": "^1.3.0", 25 | "gulp-sass": "^2.1.0", 26 | "gulp-uglify": "^1.4.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /public/css/index.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; } 4 | 5 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, cite, code, del, dfn, em, img, q, s, samp, small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td { 6 | margin: 0; 7 | padding: 0; 8 | border: 0; 9 | font-weight: normal; 10 | font-style: normal; 11 | font-size: 100%; 12 | /*line-height: 1;*/ 13 | font-family: inherit; } 14 | 15 | table { 16 | border-collapse: collapse; 17 | border-spacing: 0; } 18 | 19 | q:before, q:after, blockquote:before, blockquote:after { 20 | content: ""; } 21 | 22 | html { 23 | font-size: 100%; 24 | -webkit-text-size-adjust: 100%; 25 | -ms-text-size-adjust: 100%; } 26 | 27 | a:focus { 28 | outline: thin dotted; } 29 | 30 | a:hover, 31 | a:active { 32 | outline: 0; } 33 | 34 | article, 35 | aside, 36 | details, 37 | figcaption, 38 | figure, 39 | footer, 40 | header, 41 | hgroup, 42 | nav, 43 | section { 44 | display: block; } 45 | 46 | audio, 47 | canvas, 48 | video { 49 | display: inline-block; 50 | *display: inline; 51 | *zoom: 1; } 52 | 53 | audio:not([controls]) { 54 | display: none; } 55 | 56 | sub, 57 | sup { 58 | font-size: 75%; 59 | line-height: 0; 60 | position: relative; 61 | vertical-align: baseline; } 62 | 63 | sup { 64 | top: -0.5em; } 65 | 66 | sub { 67 | bottom: -0.25em; } 68 | 69 | img { 70 | border: 0; 71 | -ms-interpolation-mode: bicubic; } 72 | 73 | button, 74 | input, 75 | select, 76 | textarea { 77 | padding: 0; 78 | font-size: 100%; 79 | margin: 0; 80 | vertical-align: baseline; 81 | *vertical-align: middle; } 82 | 83 | button, 84 | input { 85 | line-height: normal; 86 | *overflow: visible; } 87 | 88 | button::-moz-focus-inner, 89 | input::-moz-focus-inner { 90 | border: 0; 91 | padding: 0; } 92 | 93 | button, 94 | input[type="button"], 95 | input[type="reset"], 96 | input[type="submit"] { 97 | cursor: pointer; 98 | -webkit-appearance: button; } 99 | 100 | input[type="search"] { 101 | -webkit-appearance: textfield; 102 | -webkit-box-sizing: content-box; 103 | -moz-box-sizing: content-box; 104 | box-sizing: content-box; } 105 | 106 | input[type="search"]::-webkit-search-decoration { 107 | -webkit-appearance: none; } 108 | 109 | textarea { 110 | overflow: auto; 111 | vertical-align: top; } 112 | 113 | input[type="text"], input[type="button"], input[type="file"] { 114 | font-weight: 400; 115 | width: 100%; 116 | font-size: 14px; 117 | padding: .75rem 0; 118 | line-height: inherit; 119 | border-radius: 0; 120 | text-indent: 8px; 121 | outline: none; 122 | border: 1px solid #41A6EF; } 123 | 124 | input[type="button"] { 125 | background-color: #41A6EF; } 126 | 127 | .container { 128 | width: 80%; 129 | height: auto; 130 | margin: 0 auto; 131 | margin-top: 10%; 132 | border: 4px dashed #aaa; 133 | padding: 20px; } 134 | .container .margin-auto { 135 | position: relative; 136 | width: 95%; 137 | margin: 0 auto; } 138 | .container .upload-input { 139 | width: 50%; } 140 | .container .upload-input input { 141 | margin-bottom: 30px; } 142 | .container .upload-input .select-prefix input { 143 | display: inline-block; } 144 | .container .upload-input .select-prefix .prefix-btn { 145 | width: 28%; 146 | color: #fff; } 147 | .container .upload-input .file { 148 | opacity: 0; 149 | z-index: 100; 150 | cursor: pointer; } 151 | .container .upload-input .file-btn { 152 | position: absolute; 153 | top: 74px; 154 | z-index: -1; 155 | color: #fff; } 156 | .container .result .pic-url { 157 | padding: 4px; 158 | margin-bottom: 1px; 159 | border: 1px solid rgba(65, 166, 239, 0.48); 160 | width: 100%; 161 | height: auto; 162 | word-break: break-all; 163 | word-wrap: break-word; } 164 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 图片上传自助工具 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/js/lib/zepto.min.js: -------------------------------------------------------------------------------- 1 | /* Zepto v1.1.6 - zepto event ajax form ie - zeptojs.com/license */ 2 | var Zepto=function(){function L(t){return null==t?String(t):j[S.call(t)]||"object"}function Z(t){return"function"==L(t)}function _(t){return null!=t&&t==t.window}function $(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function D(t){return"object"==L(t)}function M(t){return D(t)&&!_(t)&&Object.getPrototypeOf(t)==Object.prototype}function R(t){return"number"==typeof t.length}function k(t){return s.call(t,function(t){return null!=t})}function z(t){return t.length>0?n.fn.concat.apply([],t):t}function F(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function q(t){return t in f?f[t]:f[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function H(t,e){return"number"!=typeof e||c[F(t)]?e:e+"px"}function I(t){var e,n;return u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),u[t]=n),u[t]}function V(t){return"children"in t?o.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function B(n,i,r){for(e in i)r&&(M(i[e])||A(i[e]))?(M(i[e])&&!M(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),B(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function U(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return Z(e)?e.call(t,n,i):e}function X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function W(e,n){var i=e.className||"",r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){try{return t?"true"==t||("false"==t?!1:"null"==t?null:+t+""==t?+t:/^[\[\{]/.test(t)?n.parseJSON(t):t):t}catch(e){return t}}function G(t,e){e(t);for(var n=0,i=t.childNodes.length;i>n;n++)G(t.childNodes[n],e)}var t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},l=/^\s*<(\w+|!)[^>]*>/,h=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=["val","css","html","text","data","width","height","offset"],v=["after","prepend","before","append"],y=a.createElement("table"),x=a.createElement("tr"),b={tr:a.createElement("tbody"),tbody:y,thead:y,tfoot:y,td:x,th:x,"*":a.createElement("div")},w=/complete|loaded|interactive/,E=/^[\w-]*$/,j={},S=j.toString,T={},O=a.createElement("div"),P={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},A=Array.isArray||function(t){return t instanceof Array};return T.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~T.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},N=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},T.fragment=function(e,i,r){var s,u,f;return h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,"<$1>")),i===t&&(i=l.test(e)&&RegExp.$1),i in b||(i="*"),f=b[i],f.innerHTML=""+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),M(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},T.Z=function(t,e){return t=t||[],t.__proto__=n.fn,t.selector=e||"",t},T.isZ=function(t){return t instanceof T.Z},T.init=function(e,i){var r;if(!e)return T.Z();if("string"==typeof e)if(e=e.trim(),"<"==e[0]&&l.test(e))r=T.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}else{if(Z(e))return n(a).ready(e);if(T.isZ(e))return e;if(A(e))r=k(e);else if(D(e))r=[e],e=null;else if(l.test(e))r=T.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=T.qsa(a,e)}}return T.Z(r,e)},n=function(t,e){return T.init(t,e)},n.extend=function(t){var e,n=o.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){B(t,n,e)}),t},T.qsa=function(t,e){var n,i="#"==e[0],r=!i&&"."==e[0],s=i||r?e.slice(1):e,a=E.test(s);return $(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=a.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},n.type=L,n.isFunction=Z,n.isWindow=_,n.isArray=A,n.isPlainObject=M,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return null==t?"":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var n,r,o,i=[];if(R(t))for(r=0;r=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return T.matches(e,t)}))},add:function(t,e){return n(N(this.concat(n(t,e))))},is:function(t){return this.length>0&&T.matches(this[0],t)},not:function(e){var i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r="string"==typeof e?this.filter(e):R(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!D(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var e,i=this;return e=t?"object"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(T.qsa(this[0],t)):this.map(function(){return T.qsa(this,t)}):n()},closest:function(t,e){var i=this[0],r=!1;for("object"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:T.matches(i,t));)i=i!==e&&!$(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!$(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return U(e,t)},parent:function(t){return U(N(this.pluck("parentNode")),t)},children:function(t){return U(this.map(function(){return V(this)}),t)},contents:function(){return this.map(function(){return o.call(this.childNodes)})},siblings:function(t){return U(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=Z(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?"none"==i.css("display"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return n(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var i=this.innerHTML;n(this).empty().append(J(this,t,e,i))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=J(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this[0].textContent:null},attr:function(n,i){var r;return"string"!=typeof n||1 in arguments?this.each(function(t){if(1===this.nodeType)if(D(n))for(e in n)X(this,e,n[e]);else X(this,n,J(this,i,t,this.getAttribute(n)))}):this.length&&1===this[0].nodeType?!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:t},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){X(this,t)},this)})},prop:function(t,e){return t=P[t]||t,1 in arguments?this.each(function(n){this[t]=J(this,e,n,this[t])}):this[0]&&this[0][t]},data:function(e,n){var i="data-"+e.replace(m,"-$1").toLowerCase(),r=1 in arguments?this.attr(i,n):this.attr(i);return null!==r?Y(r):t},val:function(t){return 0 in arguments?this.each(function(e){this.value=J(this,t,e,this.value)}):this[0]&&(this[0].multiple?n(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};"static"==i.css("position")&&(s.position="relative"),i.css(s)});if(!this.length)return null;var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r,o=this[0];if(!o)return;if(r=getComputedStyle(o,""),"string"==typeof t)return o.style[C(t)]||r.getPropertyValue(t);if(A(t)){var s={};return n.each(t,function(t,e){s[e]=o.style[C(e)]||r.getPropertyValue(e)}),s}}var a="";if("string"==L(t))i||0===i?a=F(t)+":"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else for(e in t)t[e]||0===t[e]?a+=F(e)+":"+H(e,t[e])+";":this.each(function(){this.style.removeProperty(F(e))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(W(t))},q(t)):!1},addClass:function(t){return t?this.each(function(e){if("className"in this){i=[];var r=W(this),o=J(this,t,e,r);o.split(/\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?" ":"")+i.join(" "))}}):this},removeClass:function(e){return this.each(function(n){if("className"in this){if(e===t)return W(this,"");i=W(this),J(this,e,n,i).split(/\s+/g).forEach(function(t){i=i.replace(q(t)," ")}),W(this,i.trim())}})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=J(this,e,r,W(this));s.split(/\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n="scrollTop"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n="scrollLeft"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css("margin-top"))||0,i.left-=parseFloat(n(t).css("margin-left"))||0,r.top+=parseFloat(n(e[0]).css("border-top-width"))||0,r.left+=parseFloat(n(e[0]).css("border-left-width"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&"static"==n(t).css("position");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,["width","height"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?_(s)?s["inner"+i]:$(s)?s.documentElement["scroll"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=L(e),"object"==t||"array"==t||null==e?e:T.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,u){o=i?u:u.parentNode,u=0==e?u.nextSibling:1==e?u.firstChild:2==e?u:null;var f=n.contains(a.documentElement,o);r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();o.insertBefore(t,u),f&&G(t,function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+"To":"insert"+(e?"Before":"After")]=function(e){return n(e)[t](this),this}}),T.Z.prototype=n.fn,T.uniq=N,T.deserializeValue=Y,n.zepto=T,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function d(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\s/).forEach(function(i){if("ready"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),"addEventListener"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||"").split(/\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],"removeEventListener"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function S(t){var e,i={originalEvent:t};for(e in t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return"string"==typeof t},s={},a={},u="onfocusin"in window,f={focus:"focusin",blur:"focusout"},c={mouseenter:"mouseover",mouseleave:"mouseout"};a.click=a.mousedown=a.mouseup=a.mousemove="MouseEvents",t.event={add:v,remove:y},t.proxy=function(e,n){var s=2 in arguments&&i.call(arguments,2);if(r(e)){var a=function(){return e.apply(n,s?s.concat(i.call(arguments)):arguments)};return a._zid=l(e),a}if(o(n))return s?(s.unshift(e[n],e),t.proxy.apply(null,s)):t.proxy(e[n],e);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(S(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){e.type in f&&"function"==typeof this[e.type]?this[e.type]():"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=S(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||"Events"),i=!0;if(e)for(var r in e)"bubbles"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function h(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function p(t,e,i,r){return t.global?h(e||n,i,r):void 0}function d(e){e.global&&0===t.active++&&p(e,null,"ajaxStart")}function m(e){e.global&&!--t.active&&p(e,null,"ajaxStop")}function g(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||p(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void p(e,n,"ajaxSend",[t,e])}function v(t,e,n,i){var r=n.context,o="success";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),p(n,r,"ajaxSuccess",[e,n,t]),x(o,e,n)}function y(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),p(i,o,"ajaxError",[n,i,t||e]),x(e,n,i)}function x(t,e,n){var i=n.context;n.complete.call(i,e,t),p(n,i,"ajaxComplete",[e,n]),m(n)}function b(){}function w(t){return t&&(t=t.split(";",2)[0]),t&&(t==f?"html":t==u?"json":s.test(t)?"script":a.test(t)&&"xml")||"text"}function E(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function j(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()||(e.url=E(e.url,e.data),e.data=void 0)}function S(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function C(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+"["+(a||"object"==o||"array"==o?n:"")+"]"),!r&&s?e.add(u.name,u.value):"array"==o||!i&&"object"==o?C(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i,a=/^(?:text|application)\/xml/i,u="application/json",f="text/html",c=/^\s*$/,l=n.createElement("a");l.href=window.location.href,t.active=0,t.ajaxJSONP=function(i,r){if(!("type"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||"jsonp"+ ++e,a=n.createElement("script"),u=window[s],c=function(e){t(a).triggerHandler("error",e||"abort")},l={abort:c};return r&&r.promise(l),t(a).on("load error",function(e,n){clearTimeout(h),t(a).off().remove(),"error"!=e.type&&f?v(f[0],l,i,r):y(null,n||"error",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),g(l,i)===!1?(c("abort"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\?(.+)=\?/,"?$1="+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c("timeout")},i.timeout)),l)},t.ajaxSettings={type:"GET",beforeSend:b,success:b,error:b,complete:b,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:u,xml:"application/xml, text/xml",html:f,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var a,o=t.extend({},e||{}),s=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===o[i]&&(o[i]=t.ajaxSettings[i]);d(o),o.crossDomain||(a=n.createElement("a"),a.href=o.url,a.href=a.href,o.crossDomain=l.protocol+"//"+l.host!=a.protocol+"//"+a.host),o.url||(o.url=window.location.toString()),j(o);var u=o.dataType,f=/\?.+=\?/.test(o.url);if(f&&(u="jsonp"),o.cache!==!1&&(e&&e.cache===!0||"script"!=u&&"jsonp"!=u)||(o.url=E(o.url,"_="+Date.now())),"jsonp"==u)return f||(o.url=E(o.url,o.jsonp?o.jsonp+"=?":o.jsonp===!1?"":"callback=?")),t.ajaxJSONP(o,s);var C,h=o.accepts[u],p={},m=function(t,e){p[t.toLowerCase()]=[t,e]},x=/^([\w-]+:)\/\//.test(o.url)?RegExp.$1:window.location.protocol,S=o.xhr(),T=S.setRequestHeader;if(s&&s.promise(S),o.crossDomain||m("X-Requested-With","XMLHttpRequest"),m("Accept",h||"*/*"),(h=o.mimeType||h)&&(h.indexOf(",")>-1&&(h=h.split(",",2)[0]),S.overrideMimeType&&S.overrideMimeType(h)),(o.contentType||o.contentType!==!1&&o.data&&"GET"!=o.type.toUpperCase())&&m("Content-Type",o.contentType||"application/x-www-form-urlencoded"),o.headers)for(r in o.headers)m(r,o.headers[r]);if(S.setRequestHeader=m,S.onreadystatechange=function(){if(4==S.readyState){S.onreadystatechange=b,clearTimeout(C);var e,n=!1;if(S.status>=200&&S.status<300||304==S.status||0==S.status&&"file:"==x){u=u||w(o.mimeType||S.getResponseHeader("content-type")),e=S.responseText;try{"script"==u?(1,eval)(e):"xml"==u?e=S.responseXML:"json"==u&&(e=c.test(e)?null:t.parseJSON(e))}catch(i){n=i}n?y(n,"parsererror",S,o,s):v(e,S,o,s)}else y(S.statusText||null,S.status?"error":"abort",S,o,s)}},g(S,o)===!1)return S.abort(),y(null,"abort",S,o,s),S;if(o.xhrFields)for(r in o.xhrFields)S[r]=o.xhrFields[r];var N="async"in o?o.async:!0;S.open(o.type,o.url,N,o.username,o.password);for(r in p)T.apply(S,p[r]);return o.timeout>0&&(C=setTimeout(function(){S.onreadystatechange=b,S.abort(),y(null,"timeout",S,o,s)},o.timeout)),S.send(o.data?o.data:null),S},t.get=function(){return t.ajax(S.apply(null,arguments))},t.post=function(){var e=S.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=S.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\s/),u=S(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t("
").html(e.replace(o,"")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var T=encodeURIComponent;t.param=function(e,n){var i=[];return i.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(T(e)+"="+T(n))},C(i,e,n),i.join("&").replace(/%20/g,"+")}}(Zepto),function(t){t.fn.serializeArray=function(){var e,n,i=[],r=function(t){return t.forEach?t.forEach(r):void i.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(i,o){n=o.type,e=o.name,e&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&r(t(o).val())}),i},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(t){"__proto__"in{}||t.extend(t.zepto,{Z:function(e,n){return e=e||[],t.extend(e,t.fn),e.selector=n||"",e.__Z=!0,e},isZ:function(e){return"array"===t.type(e)&&"__Z"in e}});try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;window.getComputedStyle=function(t){try{return n(t)}catch(e){return null}}}}(Zepto); -------------------------------------------------------------------------------- /public/js/manager.js: -------------------------------------------------------------------------------- 1 | !function(){var n=$("#file-btn"),o=$("#result-show"),i={domain:"http://7xjbiz.com1.z0.glb.clouddn.com",tokenUrl:"/token",prefix:"temp/"},e=new frontQnUper(i);$("#upload").on("change",function(){e.prefix=$("#prefix").val()||"temp/";var i=this.files[0];e.progress=function(o,i){n.val("上传进度: "+100*(i/o).toFixed(0)+"%"),i===o&&n.val("请稍等...")},e.errHandle=function(n){alert(n)},e.post(i,function(i){var e=[];for(var t in i)e.push(['
',"",i[t],"","
"].join(""));o.append(e.join("")),setTimeout(function(){n.val("上传图片")},1500)})})}(); -------------------------------------------------------------------------------- /public/js/uploader.js: -------------------------------------------------------------------------------- 1 | !function(){var t="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",o=["jpg","jpeg","gif","png","bmp"],n=function(e){e=e||16;for(var o="",n=t.length,r=null,i=0;e>i;i++)r=Math.floor(Math.random()*n),o+=t.substring(r-1,r);return o},r=function(){var t={};return t=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),t.timeout=this.timeout,t},i=function(t,e){var o=this,n=r();n.open(t.method,t.url,!0),n.onload=function(){if(200===n.status){try{var t=JSON.parse(n.responseText)}catch(o){o.msg="parse text to json error",e(o)}e(null,t)}},n.ontimeout=function(){e("timeout")},n.onerror=function(t){t.msg="network error not frontQnUper self error",e(t)},t.onProgress&&(n.upload.onprogress=function(t){o.progress(t.total,t.loaded)}),n.send("POST"===t.method?t.data:null)},a=function(t){if("[object Object]"!==Object.prototype.toString.call(t))throw new Error("options must be Object");t.imageType?this.imageTypeArr=t.imageType.split(","):this.imageTypeArr=o,this.domain=t.domain,this.url=t.tokenUrl,this.prefix=t.prefix||"font-qn-uper/",this.timeout=t.timeout||5e3,this.maxMobileWidth=t.maxWidth||480,this.maxPcWidth=t.maxPcWidth||960,this.defaultSize=parseInt(t.maxImgSize,10)||10240,this.uploadUrl="http://upload.qiniu.com/?token="};a.prototype.checkType=function(t){var e,o=this.file.name,n=this.file.size/1024,r=o.substring(o.lastIndexOf(".")+1).toLowerCase();-1===this.imageTypeArr.indexOf(r)?(e="图片格式为下面的一种: "+this.imageTypeArr.toString(),t(e)):n>this.defaultSize?(e="图片大小因控制在"+this.defaultSize+" 内",t(e)):t()},a.prototype._getToken=function(t){var e={method:"GET",url:this.url};if("function"!=typeof t)throw new Error("when get uptoken the cb must be Function");i(e,t)},a.prototype._postPrepare=function(t){var o=this;this.checkType(function(n){return n&&"function"==typeof o.errHandle?o.errHandle(n):void o._getToken(function(n,r){return n&&"function"==typeof o.errHandle?o.errHandle(e):(o.token=r,void("function"==typeof t&&t()))})})},a.prototype.post=function(t,e){this.file=t;var o=this,r=n();this._postPrepare(function(){var n=new FormData;n.append("file",t),n.append("key",o.prefix+r);var a=o.uploadUrl+o.token.uptoken+"&rand="+Math.random(),p={method:"POST",url:a,onProgress:!0,data:n};i.call(o,p,function(t,n){if(t&&"function"==typeof errHandle)return errHandle(t);var r={};r.fullImageUrl=o.domain+"/"+n.key,r.mobileImageUrl=o.domain+"/"+n.key+"?imageView2/0/w/"+o.maxMobileWidth,r.pcImageUrl=o.domain+"/"+n.key+"?imageView2/2/w/"+o.maxPcWidth,e(r)})})},window.frontQnUper=a}(); --------------------------------------------------------------------------------