Last active
December 31, 2015 05:49
-
-
Save lastobelus/7943705 to your computer and use it in GitHub Desktop.
An asynchronous, debounced, optionally caching validator for ember-validations (requires my patch in pull request 64)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var UrlExists = Ember.Object.extend({ | |
test: function(url){ | |
var promise = Ember.Deferred.create(); | |
if(Ember.isEmpty(url)){ | |
promise.reject(false); | |
} else { | |
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+ | |
"q=select%20*%20from%20html%20where%20url%3D%22"+ | |
encodeURIComponent(url)+"%22&format=json'&callback=?", | |
function(data){ | |
if(data.results[0]){ | |
promise.resolve(true); | |
} else { | |
promise.reject(false); | |
} | |
} | |
).fail(function() { | |
promise.reject(false); | |
}); | |
} | |
return promise; | |
} | |
}).create(); | |
Ember.Validations.validators.local.UrlExists = Ember.Validations.validators.Base.extend({ | |
init: function() { | |
this._super(); | |
/*jshint expr:true*/ | |
if (this.options === true) { | |
this.options = {}; | |
} | |
if (this.options.message === undefined) { | |
this.options.message = "must be a valid URL" | |
} | |
if (this.options.debounce === undefined){ | |
this.options.debounce = 200; | |
} | |
if (this.options.caches === undefined) { | |
this.options.caches = true; | |
} | |
this.options.debounce = parseInt(this.options.debounce); | |
}, | |
promise: null, | |
inflightValidations: {}, | |
UrlExists: UrlExists, | |
pending: null, | |
call: function() { | |
var promise = this.get('promise'); | |
var self = this; | |
if(Ember.isNone(promise)){ | |
promise = Ember.Deferred.create(); | |
this.set('promise', promise); | |
} | |
// we need a stop-and-go because two call->_call->resolve chains can overlap | |
this.set('pending', Ember.Deferred.create()); | |
Ember.run.debounce(this, this._call, this.options.debounce); | |
return promise; | |
}, | |
resolveValidation: function(value, result){ | |
var inflightValidations = this.get('inflightValidations'); | |
inflightValidations[value] = result; | |
var self = this; | |
this.get('pending').then(function() { | |
self.settle(); | |
}) | |
}, | |
settle: function() { | |
var promise = this.get('promise'); | |
var currentValue = this.model.get(this.property); | |
var inflightValidations = this.get('inflightValidations'); | |
var finished = Ember.keys(inflightValidations).every(function(value){ | |
return undefined === inflightValidations[value].then; | |
}); | |
if(finished){ | |
if(inflightValidations.hasOwnProperty(currentValue)){ | |
if( inflightValidations[currentValue] === false ){ | |
this.errors.pushObject(this.options.message); | |
} | |
promise.resolve(); | |
this.set('promise', null); | |
} else { | |
// currentValue got ahead | |
this.call(); | |
} | |
} | |
}, | |
_call: function() { | |
this.get('pending').resolve(); | |
var self = this; | |
var value = this.model.get(this.property); | |
var inflightValidations = this.get('inflightValidations'); | |
if(this.options.caches && inflightValidations[value] && (undefined === inflightValidations[value].then)){ | |
this.settle(); | |
return; | |
} | |
inflightValidations[value] = this.UrlExists.test(value).then( | |
function() { | |
self.resolveValidation(value, true); | |
}, | |
function() { | |
self.resolveValidation(value, false); | |
} | |
); | |
} | |
}); | |
module.exports = UrlExists; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment