├── .gitignore ├── CONTRIBUTING.md ├── src ├── svg │ └── loading-spin.svg ├── imgur.css └── imgur.js ├── example ├── svg │ └── loading-spin.svg └── index.html ├── package.json ├── LICENSE ├── Gruntfile.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 1. Fork it! 4 | 2. Create your feature branch: `git checkout -b my-new-feature` 5 | 3. Commit your changes: `git commit -m 'Add some feature'` 6 | 4. Push to the branch: `git push origin my-new-feature` 7 | 5. Submit a pull request :D 8 | 9 | English is the universal language nowadays, so please don't create or comment on issues using another language. -------------------------------------------------------------------------------- /src/svg/loading-spin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/svg/loading-spin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgur", 3 | "description": "Upload images to imgur via JavaScript", 4 | "version": "2.1.0", 5 | "private": true, 6 | "author": "Pedro Rogério", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "devDependencies": { 11 | "grunt": "^1.5.3", 12 | "grunt-contrib-copy": "~1.0.0", 13 | "grunt-contrib-cssmin": "~2.2.1", 14 | "grunt-contrib-uglify": "~3.3.0", 15 | "grunt-contrib-watch": "^1.1.0" 16 | }, 17 | "repository": "https://github.com/pinceladasdaweb/imgur", 18 | "bugs": { 19 | "url": "https://github.com/pinceladasdaweb/imgur/issues" 20 | }, 21 | "licenses": [ 22 | { 23 | "type": "MIT", 24 | "url": "http://opensource.org/licenses/MIT" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Pedro Rogério 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/imgur.css: -------------------------------------------------------------------------------- 1 | .dropzone { 2 | border: 4px dashed #ccc; 3 | height: 200px; 4 | margin: 0 10px; 5 | position: relative; 6 | width: auto; 7 | } 8 | 9 | .dropzone p { 10 | height: 100%; 11 | line-height: 200px; 12 | margin: 0; 13 | text-align: center; 14 | width: 100%; 15 | } 16 | 17 | .dropzone input[type="file"] { 18 | height: 100%; 19 | left: 0; 20 | outline: none; 21 | opacity: 0; 22 | position: absolute; 23 | top: 0; 24 | width: 100%; 25 | } 26 | 27 | .dropzone + .status { 28 | border-radius: 5px; 29 | margin: 10px 10px 0; 30 | padding: 15px; 31 | text-align: center; 32 | } 33 | 34 | .dropzone.dropzone-dragging { 35 | border-color: black 36 | } 37 | 38 | .loading-modal { 39 | background-color: rgba( 255, 255, 255, .8 ); 40 | display: none; 41 | position: fixed; 42 | z-index: 1000; 43 | top: 0; 44 | left: 0; 45 | height: 100%; 46 | width: 100%; 47 | } 48 | 49 | .loading-image { 50 | position: absolute; 51 | top: 50%; 52 | left: 50%; 53 | margin: -16px 0 0 -16px 54 | } 55 | 56 | body.busy .loading-modal { 57 | display: block; 58 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | "use strict"; 3 | 4 | var pkg = grunt.file.readJSON("package.json"), 5 | date = new Date(); 6 | 7 | grunt.initConfig({ 8 | meta: { 9 | banner: '/*! ' + pkg.name + ' ' + pkg.version + ' | (c) ' + date.getFullYear() + ' ' + pkg.author + ' | ' + pkg.licenses[0].type + ' License */' 10 | }, 11 | copy: { 12 | main: { 13 | src: 'src/svg/loading-spin.svg', 14 | dest: 'build/svg/loading-spin.svg', 15 | }, 16 | }, 17 | cssmin: { 18 | target: { 19 | files: { 20 | 'build/imgur.min.css': ['src/imgur.css'] 21 | } 22 | } 23 | }, 24 | uglify: { 25 | options: { 26 | banner: '<%= meta.banner %>\n' 27 | }, 28 | target: { 29 | files: { 30 | 'build/imgur.min.js': ['src/imgur.js'] 31 | } 32 | } 33 | }, 34 | watch: { 35 | css: { 36 | files: ['src/imgur.css'], 37 | tasks: ['cssmin'] 38 | }, 39 | js: { 40 | files: ['src/imgur.js'], 41 | tasks: ['uglify'] 42 | } 43 | } 44 | }); 45 | 46 | grunt.loadNpmTasks('grunt-contrib-watch'); 47 | grunt.loadNpmTasks('grunt-contrib-copy'); 48 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 49 | grunt.loadNpmTasks('grunt-contrib-uglify'); 50 | 51 | grunt.registerTask('default', [ 'uglify', 'cssmin', 'copy' ]); 52 | }; 53 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | imgur Upload API 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 |
23 |

imgur Upload API

24 |

Upload images to imgur via JavaScript

25 |
26 | 27 |
28 |
29 |
30 | 31 | 32 | 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Imgur 2 | > Upload images to Imgur via JavaScript. 3 | 4 | ## Demo 5 | View demo [here](http://www.pinceladasdaweb.com.br/blog/uploads/imgur/). 6 | 7 | ## Getting Started 8 | 9 | ```bash 10 | # Get the latest snapshot 11 | $ git clone git@github.com:pinceladasdaweb/imgur.git 12 | ``` 13 | 14 | The script depends on the following HTML markup: 15 | 16 | ```html 17 |
18 | ``` 19 | 20 | Add the following css before your `````` tag: 21 | 22 | ```html 23 | 24 | ``` 25 | 26 | Add the following javascript before your `````` tag: 27 | 28 | ```html 29 | 30 | 42 | ``` 43 | 44 | Loading Imgur via AMD (require.js): 45 | 46 | ```html 47 | 61 | ``` 62 | 63 | The script expect the following values: 64 | 65 | | Value | Description | 66 | | ---------------------------------- |:-----------------------------------------------------------:| 67 | | **clientid** | Your Client-ID. Get here [https://apidocs.imgur.com/](https://apidocs.imgur.com/)| 68 | | **callback** | Calllback to run after the success upload | 69 | 70 | ##Browser Support 71 | 72 | ![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/internet-explorer/internet-explorer_48x48.png) | ![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Opera](https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png) 73 | --- | --- | --- | --- | --- | 74 | IE 10+ ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 75 | 76 | ## Contributing 77 | 78 | Check [CONTRIBUTING.md](CONTRIBUTING.md) for more information. 79 | 80 | ## History 81 | 82 | Check [Releases](https://github.com/pinceladasdaweb/imgur/releases) for detailed changelog. 83 | 84 | ## License 85 | 86 | [MIT](LICENSE) 87 | -------------------------------------------------------------------------------- /src/imgur.js: -------------------------------------------------------------------------------- 1 | /*jslint browser: true, debug: true*/ 2 | /*global define, module, exports*/ 3 | (function (root, factory) { 4 | "use strict"; 5 | if (typeof define === 'function' && define.amd) { 6 | define([], factory); 7 | } else if (typeof exports === 'object') { 8 | module.exports = factory(); 9 | } else { 10 | root.Imgur = factory(); 11 | } 12 | }(this, function () { 13 | "use strict"; 14 | var Imgur = function (options) { 15 | if (!this || !(this instanceof Imgur)) { 16 | return new Imgur(options); 17 | } 18 | 19 | if (!options) { 20 | options = {}; 21 | } 22 | 23 | if (!options.clientid) { 24 | throw 'Provide a valid Client Id here: https://apidocs.imgur.com/'; 25 | } 26 | 27 | this.clientid = options.clientid; 28 | this.endpoint = 'https://api.imgur.com/3/image'; 29 | this.callback = options.callback || undefined; 30 | this.dropzone = document.querySelectorAll('.dropzone'); 31 | 32 | this.run(); 33 | }; 34 | 35 | Imgur.prototype = { 36 | createEls: function (name, props, text) { 37 | var el = document.createElement(name), p; 38 | for (p in props) { 39 | if (props.hasOwnProperty(p)) { 40 | el[p] = props[p]; 41 | } 42 | } 43 | if (text) { 44 | el.appendChild(document.createTextNode(text)); 45 | } 46 | return el; 47 | }, 48 | insertAfter: function (referenceNode, newNode) { 49 | referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 50 | }, 51 | post: function (path, data, callback) { 52 | var xhttp = new XMLHttpRequest(); 53 | 54 | xhttp.open('POST', path, true); 55 | xhttp.setRequestHeader('Authorization', 'Client-ID ' + this.clientid); 56 | xhttp.onreadystatechange = function () { 57 | if (this.readyState === 4) { 58 | if (this.status >= 200 && this.status < 300) { 59 | var response = ''; 60 | try { 61 | response = JSON.parse(this.responseText); 62 | } catch (err) { 63 | response = this.responseText; 64 | } 65 | callback.call(window, response); 66 | } else { 67 | throw new Error(this.status + " - " + this.statusText); 68 | } 69 | } 70 | }; 71 | xhttp.send(data); 72 | xhttp = null; 73 | }, 74 | createDragZone: function () { 75 | var p, input; 76 | 77 | p = this.createEls('p', {}, 'Drag your files here or click in this area.'); 78 | input = this.createEls('input', {type: 'file', multiple: 'multiple', accept: 'image/*'}); 79 | 80 | Array.prototype.forEach.call(this.dropzone, function (zone) { 81 | zone.appendChild(p); 82 | zone.appendChild(input); 83 | this.status(zone); 84 | this.upload(zone); 85 | }.bind(this)); 86 | }, 87 | loading: function () { 88 | var div, img; 89 | 90 | div = this.createEls('div', {className: 'loading-modal'}); 91 | img = this.createEls('img', {className: 'loading-image', src: './svg/loading-spin.svg'}); 92 | 93 | div.appendChild(img); 94 | document.body.appendChild(div); 95 | }, 96 | status: function (el) { 97 | var div = this.createEls('div', {className: 'status'}); 98 | 99 | this.insertAfter(el, div); 100 | }, 101 | matchFiles: function (file, zone) { 102 | var status = zone.nextSibling; 103 | 104 | if (file.type.match(/image/) && file.type !== 'image/svg+xml') { 105 | document.body.classList.add('busy'); 106 | status.classList.remove('bg-success', 'bg-danger'); 107 | status.innerHTML = ''; 108 | 109 | var fd = new FormData(); 110 | fd.append('image', file); 111 | 112 | this.post(this.endpoint, fd, function (data) { 113 | document.body.classList.remove('busy'); 114 | typeof this.callback === 'function' && this.callback.call(this, data); 115 | }.bind(this)); 116 | } else { 117 | status.classList.remove('bg-success'); 118 | status.classList.add('bg-danger'); 119 | status.innerHTML = 'Invalid archive'; 120 | } 121 | }, 122 | upload: function (zone) { 123 | var events = ['dragenter', 'dragleave', 'dragover', 'drop'], 124 | file, target, i, len; 125 | 126 | zone.addEventListener('change', function (e) { 127 | if (e.target && e.target.nodeName === 'INPUT' && e.target.type === 'file') { 128 | target = e.target.files; 129 | 130 | for (i = 0, len = target.length; i < len; i += 1) { 131 | file = target[i]; 132 | this.matchFiles(file, zone); 133 | } 134 | } 135 | }.bind(this), false); 136 | 137 | events.map(function (event) { 138 | zone.addEventListener(event, function (e) { 139 | if (e.target && e.target.nodeName === 'INPUT' && e.target.type === 'file') { 140 | if (event === 'dragleave' || event === 'drop') { 141 | e.target.parentNode.classList.remove('dropzone-dragging'); 142 | } else { 143 | e.target.parentNode.classList.add('dropzone-dragging'); 144 | } 145 | } 146 | }, false); 147 | }); 148 | }, 149 | run: function () { 150 | var loadingModal = document.querySelector('.loading-modal'); 151 | 152 | if (!loadingModal) { 153 | this.loading(); 154 | } 155 | this.createDragZone(); 156 | } 157 | }; 158 | 159 | return Imgur; 160 | })); --------------------------------------------------------------------------------