Merge branch 'imgur' into develop
This commit is contained in:
commit
ab7c25ebea
@ -26,6 +26,7 @@ third party code used in this experiment
|
||||
* [require js](http://requirejs.org/), by [jrburke](jrburke), BSD & MIT license
|
||||
* [almond js](https://github.com/jrburke/almond), by [jrburke](jrburke), BSD & MIT license
|
||||
* [raf js](https://gist.github.com/paulirish/1579671), by [paulirish](https://github.com/paulirish), MIT license
|
||||
* [reqwest js](https://github.com/ded/reqwest/), by [ded](https://github.com/ded)
|
||||
|
||||
license
|
||||
---
|
||||
|
||||
10
index.html
10
index.html
@ -35,10 +35,16 @@
|
||||
<button id="random-button" class="button is-hidden">randomize</button>
|
||||
</div>
|
||||
<div class="export-wrapper">
|
||||
<button id="import-button" class="button">import image</button>
|
||||
<button id="import-button" class="button" title="open image from your computer">import image</button>
|
||||
<input type="file" id="import-input" accept="image/*" />
|
||||
<button id="save-button" class="button">export image</button>
|
||||
<button id="export-button" class="button" title="save image to your computer">download image</button>
|
||||
<button id="imgur-button" class="button" title="share image via imgur.com"><span>share image</span></button>
|
||||
<a id="png-button" download="glitched-image.png" target="_blank" class="download-link">download bitmap file<span> (.png)</span></a>
|
||||
<div id="imgur-url-container">
|
||||
<input id="imgur-url-input" type="text" readonly="readonly" />
|
||||
<a href id="imgur-url-link" class="button" href="http://imgur.com" target="_blank">open</a>
|
||||
<span id="imgur-url-error">Sorry, something went wrong. Maybe try again?</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="canvas-wrapper">
|
||||
<canvas id="canvas" />
|
||||
|
||||
590
scripts/lib/reqwest.js
Normal file
590
scripts/lib/reqwest.js
Normal file
@ -0,0 +1,590 @@
|
||||
!function (name, context, definition) {
|
||||
if (typeof module != 'undefined' && module.exports) module.exports = definition()
|
||||
else if (typeof define == 'function' && define.amd) define(definition)
|
||||
else context[name] = definition()
|
||||
}('reqwest', this, function () {
|
||||
|
||||
var win = window
|
||||
, doc = document
|
||||
, twoHundo = /^20\d$/
|
||||
, byTag = 'getElementsByTagName'
|
||||
, readyState = 'readyState'
|
||||
, contentType = 'Content-Type'
|
||||
, requestedWith = 'X-Requested-With'
|
||||
, head = doc[byTag]('head')[0]
|
||||
, uniqid = 0
|
||||
, callbackPrefix = 'reqwest_' + (+new Date())
|
||||
, lastValue // data stored by the most recent JSONP callback
|
||||
, xmlHttpRequest = 'XMLHttpRequest'
|
||||
, xDomainRequest = 'XDomainRequest'
|
||||
, noop = function () {}
|
||||
|
||||
, isArray = typeof Array.isArray == 'function'
|
||||
? Array.isArray
|
||||
: function (a) {
|
||||
return a instanceof Array
|
||||
}
|
||||
|
||||
, defaultHeaders = {
|
||||
contentType: 'application/x-www-form-urlencoded'
|
||||
, requestedWith: xmlHttpRequest
|
||||
, accept: {
|
||||
'*': 'text/javascript, text/html, application/xml, text/xml, */*'
|
||||
, xml: 'application/xml, text/xml'
|
||||
, html: 'text/html'
|
||||
, text: 'text/plain'
|
||||
, json: 'application/json, text/javascript'
|
||||
, js: 'application/javascript, text/javascript'
|
||||
}
|
||||
}
|
||||
|
||||
, xhr = function(o) {
|
||||
// is it x-domain
|
||||
if (o.crossOrigin === true) {
|
||||
var xhr = win[xmlHttpRequest] ? new XMLHttpRequest() : null
|
||||
if (xhr && 'withCredentials' in xhr) {
|
||||
return xhr
|
||||
} else if (win[xDomainRequest]) {
|
||||
return new XDomainRequest()
|
||||
} else {
|
||||
throw new Error('Browser does not support cross-origin requests')
|
||||
}
|
||||
} else if (win[xmlHttpRequest]) {
|
||||
return new XMLHttpRequest()
|
||||
} else {
|
||||
return new ActiveXObject('Microsoft.XMLHTTP')
|
||||
}
|
||||
}
|
||||
, globalSetupOptions = {
|
||||
dataFilter: function (data) {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
function handleReadyState(r, success, error) {
|
||||
return function () {
|
||||
// use _aborted to mitigate against IE err c00c023f
|
||||
// (can't read props on aborted request objects)
|
||||
if (r._aborted) return error(r.request)
|
||||
if (r.request && r.request[readyState] == 4) {
|
||||
r.request.onreadystatechange = noop
|
||||
if (twoHundo.test(r.request.status))
|
||||
success(r.request)
|
||||
else
|
||||
error(r.request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setHeaders(http, o) {
|
||||
var headers = o.headers || {}
|
||||
, h
|
||||
|
||||
headers.Accept = headers.Accept
|
||||
|| defaultHeaders.accept[o.type]
|
||||
|| defaultHeaders.accept['*']
|
||||
|
||||
// breaks cross-origin requests with legacy browsers
|
||||
if (!o.crossOrigin && !headers[requestedWith]) headers[requestedWith] = defaultHeaders.requestedWith
|
||||
if (!headers[contentType]) headers[contentType] = o.contentType || defaultHeaders.contentType
|
||||
for (h in headers)
|
||||
headers.hasOwnProperty(h) && 'setRequestHeader' in http && http.setRequestHeader(h, headers[h])
|
||||
}
|
||||
|
||||
function setCredentials(http, o) {
|
||||
if (typeof o.withCredentials !== 'undefined' && typeof http.withCredentials !== 'undefined') {
|
||||
http.withCredentials = !!o.withCredentials
|
||||
}
|
||||
}
|
||||
|
||||
function generalCallback(data) {
|
||||
lastValue = data
|
||||
}
|
||||
|
||||
function urlappend (url, s) {
|
||||
return url + (/\?/.test(url) ? '&' : '?') + s
|
||||
}
|
||||
|
||||
function handleJsonp(o, fn, err, url) {
|
||||
var reqId = uniqid++
|
||||
, cbkey = o.jsonpCallback || 'callback' // the 'callback' key
|
||||
, cbval = o.jsonpCallbackName || reqwest.getcallbackPrefix(reqId)
|
||||
// , cbval = o.jsonpCallbackName || ('reqwest_' + reqId) // the 'callback' value
|
||||
, cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)')
|
||||
, match = url.match(cbreg)
|
||||
, script = doc.createElement('script')
|
||||
, loaded = 0
|
||||
, isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1
|
||||
|
||||
if (match) {
|
||||
if (match[3] === '?') {
|
||||
url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name
|
||||
} else {
|
||||
cbval = match[3] // provided callback func name
|
||||
}
|
||||
} else {
|
||||
url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em
|
||||
}
|
||||
|
||||
win[cbval] = generalCallback
|
||||
|
||||
script.type = 'text/javascript'
|
||||
script.src = url
|
||||
script.async = true
|
||||
if (typeof script.onreadystatechange !== 'undefined' && !isIE10) {
|
||||
// need this for IE due to out-of-order onreadystatechange(), binding script
|
||||
// execution to an event listener gives us control over when the script
|
||||
// is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
|
||||
//
|
||||
// if this hack is used in IE10 jsonp callback are never called
|
||||
script.event = 'onclick'
|
||||
script.htmlFor = script.id = '_reqwest_' + reqId
|
||||
}
|
||||
|
||||
script.onload = script.onreadystatechange = function () {
|
||||
if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {
|
||||
return false
|
||||
}
|
||||
script.onload = script.onreadystatechange = null
|
||||
script.onclick && script.onclick()
|
||||
// Call the user callback with the last value stored and clean up values and scripts.
|
||||
fn(lastValue)
|
||||
lastValue = undefined
|
||||
head.removeChild(script)
|
||||
loaded = 1
|
||||
}
|
||||
|
||||
// Add the script to the DOM head
|
||||
head.appendChild(script)
|
||||
|
||||
// Enable JSONP timeout
|
||||
return {
|
||||
abort: function () {
|
||||
script.onload = script.onreadystatechange = null
|
||||
err({}, 'Request is aborted: timeout', {})
|
||||
lastValue = undefined
|
||||
head.removeChild(script)
|
||||
loaded = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRequest(fn, err) {
|
||||
var o = this.o
|
||||
, method = (o.method || 'GET').toUpperCase()
|
||||
, url = typeof o === 'string' ? o : o.url
|
||||
// convert non-string objects to query-string form unless o.processData is false
|
||||
, data = (o.processData !== false && o.data && typeof o.data !== 'string')
|
||||
? reqwest.toQueryString(o.data)
|
||||
: (o.data || null)
|
||||
, http
|
||||
, sendWait = false
|
||||
|
||||
// if we're working on a GET request and we have data then we should append
|
||||
// query string to end of URL and not post data
|
||||
if ((o.type == 'jsonp' || method == 'GET') && data) {
|
||||
url = urlappend(url, data)
|
||||
data = null
|
||||
}
|
||||
|
||||
if (o.type == 'jsonp') return handleJsonp(o, fn, err, url)
|
||||
|
||||
http = xhr(o)
|
||||
http.open(method, url, o.async === false ? false : true)
|
||||
setHeaders(http, o)
|
||||
setCredentials(http, o)
|
||||
if (win[xDomainRequest] && http instanceof win[xDomainRequest]) {
|
||||
http.onload = fn
|
||||
http.onerror = err
|
||||
// NOTE: see
|
||||
// http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/30ef3add-767c-4436-b8a9-f1ca19b4812e
|
||||
http.onprogress = function() {}
|
||||
sendWait = true
|
||||
} else {
|
||||
http.onreadystatechange = handleReadyState(this, fn, err)
|
||||
}
|
||||
o.before && o.before(http)
|
||||
if (sendWait) {
|
||||
setTimeout(function () {
|
||||
http.send(data)
|
||||
}, 200)
|
||||
} else {
|
||||
http.send(data)
|
||||
}
|
||||
return http
|
||||
}
|
||||
|
||||
function Reqwest(o, fn) {
|
||||
this.o = o
|
||||
this.fn = fn
|
||||
|
||||
init.apply(this, arguments)
|
||||
}
|
||||
|
||||
function setType(url) {
|
||||
var m = url.match(/\.(json|jsonp|html|xml)(\?|$)/)
|
||||
return m ? m[1] : 'js'
|
||||
}
|
||||
|
||||
function init(o, fn) {
|
||||
|
||||
this.url = typeof o == 'string' ? o : o.url
|
||||
this.timeout = null
|
||||
|
||||
// whether request has been fulfilled for purpose
|
||||
// of tracking the Promises
|
||||
this._fulfilled = false
|
||||
// success handlers
|
||||
this._successHandler = function(){}
|
||||
this._fulfillmentHandlers = []
|
||||
// error handlers
|
||||
this._errorHandlers = []
|
||||
// complete (both success and fail) handlers
|
||||
this._completeHandlers = []
|
||||
this._erred = false
|
||||
this._responseArgs = {}
|
||||
|
||||
var self = this
|
||||
, type = o.type || setType(this.url)
|
||||
|
||||
fn = fn || function () {}
|
||||
|
||||
if (o.timeout) {
|
||||
this.timeout = setTimeout(function () {
|
||||
self.abort()
|
||||
}, o.timeout)
|
||||
}
|
||||
|
||||
if (o.success) {
|
||||
this._successHandler = function () {
|
||||
o.success.apply(o, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
if (o.error) {
|
||||
this._errorHandlers.push(function () {
|
||||
o.error.apply(o, arguments)
|
||||
})
|
||||
}
|
||||
|
||||
if (o.complete) {
|
||||
this._completeHandlers.push(function () {
|
||||
o.complete.apply(o, arguments)
|
||||
})
|
||||
}
|
||||
|
||||
function complete (resp) {
|
||||
o.timeout && clearTimeout(self.timeout)
|
||||
self.timeout = null
|
||||
while (self._completeHandlers.length > 0) {
|
||||
self._completeHandlers.shift()(resp)
|
||||
}
|
||||
}
|
||||
|
||||
function success (resp) {
|
||||
resp = (type !== 'jsonp') ? self.request : resp
|
||||
// use global data filter on response text
|
||||
var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type)
|
||||
, r = filteredResponse
|
||||
try {
|
||||
resp.responseText = r
|
||||
} catch (e) {
|
||||
// can't assign this in IE<=8, just ignore
|
||||
}
|
||||
if (r) {
|
||||
switch (type) {
|
||||
case 'json':
|
||||
try {
|
||||
resp = win.JSON ? win.JSON.parse(r) : eval('(' + r + ')')
|
||||
} catch (err) {
|
||||
return error(resp, 'Could not parse JSON in response', err)
|
||||
}
|
||||
break
|
||||
case 'js':
|
||||
resp = eval(r)
|
||||
break
|
||||
case 'html':
|
||||
resp = r
|
||||
break
|
||||
case 'xml':
|
||||
resp = resp.responseXML
|
||||
&& resp.responseXML.parseError // IE trololo
|
||||
&& resp.responseXML.parseError.errorCode
|
||||
&& resp.responseXML.parseError.reason
|
||||
? null
|
||||
: resp.responseXML
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self._responseArgs.resp = resp
|
||||
self._fulfilled = true
|
||||
fn(resp)
|
||||
self._successHandler(resp)
|
||||
while (self._fulfillmentHandlers.length > 0) {
|
||||
resp = self._fulfillmentHandlers.shift()(resp)
|
||||
}
|
||||
|
||||
complete(resp)
|
||||
}
|
||||
|
||||
function error(resp, msg, t) {
|
||||
resp = self.request
|
||||
self._responseArgs.resp = resp
|
||||
self._responseArgs.msg = msg
|
||||
self._responseArgs.t = t
|
||||
self._erred = true
|
||||
while (self._errorHandlers.length > 0) {
|
||||
self._errorHandlers.shift()(resp, msg, t)
|
||||
}
|
||||
complete(resp)
|
||||
}
|
||||
|
||||
this.request = getRequest.call(this, success, error)
|
||||
}
|
||||
|
||||
Reqwest.prototype = {
|
||||
abort: function () {
|
||||
this._aborted = true
|
||||
this.request.abort()
|
||||
}
|
||||
|
||||
, retry: function () {
|
||||
init.call(this, this.o, this.fn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Small deviation from the Promises A CommonJs specification
|
||||
* http://wiki.commonjs.org/wiki/Promises/A
|
||||
*/
|
||||
|
||||
/**
|
||||
* `then` will execute upon successful requests
|
||||
*/
|
||||
, then: function (success, fail) {
|
||||
success = success || function () {}
|
||||
fail = fail || function () {}
|
||||
if (this._fulfilled) {
|
||||
this._responseArgs.resp = success(this._responseArgs.resp)
|
||||
} else if (this._erred) {
|
||||
fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
||||
} else {
|
||||
this._fulfillmentHandlers.push(success)
|
||||
this._errorHandlers.push(fail)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* `always` will execute whether the request succeeds or fails
|
||||
*/
|
||||
, always: function (fn) {
|
||||
if (this._fulfilled || this._erred) {
|
||||
fn(this._responseArgs.resp)
|
||||
} else {
|
||||
this._completeHandlers.push(fn)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* `fail` will execute when the request fails
|
||||
*/
|
||||
, fail: function (fn) {
|
||||
if (this._erred) {
|
||||
fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
|
||||
} else {
|
||||
this._errorHandlers.push(fn)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
function reqwest(o, fn) {
|
||||
return new Reqwest(o, fn)
|
||||
}
|
||||
|
||||
// normalize newline variants according to spec -> CRLF
|
||||
function normalize(s) {
|
||||
return s ? s.replace(/\r?\n/g, '\r\n') : ''
|
||||
}
|
||||
|
||||
function serial(el, cb) {
|
||||
var n = el.name
|
||||
, t = el.tagName.toLowerCase()
|
||||
, optCb = function (o) {
|
||||
// IE gives value="" even where there is no value attribute
|
||||
// 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
|
||||
if (o && !o.disabled)
|
||||
cb(n, normalize(o.attributes.value && o.attributes.value.specified ? o.value : o.text))
|
||||
}
|
||||
, ch, ra, val, i
|
||||
|
||||
// don't serialize elements that are disabled or without a name
|
||||
if (el.disabled || !n) return
|
||||
|
||||
switch (t) {
|
||||
case 'input':
|
||||
if (!/reset|button|image|file/i.test(el.type)) {
|
||||
ch = /checkbox/i.test(el.type)
|
||||
ra = /radio/i.test(el.type)
|
||||
val = el.value
|
||||
// WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
|
||||
;(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
|
||||
}
|
||||
break
|
||||
case 'textarea':
|
||||
cb(n, normalize(el.value))
|
||||
break
|
||||
case 'select':
|
||||
if (el.type.toLowerCase() === 'select-one') {
|
||||
optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
|
||||
} else {
|
||||
for (i = 0; el.length && i < el.length; i++) {
|
||||
el.options[i].selected && optCb(el.options[i])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// collect up all form elements found from the passed argument elements all
|
||||
// the way down to child elements; pass a '<form>' or form fields.
|
||||
// called with 'this'=callback to use for serial() on each element
|
||||
function eachFormElement() {
|
||||
var cb = this
|
||||
, e, i
|
||||
, serializeSubtags = function (e, tags) {
|
||||
var i, j, fa
|
||||
for (i = 0; i < tags.length; i++) {
|
||||
fa = e[byTag](tags[i])
|
||||
for (j = 0; j < fa.length; j++) serial(fa[j], cb)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < arguments.length; i++) {
|
||||
e = arguments[i]
|
||||
if (/input|select|textarea/i.test(e.tagName)) serial(e, cb)
|
||||
serializeSubtags(e, [ 'input', 'select', 'textarea' ])
|
||||
}
|
||||
}
|
||||
|
||||
// standard query string style serialization
|
||||
function serializeQueryString() {
|
||||
return reqwest.toQueryString(reqwest.serializeArray.apply(null, arguments))
|
||||
}
|
||||
|
||||
// { 'name': 'value', ... } style serialization
|
||||
function serializeHash() {
|
||||
var hash = {}
|
||||
eachFormElement.apply(function (name, value) {
|
||||
if (name in hash) {
|
||||
hash[name] && !isArray(hash[name]) && (hash[name] = [hash[name]])
|
||||
hash[name].push(value)
|
||||
} else hash[name] = value
|
||||
}, arguments)
|
||||
return hash
|
||||
}
|
||||
|
||||
// [ { name: 'name', value: 'value' }, ... ] style serialization
|
||||
reqwest.serializeArray = function () {
|
||||
var arr = []
|
||||
eachFormElement.apply(function (name, value) {
|
||||
arr.push({name: name, value: value})
|
||||
}, arguments)
|
||||
return arr
|
||||
}
|
||||
|
||||
reqwest.serialize = function () {
|
||||
if (arguments.length === 0) return ''
|
||||
var opt, fn
|
||||
, args = Array.prototype.slice.call(arguments, 0)
|
||||
|
||||
opt = args.pop()
|
||||
opt && opt.nodeType && args.push(opt) && (opt = null)
|
||||
opt && (opt = opt.type)
|
||||
|
||||
if (opt == 'map') fn = serializeHash
|
||||
else if (opt == 'array') fn = reqwest.serializeArray
|
||||
else fn = serializeQueryString
|
||||
|
||||
return fn.apply(null, args)
|
||||
}
|
||||
|
||||
reqwest.toQueryString = function (o, trad) {
|
||||
var prefix, i
|
||||
, traditional = trad || false
|
||||
, s = []
|
||||
, enc = encodeURIComponent
|
||||
, add = function (key, value) {
|
||||
// If value is a function, invoke it and return its value
|
||||
value = ('function' === typeof value) ? value() : (value == null ? '' : value)
|
||||
s[s.length] = enc(key) + '=' + enc(value)
|
||||
}
|
||||
// If an array was passed in, assume that it is an array of form elements.
|
||||
if (isArray(o)) {
|
||||
for (i = 0; o && i < o.length; i++) add(o[i].name, o[i].value)
|
||||
} else {
|
||||
// If traditional, encode the "old" way (the way 1.3.2 or older
|
||||
// did it), otherwise encode params recursively.
|
||||
for (prefix in o) {
|
||||
buildParams(prefix, o[prefix], traditional, add)
|
||||
}
|
||||
}
|
||||
|
||||
// spaces should be + according to spec
|
||||
return s.join('&').replace(/%20/g, '+')
|
||||
}
|
||||
|
||||
function buildParams(prefix, obj, traditional, add) {
|
||||
var name, i, v
|
||||
, rbracket = /\[\]$/
|
||||
|
||||
if (isArray(obj)) {
|
||||
// Serialize array item.
|
||||
for (i = 0; obj && i < obj.length; i++) {
|
||||
v = obj[i]
|
||||
if (traditional || rbracket.test(prefix)) {
|
||||
// Treat each array item as a scalar.
|
||||
add(prefix, v)
|
||||
} else {
|
||||
buildParams(prefix + '[' + (typeof v === 'object' ? i : '') + ']', v, traditional, add)
|
||||
}
|
||||
}
|
||||
} else if (obj && obj.toString() === '[object Object]') {
|
||||
// Serialize object item.
|
||||
for (name in obj) {
|
||||
buildParams(prefix + '[' + name + ']', obj[name], traditional, add)
|
||||
}
|
||||
|
||||
} else {
|
||||
// Serialize scalar item.
|
||||
add(prefix, obj)
|
||||
}
|
||||
}
|
||||
|
||||
reqwest.getcallbackPrefix = function () {
|
||||
return callbackPrefix
|
||||
}
|
||||
|
||||
// jQuery and Zepto compatibility, differences can be remapped here so you can call
|
||||
// .ajax.compat(options, callback)
|
||||
reqwest.compat = function (o, fn) {
|
||||
if (o) {
|
||||
o.type && (o.method = o.type) && delete o.type
|
||||
o.dataType && (o.type = o.dataType)
|
||||
o.jsonpCallback && (o.jsonpCallbackName = o.jsonpCallback) && delete o.jsonpCallback
|
||||
o.jsonp && (o.jsonpCallback = o.jsonp)
|
||||
}
|
||||
return new Reqwest(o, fn)
|
||||
}
|
||||
|
||||
reqwest.ajaxSetup = function (options) {
|
||||
options = options || {}
|
||||
for (var k in options) {
|
||||
globalSetupOptions[k] = options[k]
|
||||
}
|
||||
}
|
||||
|
||||
return reqwest
|
||||
});
|
||||
@ -4,11 +4,8 @@ var path = typeof _basepath_ === 'string' ? _basepath_ + '/' : '';
|
||||
requirejs.config(
|
||||
{
|
||||
baseUrl: path + 'scripts/',
|
||||
waitSeconds: 5,
|
||||
urlArgs: 'bust=' + ( new Date() ).getTime(),
|
||||
shim: {
|
||||
'lib/delaunay': { exports: 'triangulate' }
|
||||
}
|
||||
waitSeconds: 50,
|
||||
urlArgs: 'bust=' + ( new Date() ).getTime()
|
||||
}
|
||||
);
|
||||
|
||||
@ -19,10 +16,10 @@ require(
|
||||
'src/file',
|
||||
'src/dragdrop',
|
||||
'src/controls',
|
||||
'src/export-png',
|
||||
'src/save-button',
|
||||
'src/export-button',
|
||||
'src/import-button',
|
||||
'src/random-button',
|
||||
'src/upload-imgur',
|
||||
'util/feature-test',
|
||||
'lib/signals-1.0.0'
|
||||
],
|
||||
@ -32,10 +29,10 @@ require(
|
||||
file,
|
||||
dragdrop,
|
||||
controls,
|
||||
png,
|
||||
save_button,
|
||||
export_button,
|
||||
import_button,
|
||||
random_button,
|
||||
imgur,
|
||||
testFeatures,
|
||||
Signal
|
||||
)
|
||||
@ -52,20 +49,19 @@ require(
|
||||
'set-new-src' : new Signal(),
|
||||
'control-set' : new Signal(),
|
||||
'control-updated' : new Signal(),
|
||||
'export-png' : new Signal(),
|
||||
'saved' : new Signal()
|
||||
'image-data-url-requested' : new Signal()
|
||||
}
|
||||
};
|
||||
|
||||
process.init( shared );
|
||||
dragdrop.init( shared );
|
||||
controls.init( shared );
|
||||
png.init( shared );
|
||||
save_button.init( shared );
|
||||
export_button.init( shared );
|
||||
import_button.init( shared );
|
||||
random_button.init( shared );
|
||||
image.init( shared );
|
||||
file.init( shared );
|
||||
imgur.init( shared );
|
||||
}
|
||||
|
||||
function showError( required_features )
|
||||
|
||||
39
scripts/src/export-button.js
Normal file
39
scripts/src/export-button.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*global define*/
|
||||
define(
|
||||
function()
|
||||
{
|
||||
var signals;
|
||||
var export_button;
|
||||
var png_link;
|
||||
|
||||
function init( shared )
|
||||
{
|
||||
signals = shared.signals;
|
||||
export_button = document.getElementById( 'export-button' );
|
||||
png_link = document.getElementById( 'png-button' );
|
||||
|
||||
export_button.addEventListener( 'click', exportButtonClicked, false );
|
||||
png_link.addEventListener( 'click', hidePNGLink, false );
|
||||
}
|
||||
|
||||
function exportButtonClicked( event )
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
signals['image-data-url-requested'].dispatch( upldatePNGLinkAddress );
|
||||
}
|
||||
|
||||
function upldatePNGLinkAddress( data_url )
|
||||
{
|
||||
png_link.href = data_url;
|
||||
png_link.classList.add( 'is-active' );
|
||||
}
|
||||
|
||||
function hidePNGLink()
|
||||
{
|
||||
png_link.classList.remove( 'is-active' );
|
||||
}
|
||||
|
||||
return { init: init };
|
||||
}
|
||||
);
|
||||
@ -1,31 +0,0 @@
|
||||
/*global define*/
|
||||
define(
|
||||
function()
|
||||
{
|
||||
var signals;
|
||||
var png_button;
|
||||
|
||||
function init( shared )
|
||||
{
|
||||
signals = shared.signals;
|
||||
png_button = document.getElementById( 'png-button' );
|
||||
|
||||
signals['export-png'].add( generatePNG );
|
||||
signals['control-updated'].add( hideLink );
|
||||
png_button.addEventListener( 'click', hideLink, false );
|
||||
}
|
||||
|
||||
function generatePNG( data_url )
|
||||
{
|
||||
png_button.href = data_url;
|
||||
png_button.classList.add( 'is-active' );
|
||||
}
|
||||
|
||||
function hideLink()
|
||||
{
|
||||
png_button.classList.remove( 'is-active' );
|
||||
}
|
||||
|
||||
return { init: init };
|
||||
}
|
||||
);
|
||||
@ -22,7 +22,7 @@ define(
|
||||
|
||||
signals['image-loaded'].add( generate );
|
||||
signals['control-updated'].add( controlsUpdated );
|
||||
signals['saved'].add( exportData );
|
||||
signals['image-data-url-requested'].add( exportData );
|
||||
}
|
||||
|
||||
function controlsUpdated( new_values )
|
||||
@ -96,9 +96,12 @@ define(
|
||||
glitched_image_data = null;
|
||||
}
|
||||
|
||||
function exportData()
|
||||
function exportData( callback )
|
||||
{
|
||||
signals['export-png'].dispatch( canvas.toDataURL( 'image/png' ) );
|
||||
if ( typeof callback === 'function' )
|
||||
{
|
||||
callback( canvas.toDataURL( 'image/png' ) );
|
||||
}
|
||||
}
|
||||
|
||||
function getAdjustedValues( new_values )
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
/*global define*/
|
||||
define(
|
||||
function()
|
||||
{
|
||||
var signals;
|
||||
var save_button;
|
||||
|
||||
function init( shared )
|
||||
{
|
||||
signals = shared.signals;
|
||||
save_button = document.getElementById( 'save-button' );
|
||||
|
||||
save_button.addEventListener( 'click', buttonClicked, false );
|
||||
}
|
||||
|
||||
function buttonClicked( event )
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
signals['saved'].dispatch();
|
||||
}
|
||||
|
||||
return { init: init };
|
||||
}
|
||||
);
|
||||
100
scripts/src/upload-imgur.js
Normal file
100
scripts/src/upload-imgur.js
Normal file
@ -0,0 +1,100 @@
|
||||
/*global define*/
|
||||
define(
|
||||
[ 'lib/reqwest' ],
|
||||
function( reqwest, $ )
|
||||
{
|
||||
var signals;
|
||||
var imgur_button;
|
||||
var imgur_url_container;
|
||||
var imgur_url_input;
|
||||
var imgur_url_link;
|
||||
var imgur_url_error;
|
||||
var is_uploading = false;
|
||||
|
||||
function init( shared )
|
||||
{
|
||||
signals = shared.signals;
|
||||
imgur_button = document.getElementById( 'imgur-button' );
|
||||
imgur_url_container = document.getElementById( 'imgur-url-container' );
|
||||
imgur_url_input = document.getElementById( 'imgur-url-input' );
|
||||
imgur_url_link = document.getElementById( 'imgur-url-link' );
|
||||
imgur_url_error = document.getElementById( 'imgur-url-error' );
|
||||
|
||||
imgur_button.addEventListener( 'click', buttonClicked, false );
|
||||
imgur_url_input.addEventListener( 'click', selectInput, false );
|
||||
}
|
||||
|
||||
function buttonClicked( event )
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
if ( ! is_uploading )
|
||||
{
|
||||
signals['image-data-url-requested'].dispatch( upload );
|
||||
|
||||
imgur_url_container.classList.remove( 'is-active', 'upload-failed', 'upload-successful' );
|
||||
}
|
||||
}
|
||||
|
||||
function selectInput()
|
||||
{
|
||||
imgur_url_input.select();
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/questions/17805456/upload-a-canvas-image-to-imgur-api-v3-with-javascript
|
||||
function upload( data_url )
|
||||
{
|
||||
if ( ! is_uploading )
|
||||
{
|
||||
imgur_button.classList.add( 'is-uploading' );
|
||||
|
||||
is_uploading = true;
|
||||
|
||||
reqwest(
|
||||
{
|
||||
url: 'https://api.imgur.com/3/image.json',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Client-ID a4c24380d884932'
|
||||
},
|
||||
data: {
|
||||
image: data_url.split( ',' )[1],
|
||||
type: 'base64'
|
||||
},
|
||||
type: 'json',
|
||||
crossOrigin: true,
|
||||
success: imageUploaded,
|
||||
error: uploadFailed
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function imageUploaded( response )
|
||||
{
|
||||
is_uploading = false;
|
||||
|
||||
if ( response && response.data && response.data.link )
|
||||
{
|
||||
imgur_button.classList.remove( 'is-uploading' );
|
||||
imgur_url_input.setAttribute( 'value', response.data.link );
|
||||
imgur_url_link.href = response.data.link;
|
||||
imgur_url_container.classList.add( 'is-active', 'upload-successful' );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
uploadFailed();
|
||||
}
|
||||
}
|
||||
|
||||
function uploadFailed( response )
|
||||
{
|
||||
is_uploading = false;
|
||||
imgur_button.classList.remove( 'is-uploading' );
|
||||
imgur_url_container.classList.add( 'is-active', 'upload-failed' );
|
||||
}
|
||||
|
||||
return { init: init };
|
||||
}
|
||||
);
|
||||
@ -42,12 +42,14 @@ a:hover
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.button:hover
|
||||
{
|
||||
background-color: #06f;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#random-button
|
||||
@ -148,6 +150,91 @@ a:hover
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
#imgur-button
|
||||
{
|
||||
width: 85px;
|
||||
}
|
||||
|
||||
#imgur-button.is-uploading,
|
||||
#imgur-button.is-uploading:hover
|
||||
{
|
||||
background-color: #eaeaea;
|
||||
color: #06f;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#imgur-button span
|
||||
{
|
||||
display: block;
|
||||
width: 154px;
|
||||
transition: margin-left 0.5s ease-in;
|
||||
transition-property: margin-left top;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
#imgur-button.is-uploading span
|
||||
{
|
||||
margin-left: -76px;
|
||||
}
|
||||
|
||||
#imgur-button span::after
|
||||
{
|
||||
content: 'loading…';
|
||||
display: inline-block;
|
||||
padding-left: 15px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#imgur-url-container
|
||||
{
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in;
|
||||
}
|
||||
|
||||
#imgur-url-container.is-active
|
||||
{
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#imgur-url-input
|
||||
{
|
||||
padding: 4px 9px;
|
||||
border: 1px #CCC solid;
|
||||
border-radius: 3px;
|
||||
font-family: sans-serif;
|
||||
font-size: 13px;
|
||||
color: #7C7C7C;
|
||||
}
|
||||
|
||||
#imgur-url-error
|
||||
{
|
||||
padding: 5px 9px;
|
||||
line-height: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#imgur-url-input,
|
||||
#imgur-url-link,
|
||||
#imgur-url-error
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#imgur-url-container.upload-successful #imgur-url-input,
|
||||
#imgur-url-container.upload-successful #imgur-url-link
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#imgur-url-container.upload-failed #imgur-url-error
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.missing-feature
|
||||
{
|
||||
clear: both;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user