Commit 6373a817 authored by Sven Franck's avatar Sven Franck

updated 3rd party plugins to latest version

parent 3da91715
// HACKED badly (XXX) to support promise callbacks
/**
* @hello.js
*
......@@ -396,7 +397,15 @@ hello.utils.extend( hello, {
// Trigger callback
var popup = window.open(
url,
//
// OAuth redirect, fixes URI fragments from being lost in Safari
// (URI Fragments within 302 Location URI are lost over HTTPS)
// Loading the redirect.html before triggering the OAuth Flow seems to fix it.
//
// FIREFOX, decodes URL fragments when calling location.hash.
// - This is bad if the value contains break points which are escaped
// - Hence the url must be encoded twice as it contains breakpoints.
p.qs.redirect_uri + "#oauth_redirect=" + encodeURIComponent(encodeURIComponent(url)),
'Authentication',
"resizeable=true,height=" + windowHeight + ",width=" + windowWidth + ",left="+((window.innerWidth-windowWidth)/2)+",top="+((window.innerHeight-windowHeight)/2)
);
......@@ -490,6 +499,7 @@ hello.utils.extend( hello, {
// @param string optional, name of the service to get information about.
//
getAuthResponse : function(service){
// If the service doesn't exist
service = service || this.settings.default_service;
......@@ -500,6 +510,7 @@ hello.utils.extend( hello, {
}});
return null;
}
return this.utils.store(service) || null;
},
......@@ -555,8 +566,8 @@ hello.utils.extend( hello.utils, {
m = s.replace(/^[\#\?]/,'').match(/([^=\/\&]+)=([^\&]+)/g);
if(m){
for(var i=0;i<m.length;i++){
b = m[i].split('=');
a[b[0]] = decodeURIComponent( b[1] );
b = m[i].match(/([^=]+)=(.*)/);
a[b[1]] = decodeURIComponent( b[2] );
}
}
return a;
......@@ -706,6 +717,7 @@ hello.utils.extend( hello.utils, {
x = null;
// define x
// x is the first key in the list of object parameters
for(x in o){if(o.hasOwnProperty(x)){
break;
}}
......@@ -713,8 +725,17 @@ hello.utils.extend( hello.utils, {
// Passing in hash object of arguments?
// Where the first argument can't be an object
if((args.length===1)&&(typeof(args[0])==='object')&&o[x]!='o!'){
// return same hash.
return args[0];
// Could this object still belong to a property?
// Check the object keys if they match any of the property keys
for(x in args[0]){if(o.hasOwnProperty(x)){
// Does this key exist in the property list?
if( x in o ){
// Yes this key does exist so its most likely this function has been invoked with an object parameter
// return first argument as the hash of all arguments
return args[0];
}
}}
}
// else loop through and account for the missing ones.
......@@ -979,6 +1000,7 @@ hello.utils.extend( hello.utils, {
return this;
};
// XXX HACK to badly support then()
this.success = this.done = this.then = function(callback){
return this.on("success",callback);
};
......@@ -1186,6 +1208,13 @@ hello.unsubscribe = hello.off;
var utils = hello.utils,
location = window.location;
var debug = function(msg,e){
utils.append("p", {text:msg}, document.documentElement);
if(e){
console.log(e);
}
};
//
// AuthCallback
// Trigger a callback to authenticate
......@@ -1212,15 +1241,38 @@ hello.unsubscribe = hello.off;
delete obj.callback;
}catch(e){}
// Call the globalEvent function on the parent
win[cb](obj);
// Update store
utils.store(obj.network,obj);
// Call the globalEvent function on the parent
if(cb in win){
try{
win[cb](obj);
}
catch(e){
debug("Error thrown whilst executing parent callback", e);
return;
}
}
else{
debug("Error: Callback missing from parent window, snap!");
return;
}
}
window.close();
hello.emit("notice",'Trying to close window');
// Close this current window
try{
window.close();
}
catch(e){}
// IOS bug wont let us clos it if still loading
window.addEventListener('load', function(){
window.close();
});
debug("Trying to close window");
// Dont execute any more
return;
......@@ -1233,7 +1285,8 @@ hello.unsubscribe = hello.off;
//
// FACEBOOK is returning auth errors within as a query_string... thats a stickler for consistency.
// SoundCloud is the state in the querystring and the token in the hashtag, so we'll mix the two together
var p = utils.merge(hello.utils.param(location.search||''), utils.param(location.hash||''));
var p = utils.merge(utils.param(location.search||''), utils.param(location.hash||''));
// if p.state
......@@ -1245,7 +1298,7 @@ hello.unsubscribe = hello.off;
var a = JSON.parse(p.state);
p = utils.merge(p, a);
}catch(e){
hello.emit("error", "Could not decode state parameter");
debug("Could not decode state parameter");
}
// access_token?
......@@ -1289,6 +1342,14 @@ hello.unsubscribe = hello.off;
}
}
}
//
// OAuth redirect, fixes URI fragments from being lost in Safari
// (URI Fragments within 302 Location URI are lost over HTTPS)
// Loading the redirect.html before triggering the OAuth Flow seems to fix it.
else if("oauth_redirect" in p){
window.location = decodeURIComponent(p.oauth_redirect);
return;
}
// redefine
p = utils.param(location.search);
......@@ -1337,6 +1398,7 @@ hello.api = function(){
var self = this.use(),
utils = self.utils;
// Reference arguments
self.args = p;
......@@ -1450,6 +1512,11 @@ hello.api = function(){
}});
}
//
// Get the current session
var session = self.getAuthResponse(p.network);
//
// Given the path trigger the fix
processPath(p.path);
......@@ -1572,7 +1639,12 @@ hello.api = function(){
o.jsonp(p,qs);
}
// Is self still a post?
// Does this provider have a custom method?
if("api" in o && o.api( url, p, {access_token:session.access_token}, callback ) ){
return;
}
// Is method still a post?
if( p.method === 'post' ){
// Add some additional query parameters to the URL
......@@ -1615,8 +1687,7 @@ hello.api = function(){
function _sign(network, path, method, data, modifyQueryString, callback){
// OAUTH SIGNING PROXY
var session = self.getAuthResponse(network),
service = self.services[network],
var service = self.services[network],
token = (session ? session.access_token : null);
// Is self an OAuth1 endpoint
......@@ -1685,7 +1756,7 @@ hello.utils.extend( hello.utils, {
// Create a clone of an object
clone : function(obj){
if("nodeName" in obj){
return obj[x];
return obj;
}
var clone = {}, x;
for(x in obj){
......@@ -1763,7 +1834,7 @@ hello.utils.extend( hello.utils, {
}
data = null;
}
else if( data && typeof(data) !== 'string' && !(data instanceof FormData)){
else if( data && typeof(data) !== 'string' && !(data instanceof FormData) && !(data instanceof File) && !(data instanceof Blob)){
// Loop through and add formData
var f = new FormData();
for( x in data )if(data.hasOwnProperty(x)){
......@@ -1772,6 +1843,9 @@ hello.utils.extend( hello.utils, {
f.append(x, data[x].files[0]);
}
}
else if(data[x] instanceof Blob){
f.append(x, data[x], data.name);
}
else{
f.append(x, data[x]);
}
......@@ -2182,8 +2256,6 @@ hello.utils.extend( hello.utils, {
}
return false;
}
});
......@@ -2360,7 +2432,7 @@ function format_file(o){
o.file = 'https://api-content.dropbox.com/1/files/'+ path;
}
if(!o.id){
o.id = o.name;
o.id = o.path.replace(/^\//,'');
}
// o.media = "https://api-content.dropbox.com/1/files/" + path;
}
......@@ -2373,6 +2445,18 @@ function req(str){
};
}
function dataURItoBlob(dataURI) {
var reg = /^data\:([^;,]+(\;charset=[^;,]+)?)(\;base64)?,/i;
var m = dataURI.match(reg);
var binary = atob(dataURI.replace(reg,''));
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: m[1]});
}
hello.init({
'dropbox' : {
......@@ -2419,7 +2503,7 @@ hello.init({
"me" : 'account/info',
// https://www.dropbox.com/developers/core/docs#metadata
"me/files" : req("metadata/@{root|sandbox}/"),
"me/files" : req("metadata/@{root|sandbox}/@{parent}"),
"me/folder" : req("metadata/@{root|sandbox}/@{id}"),
"me/folders" : req('metadata/@{root|sandbox}/'),
......@@ -2434,13 +2518,18 @@ hello.init({
post : {
"me/files" : function(p,callback){
var path = p.data.id,
var path = p.data.parent,
file_name = p.data.name;
p.data = {
file : p.data.file
};
// Does this have a data-uri to upload as a file?
if( typeof( p.data.file ) === 'string' ){
p.data.file = dataURItoBlob(p.data.file);
}
callback('https://api-content.dropbox.com/1/files_put/@{root|sandbox}/'+path+"/"+file_name);
},
"me/folders" : function(p, callback){
......@@ -2453,6 +2542,14 @@ hello.init({
}));
}
},
// Map DELETE requests
del : {
"me/files" : "fileops/delete?root=@{root|sandbox}&path=@{id}",
"me/folder" : "fileops/delete?root=@{root|sandbox}&path=@{id}"
},
wrap : {
me : function(o){
formatError(o);
......@@ -2481,18 +2578,34 @@ hello.init({
format_file(o);
if(o.is_deleted){
o.success = true;
}
return o;
}
},
// doesn't return the CORS headers
xhr : function(p){
// forgetting content DropBox supports the allow-cross-origin-resource
if(p.path.match("https://api-content.dropbox.com/")){
//p.data = p.data.file.files[0];
return false;
// the proxy supports allow-cross-origin-resource
// alas that's the only thing we're using.
if( p.data && p.data.file ){
var file = p.data.file;
if( file ){
if(file.files){
p.data = file.files[0];
}
else{
p.data = file;
}
}
}
else if(p.path.match("me/files")&&p.method==='post'){
return true;
if(p.method==='delete'){
// Post delete operations
p.method = 'post';
}
return true;
}
......@@ -2553,7 +2666,7 @@ hello.init({
// REF: http://developers.facebook.com/docs/reference/dialogs/oauth/
oauth : {
version : 2,
auth : 'http://www.facebook.com/dialog/oauth/'
auth : 'https://www.facebook.com/dialog/oauth/'
},
// Authorization scopes
......@@ -2603,7 +2716,12 @@ hello.init({
// Map DELETE requests
del : {
//'me/album' : '@{id}'
/*
// Can't delete an album
// http://stackoverflow.com/questions/8747181/how-to-delete-an-album
'me/album' : '@{id}'
*/
'me/photo' : '@{id}'
},
wrap : {
......@@ -2621,20 +2739,20 @@ hello.init({
if(p.method==='get'||p.method==='post'){
qs.suppress_response_codes = true;
}
else if(p.method === "delete"){
qs.method = 'delete';
p.method = "post";
}
return true;
},
// Special requirements for handling JSONP fallback
jsonp : function(p){
jsonp : function(p,qs){
var m = p.method.toLowerCase();
if( m !== 'get' && !hello.utils.hasBinary(p.data) ){
p.data.method = m;
p.method = 'get';
}
else if(p.method === "delete"){
qs.method = 'delete';
p.method = "post";
}
},
// Special requirements for iframe form hack
......@@ -3041,7 +3159,7 @@ hello.init({
//
// GOOGLE API
//
(function(hello){
(function(hello, window){
"use strict";
......@@ -3210,6 +3328,295 @@ hello.init({
}
}
//
// Misc
var utils = hello.utils;
// Multipart
// Construct a multipart message
function Multipart(){
// Internal body
var body = [],
boundary = (Math.random()*1e10).toString(32),
counter = 0,
line_break = "\r\n",
delim = line_break + "--" + boundary,
ready = function(){},
data_uri = /^data\:([^;,]+(\;charset=[^;,]+)?)(\;base64)?,/i;
// Add File
function addFile(item){
var fr = new FileReader();
fr.onload = function(e){
//addContent( e.target.result, item.type );
addContent( btoa(e.target.result), item.type + line_break + "Content-Transfer-Encoding: base64");
};
fr.readAsBinaryString(item);
}
// Add content
function addContent(content, type){
body.push(line_break + 'Content-Type: ' + type + line_break + line_break + content);
counter--;
ready();
}
// Add new things to the object
this.append = function(content, type){
// Does the content have an array
if(typeof(content) === "string" || !('length' in Object(content)) ){
// converti to multiples
content = [content];
}
for(var i=0;i<content.length;i++){
counter++;
var item = content[i];
// Is this a file?
// Files can be either Blobs or File types
if(item instanceof window.File || item instanceof window.Blob){
// Read the file in
addFile(item);
}
// Data-URI?
// data:[<mime type>][;charset=<charset>][;base64],<encoded data>
// /^data\:([^;,]+(\;charset=[^;,]+)?)(\;base64)?,/i
else if( typeof( item ) === 'string' && item.match(data_uri) ){
var m = item.match(data_uri);
addContent(item.replace(data_uri,''), m[1] + line_break + "Content-Transfer-Encoding: base64");
}
// Regular string
else{
addContent(item, type);
}
}
};
this.onready = function(fn){
ready = function(){
if( counter===0 ){
// trigger ready
body.unshift('');
body.push('--');
fn( body.join(delim), boundary);
body = [];
}
};
ready();
};
}
//
// Events
//
var addEvent, removeEvent;
if(document.removeEventListener){
addEvent = function(elm, event_name, callback){
elm.addEventListener(event_name, callback);
};
removeEvent = function(elm, event_name, callback){
elm.removeEventListener(event_name, callback);
};
}
else if(document.detachEvent){
removeEvent = function (elm, event_name, callback){
elm.detachEvent("on"+event_name, callback);
};
addEvent = function (elm, event_name, callback){
elm.attachEvent("on"+event_name, callback);
};
}
//
// postMessage
// This is used whereby the browser does not support CORS
//
var xd_iframe, xd_ready, xd_id, xd_counter, xd_queue=[];
function xd(method, url, headers, body, callback){
// This is the origin of the Domain we're opening
var origin = 'https://content.googleapis.com';
// Is this the first time?
if(!xd_iframe){
// ID
xd_id = String(parseInt(Math.random()*1e8,10));
// Create the proxy window
xd_iframe = utils.append('iframe', { src : origin + "/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.mMZgig4ibk0.O%2Fm%3D__features__%2Fam%3DEQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAItRSTNZBJcXGialq7mfSUkqsE3kvYwkpQ#parent="+window.location.origin+"&rpctoken="+xd_id,
style : {position:'absolute',left:"-1000px",bottom:0,height:'1px',width:'1px'} }, 'body');
// Listen for on ready events
// Set the window listener to handle responses from this
addEvent( window, "message", function CB(e){
// Try a callback
if(e.origin !== origin){
return;
}
var json;
try{
json = JSON.parse(e.data);
}
catch(ee){
// This wasn't meant to be
return;
}
// Is this the right implementation?
if(json && json.s && json.s === "ready:"+xd_id){
// Yes, it is.
// Lets trigger the pending operations
xd_ready = true;
xd_counter = 0;
for(var i=0;i<xd_queue.length;i++){
xd_queue[i]();
}
}
});
}
//
// Action
// This is the function to call if/once the proxy has successfully loaded
// If makes a call to the IFRAME
var action = function(){
var nav = window.navigator,
position = ++xd_counter,
qs = utils.param(url.match(/\?.+/)[0]);
var token = qs.access_token;
delete qs.access_token;
// The endpoint is ready send the response
var message = JSON.stringify({
"s":"makeHttpRequests",
"f":"..",
"c":position,
"a":[[{
"key":"gapiRequest",
"params":{
"url":url.replace(/(^https?\:\/\/[^\/]+|\?.+$)/,''), // just the pathname
"httpMethod":method.toUpperCase(),
"body": body,
"headers":{
"Authorization":":Bearer "+token,
"Content-Type":headers['content-type'],
"X-Origin":window.location.origin,
"X-ClientDetails":"appVersion="+nav.appVersion+"&platform="+nav.platform+"&userAgent="+nav.userAgent
},
"urlParams": qs,
"clientName":"google-api-javascript-client",
"clientVersion":"1.1.0-beta"
}
}]],
"t":xd_id,
"l":false,
"g":true,
"r":".."
});
addEvent( window, "message", function CB2(e){
if(e.origin !== origin ){
// not the incoming message we're after
return;
}
// Decode the string
try{
var json = JSON.parse(e.data);
if( json.t === xd_id && json.a[0] === position ){
removeEvent( window, "message", CB2);
callback(JSON.parse(JSON.parse(json.a[1]).gapiRequest.data.body));
}
}
catch(ee){
callback({
error: {
code : "request_error",
message : "Failed to post to Google"
}
});
}
});
// Post a message to iframe once it has loaded
xd_iframe.contentWindow.postMessage(message, '*');
};
//
// Check to see if the proy has loaded,
// If it has then action()!
// Otherwise, xd_queue until the proxy has loaded
if(xd_ready){
action();
}
else{
xd_queue.push(action);
}
}
/**/
//
// Upload to Drive
// If this is PUT then only augment the file uploaded
// PUT https://developers.google.com/drive/v2/reference/files/update
// POST https://developers.google.com/drive/manage-uploads
function uploadDrive(p, callback){
var data = {};
if( p.data && p.data instanceof window.HTMLInputElement ){
p.data = { file : p.data };
}
if( !p.data.name && Object(Object(p.data.file).files).length && p.method === 'post' ){
p.data.name = p.data.file.files[0].name;
}
if(p.method==='post'){
p.data = {
"title": p.data.name,
"parents": [{"id":p.data.parent||'root'}],
"file" : p.data.file
};
}
else{
// Make a reference
data = p.data;
p.data = {};
// Add the parts to change as required
if( data.parent ){
p.data["parents"] = [{"id":p.data.parent||'root'}];
}
if( data.file ){
p.data.file = data.file;
}
if( data.name ){
p.data.title = data.name;
}
}
callback('upload/drive/v2/files'+( data.id ? '/' + data.id : '' )+'?uploadType=multipart');
}
//
// URLS
......@@ -3278,15 +3685,49 @@ hello.init({
'me/photos' : 'https://picasaweb.google.com/data/feed/api/user/default?alt=json&kind=photo&max-results=@{limit|100}&start-index=@{start|1}',
// https://developers.google.com/drive/v2/reference/files/list
'me/files' : 'drive/v2/files?q=%22root%22+in+parents&maxResults=@{limit|100}'
'me/files' : 'drive/v2/files?q=%22@{parent|root}%22+in+parents+and+trashed=false&maxResults=@{limit|100}',
// https://developers.google.com/drive/v2/reference/files/list
'me/folders' : 'drive/v2/files?q=%22@{id|root}%22+in+parents+and+mimeType+=+%22application/vnd.google-apps.folder%22+and+trashed=false&maxResults=@{limit|100}',
// https://developers.google.com/drive/v2/reference/files/list
'me/folder' : 'drive/v2/files?q=%22@{id|root}%22+in+parents+and+trashed=false&maxResults=@{limit|100}'
},
// Map post requests
post : {
// 'me/albums' : 'https://picasaweb.google.com/data/feed/api/user/default?alt=json'
/*
// PICASA
'me/albums' : function(p, callback){
p.data = {
"title": p.data.name,
"summary": p.data.description,
"category": 'http://schemas.google.com/photos/2007#album'
};
callback('https://picasaweb.google.com/data/feed/api/user/default?alt=json');
},
*/
// DRIVE
'me/files' : uploadDrive,
'me/folders' : function(p, callback){
p.data = {
"title": p.data.name,
"parents": [{"id":p.data.parent||'root'}],
"mimeType": "application/vnd.google-apps.folder"
};
callback('drive/v2/files');
}
},
// Map post requests
put : {
'me/files' : uploadDrive
},
// Map DELETE requests
del : {
'me/files' : 'drive/v2/files/@{id}',
'me/folder' : 'drive/v2/files/@{id}'
},
wrap : {
......@@ -3321,14 +3762,112 @@ hello.init({
'default' : gEntry
},
xhr : function(p){
if(p.method==='post'){
return false;
// Post
if(p.method==='post'||p.method==='put'){
// Does this contain binary data?
if( p.data && utils.hasBinary(p.data) || p.data.file ){
// There is support for CORS via Access Control headers
// ... unless otherwise stated by post/put handlers
p.cors_support = p.cors_support || true;
// There is noway, as it appears, to Upload a file along with its meta data
// So lets cancel the typical approach and use the override '{ api : function() }' below
return false;
}
// Convert the POST into a javascript object
p.data = JSON.stringify(p.data);
p.headers = {
'content-type' : 'application/json'
};
}
return true;
},
//
// Custom API handler, overwrites the default fallbacks
// Performs a postMessage Request
//
api : function(url,p,qs,callback){
// Dont use this function for GET requests
if(p.method==='get'){
return;
}
// Contain inaccessible binary data?
// If there is no "files" property on an INPUT then we can't get the data
if( "file" in p.data && utils.domInstance('input', p.data.file ) && !( "files" in p.data.file ) ){
callback({
error : {
code : 'request_invalid',
message : "Sorry, can't upload your files to Google Drive in this browser"
}
});
}
// Extract the file, if it exists from the data object
// If the File is an INPUT element lets just concern ourselves with the NodeList
var file;
if( "file" in p.data ){
file = p.data.file;
delete p.data.file;
if( typeof(file)==='object' && "files" in file){
// Assign the NodeList
file = file.files;
}
if(!file || !file.length){
callback({
error : {
code : 'request_invalid',
message : 'There were no files attached with this request to upload'
}
});
return;
}
}
// p.data.mimeType = Object(file[0]).type || 'application/octet-stream';
// Construct a multipart message
var parts = new Multipart();
parts.append( JSON.stringify(p.data), 'application/json');
// Read the file into a base64 string... yep a hassle, i know
// FormData doesn't let us assign our own Multipart headers and HTTP Content-Type
// Alas GoogleApi need these in a particular format
if(file){
parts.append( file );
}
parts.onready(function(body, boundary){
// Does this userAgent and endpoint support CORS?
if( p.cors_support ){
// Deliver via
utils.xhr( p.method, utils.qs(url,qs), {
'content-type' : 'multipart/related; boundary="'+boundary+'"'
}, body, callback );
}
else{
// Otherwise lets POST the data the good old fashioned way postMessage
xd( p.method, utils.qs(url,qs), {
'content-type' : 'multipart/related; boundary="'+boundary+'"'
}, body, callback );
}
});
return true;
}
}
});
})(hello);
})(hello, window);
//
// Instagram
//
......@@ -3834,6 +4373,17 @@ function formatFriends(o){
return o;
}
function dataURItoBlob(dataURI) {
var reg = /^data\:([^;,]+(\;charset=[^;,]+)?)(\;base64)?,/i;
var m = dataURI.match(reg);
var binary = atob(dataURI.replace(reg,''));
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: m[1]});
}
hello.init({
windows : {
name : 'Windows live',
......@@ -3852,7 +4402,7 @@ hello.init({
events : 'wl.calendars',
photos : 'wl.photos',
videos : 'wl.photos',
friends : '',
friends : 'wl.contacts_emails',
files : 'wl.skydrive',
publish : 'wl.share',
......@@ -3870,7 +4420,7 @@ hello.init({
// Friends
"me" : "me",
"me/friends" : "me/friends",
"me/following" : "me/friends",
"me/following" : "me/contacts",
"me/followers" : "me/friends",
"me/albums" : 'me/albums',
......@@ -3880,7 +4430,7 @@ hello.init({
"me/photo" : '@{id}',
// FILES
"me/files" : '@{id|me/skydrive}/files',
"me/files" : '@{parent|me/skydrive}/files',
"me/folders" : '@{id|me/skydrive}/files',
"me/folder" : '@{id|me/skydrive}/files'
......@@ -3888,19 +4438,19 @@ hello.init({
// Map POST requests
post : {
"me/feed" : "me/share",
"me/share" : "me/share",
"me/albums" : "me/albums",
"me/album" : "@{id}/files",
"me/folders" : '@{id|me/skydrive/}',
"me/files" : "@{id|me/skydrive/}/files"
"me/files" : "@{parent|me/skydrive/}/files"
},
// Map DELETE requests
del : {
// Include the data[id] in the path
"me/album" : '@{id}',
"me/photo" : '@{id}',
"me/folder" : '@{id}',
"me/files" : '@{id}'
},
......@@ -3933,7 +4483,21 @@ hello.init({
return o;
}
},
xhr : false,
xhr : function(p){
if( p.method !== 'get' && p.method !== 'delete' && !hello.utils.hasBinary(p.data) ){
// Does this have a data-uri to upload as a file?
if( typeof( p.data.file ) === 'string' ){
p.data.file = dataURItoBlob(p.data.file);
}else{
p.data = JSON.stringify(p.data);
p.headers = {
'Content-Type' : 'application/json'
};
}
}
return true;
},
jsonp : function(p){
if( p.method.toLowerCase() !== 'get' && !hello.utils.hasBinary(p.data) ){
//p.data = {data: JSON.stringify(p.data), method: p.method.toLowerCase()};
......@@ -4004,7 +4568,7 @@ function paging(res){
}
var yql = function(q){
return 'http://query.yahooapis.com/v1/yql?q=' + (q + ' limit @{limit|100} offset @{start|0}').replace(" ", '%20') + "&format=json";
return 'https://query.yahooapis.com/v1/yql?q=' + (q + ' limit @{limit|100} offset @{start|0}').replace(/\s/g, '%20') + "&format=json";
};
hello.init({
......@@ -4041,9 +4605,9 @@ hello.init({
base : "https://social.yahooapis.com/v1/",
get : {
"me" : yql('select * from social.profile where guid=me'),
"me/friends" : yql('select * from social.contacts where guid=me'),
"me/following" : yql('select * from social.contacts where guid=me')
"me" : yql('select * from social.profile(0) where guid=me'),
"me/friends" : yql('select * from social.contacts(0) where guid=me'),
"me/following" : yql('select * from social.contacts(0) where guid=me')
},
wrap : {
me : function(o){
......
// i18next, v1.7.1
// Copyright (c)2013 Jan Mühlemann (jamuhl).
// i18next, v1.7.2
// Copyright (c)2014 Jan Mühlemann (jamuhl).
// Distributed under MIT license
// http://i18next.com
(function() {
......@@ -37,7 +37,7 @@
return -1;
}
}
// add lastIndexOf to non ECMA-262 standard compliant browsers
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
......@@ -79,7 +79,7 @@
, initialized = false;
// Export the i18next object for **CommonJS**.
// Export the i18next object for **CommonJS**.
// If we're not in CommonJS, add `i18n` to the
// global object or to jquery.
if (typeof module !== 'undefined' && module.exports) {
......@@ -88,7 +88,7 @@
if ($) {
$.i18n = $.i18n || i18n;
}
root.i18n = root.i18n || i18n;
}
// defaults
......@@ -103,27 +103,28 @@
detectLngQS: 'setLng',
ns: 'translation',
fallbackOnNull: true,
fallbackOnEmpty: false,
fallbackToDefaultNS: false,
nsseparator: ':',
keyseparator: '.',
selectorAttr: 'data-i18n',
debug: false,
resGetPath: 'locales/__lng__/__ns__.json',
resPostPath: 'locales/add/__lng__/__ns__',
getAsync: true,
postAsync: true,
resStore: undefined,
useLocalStorage: false,
localStorageExpirationTime: 7*24*60*60*1000,
dynamicLoad: false,
sendMissing: false,
sendMissingTo: 'fallback', // current | all
sendType: 'POST',
interpolationPrefix: '__',
interpolationSuffix: '__',
reusePrefix: '$t(',
......@@ -132,7 +133,7 @@
pluralNotFound: ['plural_not_found', Math.random()].join(''),
contextNotFound: ['context_not_found', Math.random()].join(''),
escapeInterpolation: false,
setJqueryExt: true,
defaultValueFromContent: true,
useDataAttrOptions: false,
......@@ -140,26 +141,27 @@
useCookie: true,
cookieName: 'i18next',
cookieDomain: undefined,
objectTreeKeyHandler: undefined,
postProcess: undefined,
parseMissingKey: undefined,
shortcutFunction: 'sprintf' // or: defaultValue
};
function _extend(target, source) {
if (!source || typeof source === 'function') {
return target;
}
for (var attr in source) { target[attr] = source[attr]; }
return target;
}
function _each(object, callback, args) {
var name, i = 0,
length = object.length,
isObj = length === undefined || typeof object === "function";
if (args) {
if (isObj) {
for (name in object) {
......@@ -174,7 +176,7 @@
}
}
}
// A special, fast, case for the most common use of each
} else {
if (isObj) {
......@@ -191,10 +193,10 @@
}
}
}
return object;
}
var _entityMap = {
"&": "&amp;",
"<": "&lt;",
......@@ -203,19 +205,19 @@
"'": '&#39;',
"/": '&#x2F;'
};
function _escape(data) {
if (typeof data === 'string') {
return data.replace(/[&<>"'\/]/g, function (s) {
return _entityMap[s];
});
});
}else{
return data;
}
}
function _ajax(options) {
// v0.5.0 of https://github.com/goloroden/http.js
var getXhr = function (callback) {
// Use the native XHR object if the browser supports it.
......@@ -229,33 +231,33 @@
return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
}
}
// If no XHR support was found, throw an error.
return callback(new Error());
};
var encodeUsingUrlEncoding = function (data) {
if(typeof data === 'string') {
return data;
}
var result = [];
for(var dataItem in data) {
if(data.hasOwnProperty(dataItem)) {
result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
}
}
return result.join('&');
};
var utf8 = function (text) {
text = text.replace(/\r\n/g, '\n');
var result = '';
for(var i = 0; i < text.length; i++) {
var c = text.charCodeAt(i);
if(c < 128) {
result += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
......@@ -267,35 +269,35 @@
result += String.fromCharCode((c & 63) | 128);
}
}
return result;
};
var base64 = function (text) {
var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
text = utf8(text);
var result = '',
chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
i = 0;
do {
chr1 = text.charCodeAt(i++);
chr2 = text.charCodeAt(i++);
chr3 = text.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if(isNaN(chr2)) {
enc3 = enc4 = 64;
} else if(isNaN(chr3)) {
enc4 = 64;
}
result +=
keyStr.charAt(enc1) +
keyStr.charAt(enc2) +
......@@ -304,14 +306,14 @@
chr1 = chr2 = chr3 = '';
enc1 = enc2 = enc3 = enc4 = '';
} while(i < text.length);
return result;
};
var mergeHeaders = function () {
// Use the first header object as base.
var result = arguments[0];
// Iterate through the remaining header objects and add them.
for(var i = 1; i < arguments.length; i++) {
var currentHeaders = arguments[i];
......@@ -321,39 +323,39 @@
}
}
}
// Return the merged headers.
return result;
};
var ajax = function (method, url, options, callback) {
// Adjust parameters.
if(typeof options === 'function') {
callback = options;
options = {};
}
// Set default parameter values.
options.cache = options.cache || false;
options.data = options.data || {};
options.headers = options.headers || {};
options.jsonp = options.jsonp || false;
options.async = options.async === undefined ? true : options.async;
// Merge the various header objects.
var headers = mergeHeaders({
'accept': '*/*',
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
}, ajax.headers, options.headers);
// Encode the data according to the content-type.
var payload;
if (headers['content-type'] === 'application/json') {
payload = JSON.stringify(options.data);
} else {
payload = encodeUsingUrlEncoding(options.data);
payload = encodeUsingUrlEncoding(options.data);
}
// Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
// if neccessary.
if(method === 'GET') {
......@@ -363,18 +365,18 @@
queryString.push(payload);
payload = null;
}
// Handle caching.
if(!options.cache) {
queryString.push('_=' + (new Date()).getTime());
}
// If neccessary prepare the query string for a JSONP call.
if(options.jsonp) {
queryString.push('callback=' + options.jsonp);
queryString.push('jsonp=' + options.jsonp);
}
// Merge the query string and attach it to the url.
queryString = queryString.join('&');
if (queryString.length > 1) {
......@@ -384,116 +386,116 @@
url += '?' + queryString;
}
}
// Make a JSONP call if neccessary.
if(options.jsonp) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
head.appendChild(script);
head.appendChild(script);
return;
}
}
// Since we got here, it is no JSONP request, so make a normal XHR request.
getXhr(function (err, xhr) {
if(err) return callback(err);
// Open the request.
xhr.open(method, url, options.async);
// Set the request headers.
for(var header in headers) {
if(headers.hasOwnProperty(header)) {
xhr.setRequestHeader(header, headers[header]);
}
}
// Handle the request events.
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
var data = xhr.responseText || '';
// If no callback is given, return.
if(!callback) {
return;
}
// Return an object that provides access to the data as text and JSON.
callback(xhr.status, {
text: function () {
return data;
},
json: function () {
return JSON.parse(data);
}
});
}
};
// Actually send the XHR request.
xhr.send(payload);
});
};
// Define the external interface.
var http = {
authBasic: function (username, password) {
ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
},
connect: function (url, options, callback) {
return ajax('CONNECT', url, options, callback);
return ajax('CONNECT', url, options, callback);
},
del: function (url, options, callback) {
return ajax('DELETE', url, options, callback);
return ajax('DELETE', url, options, callback);
},
get: function (url, options, callback) {
return ajax('GET', url, options, callback);
},
head: function (url, options, callback) {
return ajax('HEAD', url, options, callback);
},
headers: function (headers) {
ajax.headers = headers || {};
},
isAllowed: function (url, verb, callback) {
this.options(url, function (status, data) {
callback(data.text().indexOf(verb) !== -1);
});
},
options: function (url, options, callback) {
return ajax('OPTIONS', url, options, callback);
},
patch: function (url, options, callback) {
return ajax('PATCH', url, options, callback);
return ajax('PATCH', url, options, callback);
},
post: function (url, options, callback) {
return ajax('POST', url, options, callback);
return ajax('POST', url, options, callback);
},
put: function (url, options, callback) {
return ajax('PUT', url, options, callback);
return ajax('PUT', url, options, callback);
},
trace: function (url, options, callback) {
return ajax('TRACE', url, options, callback);
}
};
var methode = options.type ? options.type.toLowerCase() : 'get';
http[methode](options.url, options, function (status, data) {
if (status === 200) {
options.success(data.json(), status, null);
......@@ -502,7 +504,7 @@
}
});
}
var _cookie = {
create: function(name,value,minutes,domain) {
var expires;
......@@ -515,7 +517,7 @@
domain = (domain)? "domain="+domain+";" : "";
document.cookie = name+"="+value+expires+";"+domain+"path=/";
},
read: function(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
......@@ -526,26 +528,26 @@
}
return null;
},
remove: function(name) {
this.create(name,"",-1);
}
};
var cookie_noop = {
create: function(name,value,minutes,domain) {},
read: function(name) { return null; },
remove: function(name) {}
};
// move dependent functions to a container so that
// they can be overriden easier in no jquery environment (node.js)
var f = {
extend: $ ? $.extend : _extend,
each: $ ? $.each : _each,
ajax: $ ? $.ajax : _ajax,
ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
detectLanguage: detectLanguage,
escape: _escape,
......@@ -556,19 +558,19 @@
var languages = [];
if (typeof lng === 'string' && lng.indexOf('-') > -1) {
var parts = lng.split('-');
lng = o.lowerCaseLng ?
lng = o.lowerCaseLng ?
parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
if (o.load !== 'unspecific') languages.push(lng);
if (o.load !== 'current') languages.push(parts[0]);
} else {
languages.push(lng);
}
if (languages.indexOf(o.fallbackLng) === -1 && o.fallbackLng) languages.push(o.fallbackLng);
return languages;
},
regexEscape: function(str) {
......@@ -576,32 +578,32 @@
}
};
function init(options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
}
options = options || {};
// override defaults with passed in options
f.extend(o, options);
delete o.fixLng; /* passed in each time */
// create namespace object if namespace is passed in as string
if (typeof o.ns == 'string') {
o.ns = { namespaces: [o.ns], defaultNs: o.ns};
}
// fallback namespaces
if (typeof o.fallbackNS == 'string') {
o.fallbackNS = [o.fallbackNS];
}
// escape prefix/suffix
o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
if (!o.lng) o.lng = f.detectLanguage();
if (!o.lng) o.lng = f.detectLanguage();
if (o.lng) {
// set cookie with lng set (as detectLanguage will set cookie on need)
if (o.useCookie) f.cookie.create(o.cookieName, o.lng, o.cookieExpirationTime, o.cookieDomain);
......@@ -609,11 +611,11 @@
o.lng = o.fallbackLng;
if (o.useCookie) f.cookie.remove(o.cookieName);
}
languages = f.toLanguages(o.lng);
currentLng = languages[0];
f.log('currentLng set to: ' + currentLng);
var lngTranslate = translate;
if (options.fixLng) {
lngTranslate = function(key, options) {
......@@ -623,18 +625,18 @@
};
lngTranslate.lng = currentLng;
}
pluralExtensions.setCurrentLng(currentLng);
// add JQuery extensions
if ($ && o.setJqueryExt) addJqueryFunct();
// jQuery deferred
var deferred;
if ($ && $.Deferred) {
deferred = $.Deferred();
}
// return immidiatly if res are passed in
if (o.resStore) {
resStore = o.resStore;
......@@ -644,7 +646,7 @@
if (deferred) return deferred.promise();
return;
}
// languages to load
var lngsToLoad = f.toLanguages(o.lng);
if (typeof o.preload === 'string') o.preload = [o.preload];
......@@ -656,16 +658,16 @@
}
}
}
// else load them
i18n.sync.load(lngsToLoad, o, function(err, store) {
resStore = store;
initialized = true;
if (cb) cb(lngTranslate);
if (deferred) deferred.resolve(lngTranslate);
});
if (deferred) return deferred.promise();
}
function preload(lngs, cb) {
......@@ -677,7 +679,7 @@
}
return init(cb);
}
function addResourceBundle(lng, ns, resources) {
if (typeof ns !== 'string') {
resources = ns;
......@@ -685,21 +687,30 @@
} else if (o.ns.namespaces.indexOf(ns) < 0) {
o.ns.namespaces.push(ns);
}
resStore[lng] = resStore[lng] || {};
resStore[lng][ns] = resStore[lng][ns] || {};
f.extend(resStore[lng][ns], resources);
}
function removeResourceBundle(lng, ns) {
if (typeof ns !== 'string') {
ns = o.ns.defaultNs;
}
resStore[lng] = resStore[lng] || {};
resStore[lng][ns] = {};
}
function setDefaultNamespace(ns) {
o.ns.defaultNs = ns;
}
function loadNamespace(namespace, cb) {
loadNamespaces([namespace], cb);
}
function loadNamespaces(namespaces, cb) {
var opts = {
dynamicLoad: o.dynamicLoad,
......@@ -708,7 +719,7 @@
customLoad: o.customLoad,
ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
};
// languages to load
var lngsToLoad = f.toLanguages(o.lng);
if (typeof o.preload === 'string') o.preload = [o.preload];
......@@ -720,7 +731,7 @@
}
}
}
// check if we have to load
var lngNeedLoad = [];
for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
......@@ -733,26 +744,26 @@
} else {
needLoad = true;
}
if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
}
if (lngNeedLoad.length) {
i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
var todo = namespaces.length * lngNeedLoad.length;
// load each file individual
f.each(namespaces, function(nsIndex, nsValue) {
// append namespace to namespace array
if (o.ns.namespaces.indexOf(nsValue) < 0) {
o.ns.namespaces.push(nsValue);
}
f.each(lngNeedLoad, function(lngIndex, lngValue) {
resStore[lngValue] = resStore[lngValue] || {};
resStore[lngValue][nsValue] = store[lngValue][nsValue];
todo--; // wait for all done befor callback
if (todo === 0 && cb) {
if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
......@@ -765,91 +776,99 @@
if (cb) cb();
}
}
function setLng(lng, options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
} else if (!options) {
options = {};
}
options.lng = lng;
return init(options, cb);
}
function lng() {
return currentLng;
}
function addJqueryFunct() {
// $.t shortcut
$.t = $.t || translate;
function parse(ele, key, options) {
if (key.length === 0) return;
var attr = 'text';
if (key.indexOf('[') === 0) {
var parts = key.split(']');
key = parts[1];
attr = parts[0].substr(1, parts[0].length-1);
}
if (key.indexOf(';') === key.length-1) {
key = key.substr(0, key.length-2);
}
var optionsToUse;
if (attr === 'html') {
optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
ele.html($.t(key, optionsToUse));
}
else if (attr === 'text') {
} else if (attr === 'text') {
optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
ele.text($.t(key, optionsToUse));
} else if (attr === 'prepend') {
optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
ele.prepend($.t(key, optionsToUse));
} else if (attr === 'append') {
optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
ele.append($.t(key, optionsToUse));
} else {
optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
ele.attr(attr, $.t(key, optionsToUse));
}
}
function localize(ele, options) {
var key = ele.attr(o.selectorAttr);
if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
if (!key) return;
var target = ele
, targetSelector = ele.data("i18n-target");
if (targetSelector) {
target = ele.find(targetSelector) || ele;
}
if (!options && o.useDataAttrOptions === true) {
options = ele.data("i18n-options");
}
options = options || {};
if (key.indexOf(';') >= 0) {
var keys = key.split(';');
$.each(keys, function(m, k) {
if (k !== '') parse(target, k, options);
});
} else {
parse(target, key, options);
}
if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
}
// fn
$.fn.i18n = function (options) {
return this.each(function() {
// localize element itself
localize($(this), options);
// localize childs
var elements = $(this).find('[' + o.selectorAttr + ']');
elements.each(function() {
elements.each(function() {
localize($(this), options);
});
});
......@@ -857,14 +876,14 @@
}
function applyReplacement(str, replacementHash, nestedKey, options) {
if (!str) return str;
options = options || replacementHash; // first call uses replacement hash combined with options
if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
, suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
, unEscapingSuffix = 'HTML'+suffix;
f.each(replacementHash, function(key, value) {
var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
if (typeof value === 'object' && value !== null) {
......@@ -881,18 +900,18 @@
});
return str;
}
// append it to functions
f.applyReplacement = applyReplacement;
function applyReuse(translated, options) {
var comma = ',';
var options_open = '{';
var options_close = '}';
var opts = f.extend({}, options);
delete opts.postProcess;
while (translated.indexOf(o.reusePrefix) != -1) {
replacementCounter++;
if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
......@@ -900,8 +919,8 @@
var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
var token = translated.substring(index_of_opening, index_of_end_of_closing);
var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
if (token_without_symbols.indexOf(comma) != -1) {
var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
if (token_without_symbols.indexOf(options_open, index_of_token_end_of_closing) != -1 && token_without_symbols.indexOf(options_close, index_of_token_end_of_closing) != -1) {
......@@ -914,31 +933,33 @@
}
}
}
var translated_token = _translate(token_without_symbols, opts);
translated = translated.replace(token, translated_token);
}
return translated;
}
function hasContext(options) {
return (options.context && typeof options.context == 'string');
return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
}
function needsPlural(options) {
return (options.count !== undefined && typeof options.count != 'string' && options.count !== 1);
}
function exists(key, options) {
options = options || {};
var notFound = _getDefaultValue(key, options)
, found = _find(key, options);
return found !== undefined || found === notFound;
}
function translate(key, options) {
options = options || {};
if (!initialized) {
f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
return options.defaultValue || '';
......@@ -946,26 +967,26 @@
replacementCounter = 0;
return _translate.apply(null, arguments);
}
function _getDefaultValue(key, options) {
return (options.defaultValue !== undefined) ? options.defaultValue : key;
}
function _injectSprintfProcessor() {
var values = [];
// mh: build array from second argument onwards
for (var i = 1; i < arguments.length; i++) {
values.push(arguments[i]);
}
return {
postProcess: 'sprintf',
sprintf: values
};
}
function _translate(potentialKeys, options) {
if (typeof options == 'string') {
if (o.shortcutFunction === 'sprintf') {
......@@ -979,33 +1000,37 @@
} else {
options = options || {};
}
if (potentialKeys === undefined || potentialKeys === null) return '';
if (typeof potentialKeys == 'string') {
potentialKeys = [potentialKeys];
}
var key = null;
for (var i = 0; i < potentialKeys.length; i++) {
key = potentialKeys[i];
if (exists(key)) {
break;
var key = potentialKeys[0];
if (potentialKeys.length > 1) {
for (var i = 0; i < potentialKeys.length; i++) {
key = potentialKeys[i];
if (exists(key)) {
break;
}
}
}
var notFound = _getDefaultValue(key, options)
, found = _find(key, options)
, lngs = options.lng ? f.toLanguages(options.lng) : languages
, ns = options.ns || o.ns.defaultNs
, parts;
// split ns and key
if (key.indexOf(o.nsseparator) > -1) {
parts = key.split(o.nsseparator);
ns = parts[0];
key = parts[1];
}
if (found === undefined && o.sendMissing) {
if (options.lng) {
sync.postMissing(lngs[0], ns, key, notFound, lngs);
......@@ -1013,14 +1038,14 @@
sync.postMissing(o.lng, ns, key, notFound, lngs);
}
}
var postProcessor = options.postProcess || o.postProcess;
if (found !== undefined && postProcessor) {
if (postProcessors[postProcessor]) {
found = postProcessors[postProcessor](found, key, options);
}
}
// process notFound if function exists
var splitNotFound = notFound;
if (notFound.indexOf(o.nsseparator) > -1) {
......@@ -1030,68 +1055,68 @@
if (splitNotFound === key && o.parseMissingKey) {
notFound = o.parseMissingKey(notFound);
}
if (found === undefined) {
notFound = applyReplacement(notFound, options);
notFound = applyReuse(notFound, options);
if (postProcessor && postProcessors[postProcessor]) {
var val = _getDefaultValue(key, options);
found = postProcessors[postProcessor](val, key, options);
}
}
return (found !== undefined) ? found : notFound;
}
function _find(key, options){
function _find(key, options) {
options = options || {};
var optionWithoutCount, translated
, notFound = _getDefaultValue(key, options)
, lngs = languages;
if (!resStore) { return notFound; } // no resStore to translate from
if (options.lng) {
lngs = f.toLanguages(options.lng);
if (!resStore[lngs[0]]) {
var oldAsync = o.getAsync;
o.getAsync = false;
i18n.sync.load(lngs, o, function(err, store) {
f.extend(resStore, store);
o.getAsync = oldAsync;
});
}
}
var ns = options.ns || o.ns.defaultNs;
if (key.indexOf(o.nsseparator) > -1) {
var parts = key.split(o.nsseparator);
ns = parts[0];
key = parts[1];
}
if (hasContext(options)) {
optionWithoutCount = f.extend({}, options);
delete optionWithoutCount.context;
optionWithoutCount.defaultValue = o.contextNotFound;
var contextKey = ns + o.nsseparator + key + '_' + options.context;
translated = translate(contextKey, optionWithoutCount);
if (translated != o.contextNotFound) {
return applyReplacement(translated, { context: options.context }); // apply replacement for context only
} // else continue translation with original/nonContext key
}
if (needsPlural(options)) {
optionWithoutCount = f.extend({}, options);
delete optionWithoutCount.count;
optionWithoutCount.defaultValue = o.pluralNotFound;
var pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
var pluralExtension = pluralExtensions.get(lngs[0], options.count);
if (pluralExtension >= 0) {
......@@ -1099,7 +1124,7 @@
} else if (pluralExtension === 1) {
pluralKey = ns + o.nsseparator + key; // singular
}
translated = translate(pluralKey, optionWithoutCount);
if (translated != o.pluralNotFound) {
return applyReplacement(translated, {
......@@ -1109,14 +1134,14 @@
}); // apply replacement for count only
} // else continue translation with original/singular key
}
var found;
var keys = key.split(o.keyseparator);
for (var i = 0, len = lngs.length; i < len; i++ ) {
if (found !== undefined) break;
var l = lngs[i];
var x = 0;
var value = resStore[l] && resStore[l][ns];
while (keys[x]) {
......@@ -1124,10 +1149,11 @@
x++;
}
if (value !== undefined) {
var valueType = Object.prototype.toString.apply(value);
if (typeof value === 'string') {
value = applyReplacement(value, options);
value = applyReuse(value, options);
} else if (Object.prototype.toString.apply(value) === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
} else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
value = value.join('\n');
value = applyReplacement(value, options);
value = applyReuse(value, options);
......@@ -1135,35 +1161,43 @@
value = undefined;
} else if (value !== null) {
if (!o.returnObjectTrees && !options.returnObjectTrees) {
value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
'returned a object instead of string.';
f.log(value);
} else if (typeof value !== 'number') {
var copy = {}; // apply child translation on a copy
if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
value = o.objectTreeKeyHandler(key, value, l, ns, options);
} else {
value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
'returned an object instead of string.';
f.log(value);
}
} else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
f.each(value, function(m) {
copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
});
value = copy;
}
}
if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
value = undefined;
found = value;
}
}
if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
// set flag for fallback lookup - avoid recursion
options.isFallbackLookup = true;
if (o.fallbackNS.length) {
for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
if (found) {
/* compare value without namespace */
var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
, notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
if (foundValue !== notFoundValue) break;
}
}
......@@ -1171,12 +1205,12 @@
found = _find(key, options); // fallback to default NS
}
}
return found;
}
function detectLanguage() {
var detectedLng;
// get from qs
var qsParm = [];
if (typeof window !== 'undefined') {
......@@ -1196,22 +1230,22 @@
detectedLng = qsParm[o.detectLngQS];
}
}
// get from cookie
if (!detectedLng && typeof document !== 'undefined' && o.useCookie ) {
var c = f.cookie.read(o.cookieName);
if (c) detectedLng = c;
}
// get from navigator
if (!detectedLng && typeof navigator !== 'undefined') {
detectedLng = (navigator.language) ? navigator.language : navigator.userLanguage;
}
return detectedLng;
}
var sync = {
load: function(lngs, options, cb) {
if (options.useLocalStorage) {
sync._loadLocal(lngs, options, function(err, store) {
......@@ -1219,12 +1253,12 @@
for (var i = 0, len = lngs.length; i < len; i++) {
if (!store[lngs[i]]) missingLngs.push(lngs[i]);
}
if (missingLngs.length > 0) {
sync._fetch(missingLngs, options, function(err, fetched) {
f.extend(store, fetched);
sync._storeLocal(fetched);
cb(null, store);
});
} else {
......@@ -1237,32 +1271,32 @@
});
}
},
_loadLocal: function(lngs, options, cb) {
var store = {}
, nowMS = new Date().getTime();
if(window.localStorage) {
var todo = lngs.length;
f.each(lngs, function(key, lng) {
var local = window.localStorage.getItem('res_' + lng);
if (local) {
local = JSON.parse(local);
if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
store[lng] = local;
}
}
todo--; // wait for all done befor callback
if (todo === 0) cb(null, store);
});
}
},
_storeLocal: function(store) {
if(window.localStorage) {
for (var m in store) {
......@@ -1272,19 +1306,19 @@
}
return;
},
_fetch: function(lngs, options, cb) {
var ns = options.ns
, store = {};
if (!options.dynamicLoad) {
var todo = ns.namespaces.length * lngs.length
, errors;
// load each file individual
f.each(ns.namespaces, function(nsIndex, nsValue) {
f.each(lngs, function(lngIndex, lngValue) {
// Call this once our translation has returned.
var loadComplete = function(err, data) {
if (err) {
......@@ -1293,11 +1327,11 @@
}
store[lngValue] = store[lngValue] || {};
store[lngValue][nsValue] = data;
todo--; // wait for all done befor callback
if (todo === 0) cb(errors, store);
};
if(typeof options.customLoad == 'function'){
// Use the specified custom callback.
options.customLoad(lngValue, nsValue, options, loadComplete);
......@@ -1312,7 +1346,7 @@
var loadComplete = function(err, data) {
cb(null, data);
};
if(typeof options.customLoad == 'function'){
// Use the specified custom callback.
options.customLoad(lngs, ns.namespaces, options, loadComplete);
......@@ -1332,10 +1366,10 @@
dataType: "json",
async : options.getAsync
});
}
}
}
},
_fetchOne: function(lng, ns, options, done) {
var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
f.ajax({
......@@ -1345,20 +1379,28 @@
done(null, data);
},
error : function(xhr, status, error) {
f.log('failed loading: ' + url);
if (error.status == 200) {
// file loaded but invalid json, stop waste time !
f.log('There is a typo in: ' + url);
} else if (error.status == 404) {
f.log('Does not exist: ' + url);
} else {
f.log(error.status + ' when loading ' + url);
}
done(error, {});
},
dataType: "json",
async : options.getAsync
});
},
postMissing: function(lng, ns, key, defaultValue, lngs) {
var payload = {};
payload[key] = defaultValue;
var urls = [];
if (o.sendMissingTo === 'fallback' && o.fallbackLng !== false) {
urls.push({lng: o.fallbackLng, url: applyReplacement(o.resPostPath, { lng: o.fallbackLng, ns: ns })});
} else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng === false) ) {
......@@ -1368,7 +1410,7 @@
urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
}
}
for (var y = 0, len = urls.length; y < len; y++) {
var item = urls[y];
f.ajax({
......@@ -1377,7 +1419,7 @@
data: payload,
success: function(data, status, xhr) {
f.log('posted missing key \'' + key + '\' to: ' + item.url);
// add key to resStore
var keys = key.split('.');
var x = 0;
......@@ -1402,1081 +1444,1081 @@
};
// definition http://translate.sourceforge.net/wiki/l10n/pluralforms
var pluralExtensions = {
rules: {
"ach": {
"name": "Acholi",
"name": "Acholi",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"af": {
"name": "Afrikaans",
"name": "Afrikaans",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ak": {
"name": "Akan",
"name": "Akan",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"am": {
"name": "Amharic",
"name": "Amharic",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"an": {
"name": "Aragonese",
"name": "Aragonese",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ar": {
"name": "Arabic",
"name": "Arabic",
"numbers": [
0,
1,
2,
3,
11,
0,
1,
2,
3,
11,
100
],
],
"plurals": function(n) { return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); }
},
},
"arn": {
"name": "Mapudungun",
"name": "Mapudungun",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"ast": {
"name": "Asturian",
"name": "Asturian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ay": {
"name": "Aymar\u00e1",
"name": "Aymar\u00e1",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"az": {
"name": "Azerbaijani",
"name": "Azerbaijani",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"be": {
"name": "Belarusian",
"name": "Belarusian",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"bg": {
"name": "Bulgarian",
"name": "Bulgarian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"bn": {
"name": "Bengali",
"name": "Bengali",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"bo": {
"name": "Tibetan",
"name": "Tibetan",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"br": {
"name": "Breton",
"name": "Breton",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"bs": {
"name": "Bosnian",
"name": "Bosnian",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"ca": {
"name": "Catalan",
"name": "Catalan",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"cgg": {
"name": "Chiga",
"name": "Chiga",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"cs": {
"name": "Czech",
"name": "Czech",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
},
},
"csb": {
"name": "Kashubian",
"name": "Kashubian",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"cy": {
"name": "Welsh",
"name": "Welsh",
"numbers": [
1,
2,
3,
1,
2,
3,
8
],
],
"plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3); }
},
},
"da": {
"name": "Danish",
"name": "Danish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"de": {
"name": "German",
"name": "German",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"dz": {
"name": "Dzongkha",
"name": "Dzongkha",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"el": {
"name": "Greek",
"name": "Greek",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"en": {
"name": "English",
"name": "English",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"eo": {
"name": "Esperanto",
"name": "Esperanto",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"es": {
"name": "Spanish",
"name": "Spanish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"es_ar": {
"name": "Argentinean Spanish",
"name": "Argentinean Spanish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"et": {
"name": "Estonian",
"name": "Estonian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"eu": {
"name": "Basque",
"name": "Basque",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"fa": {
"name": "Persian",
"name": "Persian",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"fi": {
"name": "Finnish",
"name": "Finnish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"fil": {
"name": "Filipino",
"name": "Filipino",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"fo": {
"name": "Faroese",
"name": "Faroese",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"fr": {
"name": "French",
"name": "French",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"fur": {
"name": "Friulian",
"name": "Friulian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"fy": {
"name": "Frisian",
"name": "Frisian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ga": {
"name": "Irish",
"name": "Irish",
"numbers": [
1,
1,
2,
3,
7,
7,
11
],
],
"plurals": function(n) { return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;}
},
},
"gd": {
"name": "Scottish Gaelic",
"name": "Scottish Gaelic",
"numbers": [
1,
2,
1,
2,
3,
20
],
],
"plurals": function(n) { return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3); }
},
},
"gl": {
"name": "Galician",
"name": "Galician",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"gu": {
"name": "Gujarati",
"name": "Gujarati",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"gun": {
"name": "Gun",
"name": "Gun",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"ha": {
"name": "Hausa",
"name": "Hausa",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"he": {
"name": "Hebrew",
"name": "Hebrew",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"hi": {
"name": "Hindi",
"name": "Hindi",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"hr": {
"name": "Croatian",
"name": "Croatian",
"numbers": [
1,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"hu": {
"name": "Hungarian",
"name": "Hungarian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"hy": {
"name": "Armenian",
"name": "Armenian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ia": {
"name": "Interlingua",
"name": "Interlingua",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"id": {
"name": "Indonesian",
"name": "Indonesian",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"is": {
"name": "Icelandic",
"name": "Icelandic",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n%10!=1 || n%100==11); }
},
},
"it": {
"name": "Italian",
"name": "Italian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ja": {
"name": "Japanese",
"name": "Japanese",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"jbo": {
"name": "Lojban",
"name": "Lojban",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"jv": {
"name": "Javanese",
"name": "Javanese",
"numbers": [
0,
0,
1
],
],
"plurals": function(n) { return Number(n !== 0); }
},
},
"ka": {
"name": "Georgian",
"name": "Georgian",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"kk": {
"name": "Kazakh",
"name": "Kazakh",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"km": {
"name": "Khmer",
"name": "Khmer",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"kn": {
"name": "Kannada",
"name": "Kannada",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ko": {
"name": "Korean",
"name": "Korean",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"ku": {
"name": "Kurdish",
"name": "Kurdish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"kw": {
"name": "Cornish",
"name": "Cornish",
"numbers": [
1,
2,
1,
2,
3,
4
],
],
"plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3); }
},
},
"ky": {
"name": "Kyrgyz",
"name": "Kyrgyz",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"lb": {
"name": "Letzeburgesch",
"name": "Letzeburgesch",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ln": {
"name": "Lingala",
"name": "Lingala",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"lo": {
"name": "Lao",
"name": "Lao",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"lt": {
"name": "Lithuanian",
"name": "Lithuanian",
"numbers": [
1,
1,
2,
10
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"lv": {
"name": "Latvian",
"name": "Latvian",
"numbers": [
0,
1,
0,
1,
2
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2); }
},
},
"mai": {
"name": "Maithili",
"name": "Maithili",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"mfe": {
"name": "Mauritian Creole",
"name": "Mauritian Creole",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"mg": {
"name": "Malagasy",
"name": "Malagasy",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"mi": {
"name": "Maori",
"name": "Maori",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"mk": {
"name": "Macedonian",
"name": "Macedonian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n==1 || n%10==1 ? 0 : 1); }
},
},
"ml": {
"name": "Malayalam",
"name": "Malayalam",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"mn": {
"name": "Mongolian",
"name": "Mongolian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"mnk": {
"name": "Mandinka",
"name": "Mandinka",
"numbers": [
0,
1,
0,
1,
2
],
],
"plurals": function(n) { return Number(0 ? 0 : n==1 ? 1 : 2); }
},
},
"mr": {
"name": "Marathi",
"name": "Marathi",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ms": {
"name": "Malay",
"name": "Malay",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"mt": {
"name": "Maltese",
"name": "Maltese",
"numbers": [
1,
2,
11,
1,
2,
11,
20
],
],
"plurals": function(n) { return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); }
},
},
"nah": {
"name": "Nahuatl",
"name": "Nahuatl",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"nap": {
"name": "Neapolitan",
"name": "Neapolitan",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"nb": {
"name": "Norwegian Bokmal",
"name": "Norwegian Bokmal",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ne": {
"name": "Nepali",
"name": "Nepali",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"nl": {
"name": "Dutch",
"name": "Dutch",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"nn": {
"name": "Norwegian Nynorsk",
"name": "Norwegian Nynorsk",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"no": {
"name": "Norwegian",
"name": "Norwegian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"nso": {
"name": "Northern Sotho",
"name": "Northern Sotho",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"oc": {
"name": "Occitan",
"name": "Occitan",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"or": {
"name": "Oriya",
"name": "Oriya",
"numbers": [
2,
2,
1
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"pa": {
"name": "Punjabi",
"name": "Punjabi",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"pap": {
"name": "Papiamento",
"name": "Papiamento",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"pl": {
"name": "Polish",
"name": "Polish",
"numbers": [
1,
1,
2,
5
],
],
"plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"pms": {
"name": "Piemontese",
"name": "Piemontese",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ps": {
"name": "Pashto",
"name": "Pashto",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"pt": {
"name": "Portuguese",
"name": "Portuguese",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"pt_br": {
"name": "Brazilian Portuguese",
"name": "Brazilian Portuguese",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"rm": {
"name": "Romansh",
"name": "Romansh",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ro": {
"name": "Romanian",
"name": "Romanian",
"numbers": [
1,
1,
2,
20
],
],
"plurals": function(n) { return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); }
},
},
"ru": {
"name": "Russian",
"name": "Russian",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"sah": {
"name": "Yakut",
"name": "Yakut",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"sco": {
"name": "Scots",
"name": "Scots",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"se": {
"name": "Northern Sami",
"name": "Northern Sami",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"si": {
"name": "Sinhala",
"name": "Sinhala",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"sk": {
"name": "Slovak",
"name": "Slovak",
"numbers": [
1,
2,
1,
2,
5
],
],
"plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
},
},
"sl": {
"name": "Slovenian",
"name": "Slovenian",
"numbers": [
5,
1,
2,
5,
1,
2,
3
],
],
"plurals": function(n) { return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
},
},
"so": {
"name": "Somali",
"name": "Somali",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"son": {
"name": "Songhay",
"name": "Songhay",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"sq": {
"name": "Albanian",
"name": "Albanian",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"sr": {
"name": "Serbian",
"name": "Serbian",
"numbers": [
1,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"su": {
"name": "Sundanese",
"name": "Sundanese",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"sv": {
"name": "Swedish",
"name": "Swedish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"sw": {
"name": "Swahili",
"name": "Swahili",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"ta": {
"name": "Tamil",
"name": "Tamil",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"te": {
"name": "Telugu",
"name": "Telugu",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"tg": {
"name": "Tajik",
"name": "Tajik",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"th": {
"name": "Thai",
"name": "Thai",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"ti": {
"name": "Tigrinya",
"name": "Tigrinya",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"tk": {
"name": "Turkmen",
"name": "Turkmen",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"tr": {
"name": "Turkish",
"name": "Turkish",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"tt": {
"name": "Tatar",
"name": "Tatar",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"ug": {
"name": "Uyghur",
"name": "Uyghur",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"uk": {
"name": "Ukrainian",
"name": "Ukrainian",
"numbers": [
1,
1,
2,
5
],
],
"plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
},
},
"ur": {
"name": "Urdu",
"name": "Urdu",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"uz": {
"name": "Uzbek",
"name": "Uzbek",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"vi": {
"name": "Vietnamese",
"name": "Vietnamese",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"wa": {
"name": "Walloon",
"name": "Walloon",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n > 1); }
},
},
"wo": {
"name": "Wolof",
"name": "Wolof",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
},
},
"yo": {
"name": "Yoruba",
"name": "Yoruba",
"numbers": [
1,
1,
2
],
],
"plurals": function(n) { return Number(n != 1); }
},
},
"zh": {
"name": "Chinese",
"name": "Chinese",
"numbers": [
1
],
],
"plurals": function(n) { return 0; }
}
},
// for demonstration only sl and ar is added but you can add your own pluralExtensions
addRule: function(lng, obj) {
pluralExtensions.rules[lng] = obj;
pluralExtensions.rules[lng] = obj;
},
setCurrentLng: function(lng) {
if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
var parts = lng.split('-');
pluralExtensions.currentRule = {
lng: lng,
rule: pluralExtensions.rules[parts[0]]
};
}
},
get: function(lng, count) {
var parts = lng.split('-');
function getResult(l, c) {
var ext;
if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
ext = pluralExtensions.currentRule.rule;
ext = pluralExtensions.currentRule.rule;
} else {
ext = pluralExtensions.rules[l];
}
......@@ -2484,7 +2526,7 @@
var i = ext.plurals(c);
var number = ext.numbers[i];
if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
if (number === 2) {
if (number === 2) {
number = -1; // regular plural
} else if (number === 1) {
number = 1; // singular
......@@ -2495,10 +2537,10 @@
return c === 1 ? '1' : '-1';
}
}
return getResult(parts[0], count);
}
};
var postProcessors = {};
var addPostProcessor = function(name, fc) {
......@@ -2513,14 +2555,14 @@
for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
return output.join('');
}
var str_format = function() {
if (!str_format.cache.hasOwnProperty(arguments[0])) {
str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
}
return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
};
str_format.format = function(parse_tree, argv) {
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
for (i = 0; i < tree_length; i++) {
......@@ -2545,7 +2587,7 @@
else { // positional argument (implicit)
arg = argv[cursor++];
}
if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
}
......@@ -2570,9 +2612,9 @@
}
return output.join('');
};
str_format.cache = {};
str_format.parse = function(fmt) {
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
while (_fmt) {
......@@ -2620,24 +2662,24 @@
}
return parse_tree;
};
return str_format;
})();
var vsprintf = function(fmt, argv) {
argv.unshift(fmt);
return sprintf.apply(null, argv);
};
addPostProcessor("sprintf", function(val, key, opts) {
if (!opts.sprintf) return val;
if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
return vsprintf(val, opts.sprintf);
} else if (typeof opts.sprintf === 'object') {
return sprintf(val, opts.sprintf);
}
return val;
});
// public api interface
......@@ -2645,6 +2687,7 @@
i18n.setLng = setLng;
i18n.preload = preload;
i18n.addResourceBundle = addResourceBundle;
i18n.removeResourceBundle = removeResourceBundle;
i18n.loadNamespace = loadNamespace;
i18n.loadNamespaces = loadNamespaces;
i18n.setDefaultNamespace = setDefaultNamespace;
......
/* Modernizr 2.7.0 (Custom Build) | MIT & BSD
* Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-mq-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-blob_constructor-cors-file_api-file_filesystem-json
/*!
* Modernizr v2.7.1
* www.modernizr.com
*
* Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
* Available under the BSD and MIT licenses: www.modernizr.com/license/
*/
;
/*
* Modernizr tests which native CSS3 and HTML5 features are available in
* the current UA and makes the results available to you in two ways:
* as properties on a global Modernizr object, and as classes on the
* <html> element. This information allows you to progressively enhance
* your pages with a granular level of control over the experience.
*
* Modernizr has an optional (not included) conditional resource loader
* called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
* To get a build that includes Modernizr.load(), as well as choosing
* which tests to include, go to www.modernizr.com/download/
*
* Authors Faruk Ates, Paul Irish, Alex Sexton
* Contributors Ryan Seddon, Ben Alman
*/
window.Modernizr = (function( window, document, undefined ) {
var version = '2.7.0',
var version = '2.7.1',
Modernizr = {},
/*>>cssclasses*/
// option for enabling the HTML classes to be added
enableClasses = true,
/*>>cssclasses*/
docElement = document.documentElement,
/**
* Create our "modernizr" element that we do most feature tests on.
*/
mod = 'modernizr',
modElem = document.createElement(mod),
mStyle = modElem.style,
inputElem = document.createElement('input') ,
/**
* Create the input element for various Web Forms feature tests.
*/
inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ ,
/*>>smile*/
smile = ':)',
/*>>smile*/
toString = {}.toString,
// TODO :: make the prefixes more granular
/*>>prefixes*/
// List of property values to set for css tests. See ticket #21
prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
/*>>prefixes*/
/*>>domprefixes*/
// Following spec is to expose vendor-specific style properties as:
// elem.style.WebkitBorderRadius
// and the following would be incorrect:
// elem.style.webkitBorderRadius
// Webkit ghosts their properties in lowercase but Opera & Moz do not.
// Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
// erik.eae.net/archives/2008/03/10/21.48.10/
// More here: github.com/Modernizr/Modernizr/issues/issue/21
omPrefixes = 'Webkit Moz O ms',
cssomPrefixes = omPrefixes.split(' '),
domPrefixes = omPrefixes.toLowerCase().split(' '),
/*>>domprefixes*/
/*>>ns*/
ns = {'svg': 'http://www.w3.org/2000/svg'},
/*>>ns*/
tests = {},
inputs = {},
......@@ -44,38 +89,54 @@ window.Modernizr = (function( window, document, undefined ) {
slice = classes.slice,
featureName,
featureName, // used in testing loop
/*>>teststyles*/
// Inject element with style element and some CSS rules
injectElementWithStyles = function( rule, callback, nodes, testnames ) {
var style, ret, node, docOverflow,
div = document.createElement('div'),
body = document.body,
fakeBody = body || document.createElement('body');
// After page load injecting a fake body doesn't work so check if body exists
body = document.body,
// IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
fakeBody = body || document.createElement('body');
if ( parseInt(nodes, 10) ) {
while ( nodes-- ) {
// In order not to give false positives we create a node for each test
// This also allows the method to scale for unspecified uses
while ( nodes-- ) {
node = document.createElement('div');
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
div.appendChild(node);
}
}
style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
// <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
// when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
// with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
// msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
// Documents served as xml will throw if using &shy; so use xml friendly encoded version. See issue #277
style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
div.id = mod;
(body ? div : fakeBody).innerHTML += style;
// IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
(body ? div : fakeBody).innerHTML += style;
fakeBody.appendChild(div);
if ( !body ) {
fakeBody.style.background = '';
fakeBody.style.overflow = 'hidden';
//avoid crashing IE8, if background image is used
fakeBody.style.background = '';
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
fakeBody.style.overflow = 'hidden';
docOverflow = docElement.style.overflow;
docElement.style.overflow = 'hidden';
docElement.appendChild(fakeBody);
}
ret = callback(div, rule);
if ( !body ) {
// If this is done after page load we don't want to remove the body so check if body exists
if ( !body ) {
fakeBody.parentNode.removeChild(fakeBody);
docElement.style.overflow = docOverflow;
} else {
......@@ -85,7 +146,12 @@ window.Modernizr = (function( window, document, undefined ) {
return !!ret;
},
/*>>teststyles*/
/*>>mq*/
// adapted from matchMedia polyfill
// by Scott Jehl and Paul Irish
// gist.github.com/786768
testMediaQuery = function( mq ) {
var matchMedia = window.matchMedia || window.msMatchMedia;
......@@ -104,8 +170,18 @@ window.Modernizr = (function( window, document, undefined ) {
return bool;
},
/*>>mq*/
/*>>hasevent*/
//
// isEventSupported determines if a given element supports the given event
// kangax.github.com/iseventsupported/
//
// The following results are known incorrects:
// Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
// Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
// ...
isEventSupported = (function() {
var TAGNAMES = {
......@@ -119,17 +195,20 @@ window.Modernizr = (function( window, document, undefined ) {
element = element || document.createElement(TAGNAMES[eventName] || 'div');
eventName = 'on' + eventName;
var isSupported = eventName in element;
// When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
var isSupported = eventName in element;
if ( !isSupported ) {
if ( !element.setAttribute ) {
// If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
if ( !element.setAttribute ) {
element = document.createElement('div');
}
if ( element.setAttribute && element.removeAttribute ) {
element.setAttribute(eventName, '');
isSupported = is(element[eventName], 'function');
if ( !is(element[eventName], 'undefined') ) {
// If property was created, "remove it" (by setting value to `undefined`)
if ( !is(element[eventName], 'undefined') ) {
element[eventName] = undefined;
}
element.removeAttribute(eventName);
......@@ -141,8 +220,11 @@ window.Modernizr = (function( window, document, undefined ) {
}
return isEventSupported;
})(),
/*>>hasevent*/
// TODO :: Add flag for hasownprop ? didn't last time
// hasOwnProperty shim by kangax needed for Safari 2.0 support
_hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
......@@ -151,11 +233,13 @@ window.Modernizr = (function( window, document, undefined ) {
};
}
else {
hasOwnProp = function (object, property) {
hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
};
}
// Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
// es5.github.com/#x15.3.4.5
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) {
......@@ -199,22 +283,54 @@ window.Modernizr = (function( window, document, undefined ) {
};
}
/**
* setCss applies given styles to the Modernizr DOM node.
*/
function setCss( str ) {
mStyle.cssText = str;
}
/**
* setCssAll extrapolates all vendor-specific css strings.
*/
function setCssAll( str1, str2 ) {
return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
}
/**
* is returns a boolean for if typeof obj is exactly type.
*/
function is( obj, type ) {
return typeof obj === type;
}
/**
* contains returns a boolean for if substr is found within str.
*/
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
/*>>testprop*/
// testProps is a generic CSS / DOM property test.
// In testing support for a given CSS property, it's legit to test:
// `elem.style[styleName] !== undefined`
// If the property is supported it will return an empty string,
// if unsupported it will return undefined.
// We'll take advantage of this quick test and skip setting a style
// on our modernizr element, but instead just testing undefined vs
// empty string.
// Because the testing of the CSS property names (with "-", as
// opposed to the camelCase DOM properties) is non-portable and
// non-standard but works in WebKit and IE (but not Gecko or Opera),
// we explicitly reject properties with dashes so that authors
// developing in WebKit or IE first don't end up with
// browser-specific content by accident.
function testProps( props, prefixed ) {
for ( var i in props ) {
var prop = props[i];
......@@ -224,39 +340,83 @@ window.Modernizr = (function( window, document, undefined ) {
}
return false;
}
/*>>testprop*/
// TODO :: add testDOMProps
/**
* testDOMProps is a generic DOM property test; if a browser supports
* a certain property, it won't return undefined for it.
*/
function testDOMProps( props, obj, elem ) {
for ( var i in props ) {
var item = obj[props[i]];
if ( item !== undefined) {
if (elem === false) return props[i];
// return the property name as a string
if (elem === false) return props[i];
if (is(item, 'function')){
return item.bind(elem || obj);
// let's bind a function
if (is(item, 'function')){
// default to autobind unless override
return item.bind(elem || obj);
}
return item;
// return the unbound function or obj or value
return item;
}
}
return false;
}
/*>>testallprops*/
/**
* testPropsAll tests a list of DOM properties we want to check against.
* We specify literally ALL possible (known and/or likely) properties on
* the element including the non-vendor prefixed one, for forward-
* compatibility.
*/
function testPropsAll( prop, prefixed, elem ) {
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
if(is(prefixed, "string") || is(prefixed, "undefined")) {
// did they call .prefixed('boxSizing') or are we just testing a prop?
if(is(prefixed, "string") || is(prefixed, "undefined")) {
return testProps(props, prefixed);
} else {
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
} else {
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
return testDOMProps(props, prefixed, elem);
}
} tests['flexbox'] = function() {
}
/*>>testallprops*/
/**
* Tests
* -----
*/
// The *new* flexbox
// dev.w3.org/csswg/css3-flexbox
tests['flexbox'] = function() {
return testPropsAll('flexWrap');
}; tests['canvas'] = function() {
};
// The *old* flexbox
// www.w3.org/TR/2009/WD-css3-flexbox-20090723/
tests['flexboxlegacy'] = function() {
return testPropsAll('boxDirection');
};
// On the S60 and BB Storm, getContext exists, but always returns undefined
// so we actually have to call getContext() to verify
// github.com/Modernizr/Modernizr/issues/issue/97/
tests['canvas'] = function() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
......@@ -265,12 +425,28 @@ window.Modernizr = (function( window, document, undefined ) {
return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
};
// webk.it/70117 is tracking a legit WebGL feature detect proposal
// We do a soft detect which may false positive in order to avoid
// an expensive context creation: bugzil.la/732441
tests['webgl'] = function() {
return !!window.WebGLRenderingContext;
};
/*
* The Modernizr.touch test only indicates if the browser supports
* touch events, which does not necessarily reflect a touchscreen
* device, as evidenced by tablets running Windows 7 or, alas,
* the Palm Pre / WebOS (touch) phones.
*
* Additionally, Chrome (desktop) used to lie about its support on this,
* but that has since been rectified: crbug.com/36415
*
* We also test for Firefox 4 Multitouch Support.
*
* For more info, see: modernizr.github.com/Modernizr/touch.html
*/
tests['touch'] = function() {
var bool;
......@@ -287,6 +463,15 @@ window.Modernizr = (function( window, document, undefined ) {
};
// geolocation is often considered a trivial feature detect...
// Turns out, it's quite tricky to get right:
//
// Using !!navigator.geolocation does two things we don't want. It:
// 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
// 2. Disables page caching in WebKit: webk.it/43956
//
// Meanwhile, in Firefox < 8, an about:config setting could expose
// a false positive that would throw an exception: bugzil.la/688158
tests['geolocation'] = function() {
return 'geolocation' in navigator;
......@@ -298,18 +483,31 @@ window.Modernizr = (function( window, document, undefined ) {
};
// Chrome incognito mode used to throw an exception when using openDatabase
// It doesn't anymore.
tests['websqldatabase'] = function() {
return !!window.openDatabase;
};
// Vendors had inconsistent prefixing with the experimental Indexed DB:
// - Webkit's implementation is accessible through webkitIndexedDB
// - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
// For speed, we don't test the legacy (and beta-only) indexedDB
tests['indexedDB'] = function() {
return !!testPropsAll("indexedDB", window);
};
// documentMode logic from YUI to filter out IE8 Compat Mode
// which false positives.
tests['hashchange'] = function() {
return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
};
// Per 1.6:
// This used to be Modernizr.historymanagement but the longer
// name has been deprecated in favor of a shorter and property-matching one.
// The old API is still available in 1.6, but as of 2.0 will throw a warning,
// and in the first release thereafter disappear entirely.
tests['history'] = function() {
return !!(window.history && history.pushState);
};
......@@ -319,28 +517,52 @@ window.Modernizr = (function( window, document, undefined ) {
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
};
// FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
// will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
// FF10 still uses prefixes, so check for it until then.
// for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
tests['websockets'] = function() {
return 'WebSocket' in window || 'MozWebSocket' in window;
};
// css-tricks.com/rgba-browser-support/
tests['rgba'] = function() {
// Set an rgba() color and check the returned value
setCss('background-color:rgba(150,255,150,.5)');
return contains(mStyle.backgroundColor, 'rgba');
};
tests['hsla'] = function() {
setCss('background-color:hsla(120,40%,100%,.5)');
// Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
// except IE9 who retains it as hsla
setCss('background-color:hsla(120,40%,100%,.5)');
return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
};
tests['multiplebgs'] = function() {
setCss('background:url(https://),url(https://),red url(https://)');
// Setting multiple images AND a color on the background shorthand property
// and then querying the style.background property value for the number of
// occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
setCss('background:url(https://),url(https://),red url(https://)');
return (/(url\s*\(.*?){3}/).test(mStyle.background);
}; tests['backgroundsize'] = function() {
// If the UA supports multiple backgrounds, there should be three occurrences
// of the string "url(" in the return value for elemStyle.background
return (/(url\s*\(.*?){3}/).test(mStyle.background);
};
// this will false positive in Opera Mini
// github.com/Modernizr/Modernizr/issues/396
tests['backgroundsize'] = function() {
return testPropsAll('backgroundSize');
};
......@@ -349,27 +571,41 @@ window.Modernizr = (function( window, document, undefined ) {
};
// Super comprehensive table about all the unique implementations of
// border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
tests['borderradius'] = function() {
return testPropsAll('borderRadius');
};
// WebOS unfortunately false positives on this test.
tests['boxshadow'] = function() {
return testPropsAll('boxShadow');
};
// FF3.0 will false positive on this test
tests['textshadow'] = function() {
return document.createElement('div').style.textShadow === '';
};
tests['opacity'] = function() {
setCssAll('opacity:.55');
// Browsers that actually have CSS Opacity implemented have done so
// according to spec, which means their return values are within the
// range of [0.0,1.0] - including the leading zero.
return (/^0.55$/).test(mStyle.opacity);
setCssAll('opacity:.55');
// The non-literal . in this regex is intentional:
// German Chrome returns this value as 0,55
// github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
return (/^0.55$/).test(mStyle.opacity);
};
// Note, Android < 4 will pass this test, but can only animate
// a single property at a time
// daneden.me/2011/12/putting-up-with-androids-bullshit/
tests['cssanimations'] = function() {
return testPropsAll('animationName');
};
......@@ -381,13 +617,23 @@ window.Modernizr = (function( window, document, undefined ) {
tests['cssgradients'] = function() {
/**
* For CSS Gradients syntax, please see:
* webkit.org/blog/175/introducing-css-gradients/
* developer.mozilla.org/en/CSS/-moz-linear-gradient
* developer.mozilla.org/en/CSS/-moz-radial-gradient
* dev.w3.org/csswg/css3-images/#gradients-
*/
var str1 = 'background-image:',
str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
str3 = 'linear-gradient(left top,#9f9, white);';
setCss(
(str1 + '-webkit- '.split(' ').join(str2 + str1) +
prefixes.join(str3 + str1)).slice(0, -str1.length)
// legacy webkit syntax (FIXME: remove when syntax not in use anymore)
(str1 + '-webkit- '.split(' ').join(str2 + str1) +
// standard syntax // trailing 'background-image:'
prefixes.join(str3 + str1)).slice(0, -str1.length)
);
return contains(mStyle.backgroundImage, 'gradient');
......@@ -408,9 +654,15 @@ window.Modernizr = (function( window, document, undefined ) {
var ret = !!testPropsAll('perspective');
if ( ret && 'webkitPerspective' in docElement.style ) {
// Webkit's 3D transforms are passed off to the browser's own graphics renderer.
// It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
// some conditions. As a result, Webkit typically recognizes the syntax but
// will sometimes throw a false positive, thus we must do a more thorough check:
if ( ret && 'webkitPerspective' in docElement.style ) {
injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
// Webkit allows this media query to succeed only if the feature is enabled.
// `@media (transform-3d),(-webkit-transform-3d){ ... }`
injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
ret = node.offsetLeft === 9 && node.offsetHeight === 3;
});
}
......@@ -423,7 +675,13 @@ window.Modernizr = (function( window, document, undefined ) {
};
/*>>fontface*/
// @font-face detection routine by Diego Perini
// javascript.nwbox.com/CSSSupport/
// false positives:
// WebOS github.com/Modernizr/Modernizr/issues/342
// WP7 github.com/Modernizr/Modernizr/issues/538
tests['fontface'] = function() {
var bool;
......@@ -437,7 +695,9 @@ window.Modernizr = (function( window, document, undefined ) {
return bool;
};
/*>>fontface*/
// CSS generated content detection
tests['generatedcontent'] = function() {
var bool;
......@@ -447,16 +707,35 @@ window.Modernizr = (function( window, document, undefined ) {
return bool;
};
// These tests evaluate support of the video/audio elements, as well as
// testing what types of content they support.
//
// We're using the Boolean constructor here, so that we can extend the value
// e.g. Modernizr.video // true
// Modernizr.video.ogg // 'probably'
//
// Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
// thx to NielsLeenheer and zcorpan
// Note: in some older browsers, "no" was a return value instead of empty string.
// It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
// It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
tests['video'] = function() {
var elem = document.createElement('video'),
bool = false;
try {
// IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
try {
if ( bool = !!elem.canPlayType ) {
bool = new Boolean(bool);
bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,'');
bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
// Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
}
......@@ -476,7 +755,10 @@ window.Modernizr = (function( window, document, undefined ) {
bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,'');
bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
// Mimetypes accepted:
// developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
// bit.ly/iphoneoscodecs
bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
bool.m4a = ( elem.canPlayType('audio/x-m4a;') ||
elem.canPlayType('audio/aac;')) .replace(/^no$/,'');
}
......@@ -486,6 +768,23 @@ window.Modernizr = (function( window, document, undefined ) {
};
// In FF4, if disabled, window.localStorage should === null.
// Normally, we could not test that directly and need to do a
// `('localStorage' in window) && ` test first because otherwise Firefox will
// throw bugzil.la/365772 if cookies are disabled
// Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
// will throw the exception:
// QUOTA_EXCEEDED_ERRROR DOM Exception 22.
// Peculiarly, getItem and removeItem calls do not throw.
// Because we are forced to try/catch this, we'll go aggressive.
// Just FWIW: IE8 Compat mode supports these features completely:
// www.quirksmode.org/dom/html5.html
// But IE8 doesn't support either with local files
tests['localstorage'] = function() {
try {
localStorage.setItem(mod, mod);
......@@ -517,43 +816,79 @@ window.Modernizr = (function( window, document, undefined ) {
};
// Thanks to Erik Dahlstrom
tests['svg'] = function() {
return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
};
// specifically for SVG inline in HTML, not within XHTML
// test page: paulirish.com/demo/inline-svg
tests['inlinesvg'] = function() {
var div = document.createElement('div');
div.innerHTML = '<svg/>';
return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
};
// SVG SMIL animation
tests['smil'] = function() {
return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
};
// This test is only for clip paths in SVG proper, not clip paths on HTML content
// demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
// However read the comments to dig into applying SVG clippaths to HTML content here:
// github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
tests['svgclippaths'] = function() {
return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
};
/*>>webforms*/
// input features and input types go directly onto the ret object, bypassing the tests loop.
// Hold this guy to execute in a moment.
function webforms() {
Modernizr['input'] = (function( props ) {
/*>>input*/
// Run through HTML5's new input attributes to see if the UA understands any.
// We're using f which is the <input> element created early on
// Mike Taylr has created a comprehensive resource for testing these attributes
// when applied to all input types:
// miketaylr.com/code/input-type-attr.html
// spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
// Only input placeholder is tested while textarea's placeholder is not.
// Currently Safari 4 and Opera 11 have support only for the input placeholder
// Both tests are available in feature-detects/forms-placeholder.js
Modernizr['input'] = (function( props ) {
for ( var i = 0, len = props.length; i < len; i++ ) {
attrs[ props[i] ] = !!(props[i] in inputElem);
}
if (attrs.list){
attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
// safari false positive's on datalist: webk.it/74252
// see also github.com/Modernizr/Modernizr/issues/146
attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
}
return attrs;
})('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
Modernizr['inputtypes'] = (function(props) {
/*>>input*/
/*>>inputtypes*/
// Run through HTML5's new input types to see if the UA understands any.
// This is put behind the tests runloop because it doesn't return a
// true/false like all the other tests; instead, it returns an object
// containing each input type with its corresponding true/false value
// Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
Modernizr['inputtypes'] = (function(props) {
for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
inputElem.setAttribute('type', inputElemType = props[i]);
bool = inputElem.type !== 'text';
if ( bool ) {
// We first check to see if the type we give it sticks..
// If the type does, we feed it a textual value, which shouldn't be valid.
// If the value doesn't stick, we know there's input sanitization which infers a custom UI
if ( bool ) {
inputElem.value = smile;
inputElem.style.cssText = 'position:absolute;visibility:hidden;';
......@@ -563,18 +898,29 @@ window.Modernizr = (function( window, document, undefined ) {
docElement.appendChild(inputElem);
defaultView = document.defaultView;
bool = defaultView.getComputedStyle &&
// Safari 2-4 allows the smiley as a value, despite making a slider
bool = defaultView.getComputedStyle &&
defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
(inputElem.offsetHeight !== 0);
// Mobile android web browser has false positive, so must
// check the height to see if the widget is actually there.
(inputElem.offsetHeight !== 0);
docElement.removeChild(inputElem);
} else if ( /^(search|tel)$/.test(inputElemType) ){
} else if ( /^(url|email)$/.test(inputElemType) ) {
bool = inputElem.checkValidity && inputElem.checkValidity() === false;
// Spec doesn't define any special parsing or detectable UI
// behaviors so we pass these through as true
// Interestingly, opera fails the earlier test, so it doesn't
// even make it here.
} else if ( /^(url|email)$/.test(inputElemType) ) {
// Real url and email support comes with prebaked validation.
bool = inputElem.checkValidity && inputElem.checkValidity() === false;
} else {
bool = inputElem.value != smile;
// If the upgraded input compontent rejects the :) text, we got a winner
bool = inputElem.value != smile;
}
}
......@@ -582,19 +928,44 @@ window.Modernizr = (function( window, document, undefined ) {
}
return inputs;
})('search tel url email datetime date month week time datetime-local number range color'.split(' '));
}
/*>>inputtypes*/
}
/*>>webforms*/
// End of test definitions
// -----------------------
// Run through all tests and detect their support in the current UA.
// todo: hypothetically we could be doing an array of tests and use a basic loop here.
for ( var feature in tests ) {
if ( hasOwnProp(tests, feature) ) {
featureName = feature.toLowerCase();
// run the test, throw the return value into the Modernizr,
// then based on that boolean, define an appropriate className
// and push it into an array of classes we'll join later.
featureName = feature.toLowerCase();
Modernizr[featureName] = tests[feature]();
classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
}
}
/*>>webforms*/
// input tests need to run.
Modernizr.input || webforms();
/*>>webforms*/
/**
* addTest allows the user to define their own feature tests
* the result will be added onto the Modernizr object,
* as well as an appropriate className set on the html element
*
* @param feature - String naming the feature
* @param test - Function returning true if feature is supported, false if not
*/
Modernizr.addTest = function ( feature, test ) {
if ( typeof feature == 'object' ) {
for ( var key in feature ) {
......@@ -607,7 +978,12 @@ window.Modernizr = (function( window, document, undefined ) {
feature = feature.toLowerCase();
if ( Modernizr[feature] !== undefined ) {
return Modernizr;
// we're going to quit if you're trying to overwrite an existing test
// if we were to allow it, we'd do this:
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
// docElement.className = docElement.className.replace( re, '' );
// but, no rly, stuff 'em.
return Modernizr;
}
test = typeof test == 'function' ? test() : test;
......@@ -619,82 +995,412 @@ window.Modernizr = (function( window, document, undefined ) {
}
return Modernizr;
return Modernizr; // allow chaining.
};
// Reset modElem.cssText to nothing to reduce memory footprint.
setCss('');
modElem = inputElem = null;
/*>>shiv*/
/**
* @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
;(function(window, document) {
/*jshint evil:true */
/** version */
var version = '3.7.0';
/** Preset options */
var options = window.html5 || {};
/** Used to skip problem elements */
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
/** Not all elements can be cloned in IE **/
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
/** Detect whether the browser supports default html5 styles */
var supportsHtml5Styles;
/** Name of the expando, to work with multiple documents or to re-shiv one document */
var expando = '_html5shiv';
/** The id for the the documents expando */
var expanID = 0;
/** Cached data for each document */
var expandoData = {};
/** Detect whether the browser supports unknown elements */
var supportsUnknownElements;
(function() {
try {
var a = document.createElement('a');
a.innerHTML = '<xyz></xyz>';
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
supportsHtml5Styles = ('hidden' in a);
supportsUnknownElements = a.childNodes.length == 1 || (function() {
// assign a false positive if unable to shiv
(document.createElement)('a');
var frag = document.createDocumentFragment();
return (
typeof frag.cloneNode == 'undefined' ||
typeof frag.createDocumentFragment == 'undefined' ||
typeof frag.createElement == 'undefined'
);
}());
} catch(e) {
// assign a false positive if detection fails => unable to shiv
supportsHtml5Styles = true;
supportsUnknownElements = true;
}
}());
/*--------------------------------------------------------------------------*/
/**
* Creates a style sheet with the given CSS text and adds it to the document.
* @private
* @param {Document} ownerDocument The document.
* @param {String} cssText The CSS text.
* @returns {StyleSheet} The style element.
*/
function addStyleSheet(ownerDocument, cssText) {
var p = ownerDocument.createElement('p'),
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
p.innerHTML = 'x<style>' + cssText + '</style>';
return parent.insertBefore(p.lastChild, parent.firstChild);
}
/**
* Returns the value of `html5.elements` as an array.
* @private
* @returns {Array} An array of shived element node names.
*/
function getElements() {
var elements = html5.elements;
return typeof elements == 'string' ? elements.split(' ') : elements;
}
/**
* Returns the data associated to the given document
* @private
* @param {Document} ownerDocument The document.
* @returns {Object} An object of data.
*/
function getExpandoData(ownerDocument) {
var data = expandoData[ownerDocument[expando]];
if (!data) {
data = {};
expanID++;
ownerDocument[expando] = expanID;
expandoData[expanID] = data;
}
return data;
}
/**
* returns a shived element for the given nodeName and document
* @memberOf html5
* @param {String} nodeName name of the element
* @param {Document} ownerDocument The context document.
* @returns {Object} The shived element.
*/
function createElement(nodeName, ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createElement(nodeName);
}
if (!data) {
data = getExpandoData(ownerDocument);
}
var node;
if (data.cache[nodeName]) {
node = data.cache[nodeName].cloneNode();
} else if (saveClones.test(nodeName)) {
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
} else {
node = data.createElem(nodeName);
}
// Avoid adding some elements to fragments in IE < 9 because
// * Attributes like `name` or `type` cannot be set/changed once an element
// is inserted into a document/fragment
// * Link elements with `src` attributes that are inaccessible, as with
// a 403 response, will cause the tab/window to crash
// * Script elements appended to fragments will execute when their `src`
// or `text` property is set
return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
}
/**
* returns a shived DocumentFragment for the given document
* @memberOf html5
* @param {Document} ownerDocument The context document.
* @returns {Object} The shived DocumentFragment.
*/
function createDocumentFragment(ownerDocument, data){
if (!ownerDocument) {
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createDocumentFragment();
}
data = data || getExpandoData(ownerDocument);
var clone = data.frag.cloneNode(),
i = 0,
elems = getElements(),
l = elems.length;
for(;i<l;i++){
clone.createElement(elems[i]);
}
return clone;
}
/**
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
* @private
* @param {Document|DocumentFragment} ownerDocument The document.
* @param {Object} data of the document.
*/
function shivMethods(ownerDocument, data) {
if (!data.cache) {
data.cache = {};
data.createElem = ownerDocument.createElement;
data.createFrag = ownerDocument.createDocumentFragment;
data.frag = data.createFrag();
}
ownerDocument.createElement = function(nodeName) {
//abort shiv
if (!html5.shivMethods) {
return data.createElem(nodeName);
}
return createElement(nodeName, ownerDocument, data);
};
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
'var n=f.cloneNode(),c=n.createElement;' +
'h.shivMethods&&(' +
// unroll the `createElement` calls
getElements().join().replace(/[\w\-]+/g, function(nodeName) {
data.createElem(nodeName);
data.frag.createElement(nodeName);
return 'c("' + nodeName + '")';
}) +
');return n}'
)(html5, data.frag);
}
/*--------------------------------------------------------------------------*/
/**
* Shivs the given document.
* @memberOf html5
* @param {Document} ownerDocument The document to shiv.
* @returns {Document} The shived document.
*/
function shivDocument(ownerDocument) {
if (!ownerDocument) {
ownerDocument = document;
}
var data = getExpandoData(ownerDocument);
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
data.hasCSS = !!addStyleSheet(ownerDocument,
// corrects block display not defined in IE6/7/8/9
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
// adds styling not present in IE6/7/8/9
'mark{background:#FF0;color:#000}' +
// hides non-rendered elements
'template{display:none}'
);
}
if (!supportsUnknownElements) {
shivMethods(ownerDocument, data);
}
return ownerDocument;
}
/*--------------------------------------------------------------------------*/
/**
* The `html5` object is exposed so that more elements can be shived and
* existing shiving can be detected on iframes.
* @type Object
* @example
*
* // options can be changed before the script is included
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
*/
var html5 = {
/**
* An array or space separated string of node names of the elements to shiv.
* @memberOf html5
* @type Array|String
*/
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video',
/**
* current version of html5shiv
*/
'version': version,
/**
* A flag to indicate that the HTML5 style sheet should be inserted.
* @memberOf html5
* @type Boolean
*/
'shivCSS': (options.shivCSS !== false),
/**
* Is equal to true if a browser supports creating unknown/HTML5 elements
* @memberOf html5
* @type boolean
*/
'supportsUnknownElements': supportsUnknownElements,
/**
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
* methods should be overwritten.
* @memberOf html5
* @type Boolean
*/
'shivMethods': (options.shivMethods !== false),
/**
* A string to describe the type of `html5` object ("default" or "default print").
* @memberOf html5
* @type String
*/
'type': 'default',
// shivs the document according to the specified `html5` object options
'shivDocument': shivDocument,
//creates a shived element
createElement: createElement,
//creates a shived documentFragment
createDocumentFragment: createDocumentFragment
};
/*--------------------------------------------------------------------------*/
// expose html5
window.html5 = html5;
// shiv the document
shivDocument(document);
}(this, document));
/*>>shiv*/
// Assign private properties to the return object with prefix
Modernizr._version = version;
// expose these for the plugin API. Look in the source for how to join() them against your input
/*>>prefixes*/
Modernizr._prefixes = prefixes;
/*>>prefixes*/
/*>>domprefixes*/
Modernizr._domPrefixes = domPrefixes;
Modernizr._cssomPrefixes = cssomPrefixes;
/*>>domprefixes*/
/*>>mq*/
// Modernizr.mq tests a given media query, live against the current state of the window
// A few important notes:
// * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
// * A max-width or orientation query will be evaluated against the current state, which may change later.
// * You must specify values. Eg. If you are testing support for the min-width media query use:
// Modernizr.mq('(min-width:0)')
// usage:
// Modernizr.mq('only screen and (max-width:768)')
Modernizr.mq = testMediaQuery;
/*>>mq*/
/*>>hasevent*/
// Modernizr.hasEvent() detects support for a given event, with an optional element to test on
// Modernizr.hasEvent('gesturestart', elem)
Modernizr.hasEvent = isEventSupported;
/*>>hasevent*/
/*>>testprop*/
// Modernizr.testProp() investigates whether a given style property is recognized
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testProp('pointerEvents')
Modernizr.testProp = function(prop){
return testProps([prop]);
};
/*>>testprop*/
/*>>testallprops*/
// Modernizr.testAllProps() investigates whether a given style property,
// or any of its vendor-prefixed variants, is recognized
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testAllProps('boxSizing')
Modernizr.testAllProps = testPropsAll;
/*>>testallprops*/
/*>>teststyles*/
// Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
// Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
Modernizr.testStyles = injectElementWithStyles;
/*>>teststyles*/
/*>>prefixed*/
// Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
// Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
// Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
// Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
//
// str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
// If you're trying to ascertain which transition end event to bind to, you might do something like...
//
// var transEndEventNames = {
// 'WebkitTransition' : 'webkitTransitionEnd',
// 'MozTransition' : 'transitionend',
// 'OTransition' : 'oTransitionEnd',
// 'msTransition' : 'MSTransitionEnd',
// 'transition' : 'transitionend'
// },
// transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
Modernizr.prefixed = function(prop, obj, elem){
if(!obj) {
return testPropsAll(prop, 'pfx');
} else {
return testPropsAll(prop, obj, elem);
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
return testPropsAll(prop, obj, elem);
}
};
/*>>prefixed*/
/*>>cssclasses*/
// Remove "no-js" class from <html> element, if it exists:
docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
// Add the new classes to the <html> element.
(enableClasses ? ' js ' + classes.join(' ') : '');
/*>>cssclasses*/
return Modernizr;
})(this, this.document);
// Blob constructor
// http://dev.w3.org/2006/webapi/FileAPI/#constructorBlob
Modernizr.addTest('blobconstructor', function () {
try {
return !!new Blob();
} catch (e) {
return false;
}
});
// cors
// By Theodoor van Donge
Modernizr.addTest('cors', !!(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()));/**
* file tests for the File API specification
* Tests for objects specific to the File API W3C specification without
* being redundant (don't bother testing for Blob since it is assumed
* to be the File object's prototype.
*
* Will fail in Safari 5 due to its lack of support for the standards
* defined FileReader object
*/
Modernizr.addTest('filereader', function () {
return !!(window.File && window.FileList && window.FileReader);
});
// Filesystem API
// dev.w3.org/2009/dap/file-system/file-dir-sys.html
// The API will be present in Chrome incognito, but will throw an exception.
// See crbug.com/93417
//
// By Eric Bidelman (@ebidel)
Modernizr.addTest('filesystem', !!Modernizr.prefixed('requestFileSystem', window));// native JSON support.
// developer.mozilla.org/en/JSON
// this will also succeed if you've loaded the JSON2.js polyfill ahead of time
// ... but that should be obvious. :)
Modernizr.addTest('json', !!window.JSON && !!JSON.parse);
;
\ No newline at end of file
/*
* jQuery validVal version 5.0.2
* demo's and documentation:
* validval.frebsite.nl
*
* Copyright (c) 2013 Fred Heusschen
* www.frebsite.nl
*
* Dual licensed under the MIT and GPL licenses.
* http://en.wikipedia.org/wiki/MIT_License
* http://en.wikipedia.org/wiki/GNU_General_Public_License
*/
(function( $ )
{
var _PLUGIN_ = 'validVal',
_FIELD_ = 'validValField',
_VERSION_ = '5.0.2',
_INPUTS_ = 'textarea, select, input:not( [type="button"], [type="submit"], [type="reset"] )';
// validVal already excists
if ( $.fn[ _PLUGIN_ ] )
{
return;
}
function ValidVal( form, opts )
{
this.form = form;
this.opts = $.extend( true, {}, $.fn[ _PLUGIN_ ].defaults, opts );
this._gatherValidation();
this._bindEvents();
this._bindCustomEvents();
this.addField( this.opts.validate.fields.filter( $(_INPUTS_, this.form) ) );
}
ValidVal.prototype = {
// Public methods
addField: function( $field )
{
if ( isHtmlElement( $field ) || typeof $field == 'string' )
{
$field = $( $field );
}
if ( !( $field instanceof $ ) )
{
$.fn[ _PLUGIN_ ].debug( 'Not a valid argument for "$field"' );
return this;
}
var that = this;
return $field.each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.destroy();
}
$f.data( _FIELD_, new ValidValField( $f, that ) );
}
);
},
validate: function( body, callCallback )
{
var that = this;
// Complement arguments
if ( typeof body == 'undefined' )
{
body = this.form;
callCallback = true;
}
else if ( typeof callCallback != 'boolean' )
{
callCallback = false;
}
if ( typeof this.opts.form.onValidate == 'function' )
{
this.opts.form.onValidate.call( this.form[ 0 ], this.opts.language );
}
// Set varialbes
var miss_arr = $(),
data_obj = {};
// Validate fields
this.opts.validate.fields.filter( $(_INPUTS_, body) ).each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.validate( that.opts.validate.onSubmit )
if ( vf.valid )
{
var v = $f.val();
if ( $f.is( '[type="radio"]' ) || $f.is( '[type="checkbox"]' ) )
{
if ( !$f.is( ':checked' ) )
{
v = '';
}
}
if ( typeof v == 'undefined' || v == null )
{
v = '';
}
data_obj[ $f.attr( 'name' ) ] = v;
}
else
{
if ( that.opts.validate.onSubmit !== false )
{
miss_arr = miss_arr.add( $f );
}
}
}
}
);
// Not valid
if ( miss_arr.length > 0 )
{
if ( typeof this.opts.form.onInvalid == 'function' && callCallback )
{
this.opts.form.onInvalid.call( this.form[ 0 ], miss_arr, this.opts.language );
}
return false;
}
// Valid
else
{
if ( typeof this.opts.form.onValid == 'function' && callCallback )
{
this.opts.form.onValid.call( this.form[ 0 ], this.opts.language );
}
return data_obj;
}
},
submitForm: function()
{
var result = this.validate();
if ( result )
{
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf )
{
vf.clearPlaceholderValue();
}
}
);
}
return result;
},
resetForm: function()
{
var that = this;
if ( typeof this.opts.form.onReset == 'function' )
{
this.opts.form.onReset.call( this.form[ 0 ], this.opts.language );
}
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
if ( vf.placeholderValue !== false )
{
$f.addClass( 'inactive' );
$f.val( vf.placeholderValue );
}
else
{
$f.val( vf.originalValue );
}
vf.isValid( true, true );
}
}
);
return true;
},
options: function( o )
{
if ( typeof o == 'object' )
{
this.opts = $.extend( this.opts, o );
}
return this.opts;
},
destroy: function()
{
this.form.unbind( '.vv' );
this.form.data( _PLUGIN_, null );
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf )
{
vf.destroy();
}
}
);
return true;
},
// Protected methods
_gatherValidation: function()
{
this.opts.validations = {};
if ( $.fn[ _PLUGIN_ ].customValidations )
{
this.opts.validations = $.extend( this.opts.validations, $.fn[ _PLUGIN_ ].customValidations );
}
if ( this.opts.customValidations )
{
this.opts.validations = $.extend( this.opts.validations, this.opts.customValidations );
}
this.opts.validations = $.extend( this.opts.validations, $.fn[ _PLUGIN_ ].defaultValidations );
return this;
},
_bindEvents: function ()
{
var that = this;
if ( this.form.is( 'form' ) )
{
this.form.attr( 'novalidate', 'novalidate' );
this.form.bind(
namespace( 'submit' ),
function( event, validate )
{
if ( typeof validate != 'boolean' )
{
validate = true;
}
return ( validate )
? that.submitForm()
: true;
}
);
this.form.bind(
namespace( 'reset' ),
function( event )
{
return that.resetForm();
}
);
}
return this;
},
_bindCustomEvents: function()
{
var that = this;
this.form.bind(
namespace([
'addField',
'destroy',
'validate',
'submitForm',
'resetForm',
'options'
]),
function()
{
arguments = Array.prototype.slice.call( arguments );
var event = arguments.shift(),
type = event.type;
event.stopPropagation();
if ( typeof that[ type ] != 'function' )
{
$.fn.validVal.debug( 'Public method "' + type + '" not found.' );
return false;
}
return that[ type ].apply( that, arguments );
}
);
return this;
}
};
function ValidValField( field, form )
{
this.field = field;
this.form = form;
this.originalValue = this.field.attr( 'value' ) || '';
this._gatherValidations();
this._bindEvents();
this._bindCustomEvents();
this._init();
}
ValidValField.prototype = {
// Public methods
validate: function( onEvent, fixPlaceholder )
{
var that = this;
if ( onEvent === false )
{
return;
}
if ( typeof fixPlaceholder != 'boolean' )
{
fixPlaceholder = true;
}
this.valid = true;
if ( ( this.field.is( ':hidden' ) && !this.form.opts.validate.fields.hidden ) ||
( this.field.is( ':disabled' ) && !this.form.opts.validate.fields.disabled )
) {
return true;
}
if ( fixPlaceholder )
{
this.clearPlaceholderValue();
}
if ( typeof this.form.opts.fields.onValidate == 'function' )
{
this.form.opts.fields.onValidate.call( this.field[ 0 ], this.form.form, this.form.opts.language );
}
var invalid_check = false,
val = trim( this.field.val() );
for ( var v in this.form.opts.validations )
{
var f = this.form.opts.validations[ v ];
if ( typeof f == 'function' && $.inArray( v, this.validations ) != -1 )
{
if ( !f.call( this.field[ 0 ], val ) )
{
invalid_check = v;
break;
}
}
}
this.valid = ( invalid_check ) ? false : true;
var callCallback = ( this.valid )
? ( onEvent !== 'invalid' )
: ( onEvent !== 'valid' );
this.isValid( this.valid, callCallback, invalid_check );
if ( this.validationgroup !== false )
{
$(_INPUTS_).not( this.field ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf && vf.validationgroup == that.validationgroup )
{
vf.isValid( that.valid, true );
}
}
);
}
if ( fixPlaceholder )
{
this.restorePlaceholderValue();
}
if ( invalid_check )
{
$.fn[ _PLUGIN_ ].debug( 'invalid validation: ' + invalid_check );
}
return this.valid;
},
isValid: function( valid, callCallback )
{
if ( typeof valid == 'boolean' )
{
this.valid = valid;
if ( callCallback )
{
var fn = ( valid ) ? 'onValid' : 'onInvalid';
if ( typeof this.form.opts.fields[ fn ] == 'function' )
{
this.form.opts.fields[ fn ].call( this.field[ 0 ], this.form.form, this.form.opts.language );
}
}
}
return this.valid;
},
getValidations: function()
{
return this.validations;
},
setValidations: function( validations )
{
if ( typeof validations == 'string' )
{
this.validations = validations.split( ' ' );
}
else if ( validations instanceof Array )
{
this.validations = validations;
}
else
{
$.fn.validVal.debug( 'Argument "validations" should be an array.' );
}
return this.validations;
},
addValidation: function( validation )
{
if ( typeof validation == 'string' )
{
validation = validation.split( ' ' );
}
for( var v in validation )
{
this.validations.push( validation[ v ] );
}
return this.validations;
},
removeValidation: function( validation )
{
if ( typeof validation == 'string' )
{
validation = validation.split( ' ' );
}
for( var v in validation )
{
var pos = $.inArray( validation[ v ], this.validations );
if ( pos != -1 )
{
this.validations.splice( pos, 1 );
}
}
return this.validations;
},
clearPlaceholderValue: function()
{
this._togglePlaceholderValue( 'clear' );
return true;
},
restorePlaceholderValue: function()
{
this._togglePlaceholderValue( 'restore' );
return true;
},
destroy: function()
{
this.field.unbind( '.vv' );
this.field.data( _FIELD_, null );
return true;
},
// Protected methods
_gatherValidations: function()
{
this.autotab = false;
this.corresponding = false;
this.requiredgroup = false;
this.validationgroup = false;
this.placeholderValue = false;
this.placeholderNumber = false;
this.passwordplaceholder = false;
this.validations = [];
if ( this.field.is( 'select' ) )
{
this.originalValue = this.field.find( 'option:first' ).attr( 'value' ) || '';
}
else if ( this.field.is( 'textarea' ) )
{
this.originalValue = this.field.text();
}
// Refactor HTML5 usage
if ( this.form.opts.supportHtml5 )
{
var valids = this.field.data( 'vv-validations' );
if ( valids )
{
this.validations.push( valids );
this.__removeAttr( 'data-vv-validations' );
}
// Placeholder attribute, only use if placeholder not supported by browser or placeholder not in keepAttributes-option
if ( this.__hasHtml5Attr( 'placeholder' ) && this.field.attr( 'placeholder' ).length > 0 )
{
if ( !$.fn[ _PLUGIN_ ].support.placeholder || $.inArray( 'placeholder', this.form.opts.keepAttributes ) == -1 )
{
this.placeholderValue = this.field.attr( 'placeholder' );
}
}
if ( this.placeholderValue !== false )
{
this.__removeAttr( 'placeholder' );
}
// Pattern attribute
if ( this.__hasHtml5Attr( 'pattern' ) && this.field.attr( 'pattern' ).length > 0 )
{
this.pattern = this.field.attr( 'pattern' );
this.validations.push( 'pattern' );
this.__removeAttr( 'pattern' );
}
// Corresponding, required group and validation group
var dts = [ 'corresponding', 'requiredgroup', 'validationgroup' ];
for ( var d = 0, l = dts.length; d < l; d++ )
{
var dt = this.field.data( 'vv-' + dts[ d ] );
if ( dt )
{
this[ dts[ d ] ] = dt;
this.validations.push( dts[ d ] );
this.__removeAttr( 'data-vv-' + dts[ d ] );
}
}
// Attributes
var atr = [ 'required', 'autofocus' ];
for ( var a = 0, l = atr.length; a < l; a++ )
{
if ( this.__hasHtml5Attr( atr[ a ] ) )
{
this.validations.push( atr[ a ] );
this.__removeAttr( atr[ a ] );
}
}
// Type-values
var typ = [ 'number', 'email', 'url' ];
for ( var t = 0, l = typ.length; t < l; t++ )
{
if ( this.__hasHtml5Type( typ[ t ] ) )
{
this.validations.push( typ[ t ] );
}
}
// Autotab
if ( this.field.data( 'vv-autotab' ) )
{
this.autotab = true;
this.__removeAttr( 'data-vv-autotab' );
}
}
// Refactor non-HTML5 usage
var classes = this.field.attr( 'class' );
if ( classes && classes.length )
{
// Placeholder
if ( this.field.hasClass( 'placeholder' ) )
{
if ( this.field.is( 'select' ) )
{
var num = 0,
opt = this.field.data( 'vv-placeholder-number' );
if ( opt )
{
num = opt;
this.__removeAttr( 'data-vv-placeholder-number' );
}
else if ( typeof this.form.opts.selectPlaceholder == 'number' )
{
num = this.form.opts.selectPlaceholder;
}
else
{
var $options = this.field.find( 'option' ),
selected = $options.index( $options.filter( '[selected]' ) );
if ( selected > -1 )
{
num = selected;
}
}
this.placeholderNumber = num;
this.originalValue = this.field.find( 'option:eq( ' + num + ' )' ).attr( 'value' ) || '';
}
this.placeholderValue = this.originalValue;
this.originalValue = '';
this.__removeClass( 'placeholder' );
}
// Corresponding
var corsp = 'corresponding:',
start = classes.indexOf( corsp );
if ( start != -1 )
{
var corrcls = classes.substr( start ).split( ' ' )[ 0 ],
corresp = corrcls.substr( corsp.length );
if ( corresp.length )
{
this.corresponding = corresp;
this.validations.push( 'corresponding' );
this.field.removeClass( corrcls );
}
}
// Pattern
// still uses alt-attribute...
if ( this.field.hasClass( 'pattern' ) )
{
this.pattern = this.field.attr( 'alt' ) || '';
this.validations.push( 'pattern' );
this.__removeAttr( 'alt' );
this.__removeClass( 'pattern' );
}
// Groups
var grp = [ 'requiredgroup', 'validationgroup' ];
for ( var g = 0, l = grp.length; g < l; g++ )
{
var group = grp[ g ] + ':',
start = classes.indexOf( group );
if ( start != -1 )
{
var groupclass = classes.substr( start ).split( ' ' )[ 0 ],
groupname = groupclass.substr( group.length );
if ( groupname.length )
{
this[ grp[ g ] ] = groupname;
this.validations.push( grp[ g ]);
this.field.removeClass( groupclass );
}
}
}
// Autotab
if ( this.field.hasClass( 'autotab' ) )
{
this.autotab = true;
this.__removeClass( 'autotab' );
}
}
// Password placeholder
if ( this.placeholderValue !== false && this.field.is( '[type="password"]' ) )
{
this.passwordplaceholder = true;
}
// Add all remaining classes
var classes = this.field.attr( 'class' );
if ( classes && classes.length )
{
this.validations.push( classes );
}
this.validations = unique( this.validations.join( ' ' ).split( ' ' ) );
return this;
},
_bindEvents: function()
{
var that = this;
this.field.bind(
namespace( 'focus' ),
function( event )
{
$(this).addClass( 'focus' );
that.clearPlaceholderValue();
}
);
this.field.bind(
namespace( 'blur' ),
function( event )
{
$(this).removeClass( 'focus' );
that.validate( that.form.opts.validate.onBlur );
}
);
this.field.bind(
namespace( 'keyup' ),
function( event )
{
if ( !preventkeyup( event.keyCode ) )
{
that.validate( that.form.opts.validate.onKeyup, false );
}
}
);
if ( this.field.is( 'select, input[type="checkbox"], input[type="radio"]' ) )
{
this.field.bind(
namespace( 'change' ),
function( event )
{
$(this).trigger( namespace( 'blur' ) );
}
);
}
return this;
},
_bindCustomEvents: function()
{
var that = this;
this.field.bind(
namespace([
'validate',
'isValid',
'destroy',
'addValidation',
'removeValidation'
]),
function()
{
arguments = Array.prototype.slice.call( arguments );
var event = arguments.shift(),
type = event.type;
event.stopPropagation();
if ( typeof that[ type ] != 'function' )
{
$.fn.validVal.debug( 'Public method "' + type + '" not found.' );
return false;
}
return that[ type ].apply( that, arguments );
}
);
this.field.bind(
namespace([ 'validations' ]),
function( event, validations, callCallback )
{
if ( typeof validations == 'undefined' )
{
return this.getValidations();
}
else
{
return this.setValidations( validations, callCallback );
}
}
);
return this;
},
_init: function()
{
var that = this;
// Placeholder
if ( this.placeholderValue !== false )
{
if ( this.field.val() == '' )
{
this.field.val( this.placeholderValue );
}
if ( this.passwordplaceholder )
{
if ( this.field.val() == this.placeholderValue ) try
{
this.field[ 0 ].type = 'text';
}
catch( err ) {};
}
if ( this.field.val() == this.placeholderValue )
{
this.field.addClass( 'inactive' );
}
if ( this.field.is( 'select' ) )
{
this.field.find( 'option:eq(' + this.placeholderNumber + ')' ).addClass( 'inactive' );
this.field.bind(
namespace( 'change' ),
function( event )
{
$(this)[ that.field.val() == that.placeholderValue ? 'addClass' : 'removeClass' ]( 'inactive' );
}
);
}
}
// Corresponding
if ( this.corresponding !== false )
{
$(_INPUTS_).filter('[name="' + this.corresponding + '"]').bind(
namespace( 'blur' ),
function( event )
{
that.validate( that.form.opts.validate.onBlur );
}
).bind(
namespace( 'keyup' ),
function( event )
{
if ( !preventkeyup( event.keyCode ) )
{
that.validate( that.form.opts.validate.onKeyup, false );
}
}
);
}
// Autotabbing
if ( this.autotab )
{
var max = this.field.attr( 'maxlength' ),
tab = this.field.attr( 'tabindex' ),
$next = $(_INPUTS_).filter('[tabindex="' + ( parseInt( tab ) + 1 ) + '"]');
if ( this.field.is( 'select' ) )
{
if ( tab )
{
this.field.bind(
namespace( 'change' ),
function( event )
{
if ( $next.length )
{
$next.focus();
}
}
);
}
}
else
{
if ( max && tab )
{
this.field.bind(
namespace( 'keyup' ),
function( event )
{
if ( $(this).val().length == max )
{
if ( !preventkeyup( event.keyCode ) )
{
$(this).trigger( namespace( 'blur' ) );
if ( $next.length )
{
$next.focus();
}
}
}
}
);
}
}
}
// Autofocus
if ( $.inArray( 'autofocus', this.validations ) != -1 && !this.field.is( ':disabled' ) )
{
this.field.focus();
}
return this;
},
_togglePlaceholderValue: function( toggle )
{
if ( this.placeholderValue !== false )
{
if ( toggle == 'clear' )
{
var v1 = this.placeholderValue,
v2 = '',
cl = 'removeClass',
tp = 'password';
}
else
{
var v1 = '',
v2 = this.placeholderValue,
cl = 'addClass',
tp = 'text';
}
if ( this.field.val() == v1 && !this.field.is( 'select' ) )
{
this.field.val( v2 );
this.field[ cl ]( 'inactive' );
if ( this.passwordplaceholder ) try
{
this.field[ 0 ].type = tp;
}
catch( err ) {};
}
}
return this;
},
// Private methods
__hasHtml5Attr: function( a )
{
// non HTML5 browsers
if ( typeof this.field.attr( a ) == 'undefined' )
{
return false;
}
// HTML5 browsers
if ( this.field.attr( a ) === 'false' || this.field.attr( a ) === false )
{
return false;
}
return true;
},
__hasHtml5Type: function( t )
{
// cool HTML5 browsers
if ( this.field.attr( 'type' ) == t )
{
return true;
}
// non-HTML5 but still cool browsers
if ( this.field.is( 'input[type="' + t + '"]' ) )
{
return true;
}
// non-HTML5, non-cool browser
var $c = $( '<div />' ).append( this.field.clone() ).html()
if ( $c.indexOf( 'type="' + t + '"' ) != -1 || $c.indexOf( 'type=\'' + t + '\'' ) != -1 || $c.indexOf( 'type=' + t + '' ) != -1 )
{
return true;
}
return false;
},
__removeAttr: function( a )
{
if ( $.inArray( a, this.form.opts.keepAttributes ) == -1 )
{
this.field.removeAttr( a );
}
return this;
},
__removeClass: function( c )
{
if ( $.inArray( c, this.form.opts.keepClasses ) == -1 )
{
this.field.removeClass( c );
}
return this;
}
};
$.fn[ _PLUGIN_ ] = function( o, c )
{
return this.each(
function()
{
var $t = $(this);
if ( $t.data( _PLUGIN_ ) )
{
$t.data( _PLUGIN_ ).destroy();
}
$t.data( _PLUGIN_, new ValidVal( $t, o, c ) );
}
);
};
$.fn[ _PLUGIN_ ].version = _VERSION_;
$.fn[ _PLUGIN_ ].defaults = {
'selectPlaceholder' : 0,
'supportHtml5' : true,
'language' : 'en',
'customValidations' : {},
'validate' : {
'onBlur' : true,
'onSubmit' : true,
'onKeyup' : false,
'fields' : {
'hidden' : false,
'disabled' : false,
'filter' : function( $i )
{
return $i;
}
}
},
'fields' : {
'onValidate' : null,
'onValid' : function()
{
$(this).add( $(this).parent() ).removeClass( 'invalid' );
},
'onInvalid' : function()
{
$(this).add( $(this).parent() ).addClass( 'invalid' );
}
},
'form' : {
'onReset' : null,
'onValidate': null,
'onValid' : null,
'onInvalid' : function( fieldArr, language )
{
switch ( language )
{
case 'nl':
msg = 'Let op, niet alle velden zijn correct ingevuld.';
break;
case 'de':
msg = 'Achtung, nicht alle Felder sind korrekt ausgefuellt.';
break;
case 'es':
msg = 'Atención, no se han completado todos los campos correctamente.';
break;
case 'en':
default:
msg = 'Attention, not all fields have been filled out correctly.';
break;
}
alert( msg );
fieldArr.first().focus();
}
},
'keepClasses' : [ 'required' ],
'keepAttributes': [ 'pattern', 'placeholder' ]
};
$.fn[ _PLUGIN_ ].defaultValidations = {
'required': function( v )
{
var $f = $(this);
if ( $f.is( '[type="radio"]' ) || $f.is( '[type="checkbox"]' ) )
{
if ( $f.is( '[type="radio"]' ) )
{
var name = $f.attr( 'name' );
if ( name && name.length > 0 )
{
$f = $( 'input[name="' + name + '"]' );
}
}
if ( !$f.is( ':checked' ) )
{
return false;
}
}
else if ( $f.is( 'select' ) )
{
var vf = $f.data( _FIELD_ );
if ( vf && vf.placeholderValue !== false )
{
if ( $f.val() == vf.placeholderValue )
{
return false;
}
}
else
{
if ( v.length == 0 )
{
return false;
}
}
}
else
{
if ( v.length == 0 )
{
return false;
}
}
return true;
},
'Required': function( v )
{
return $.fn[ _PLUGIN_ ].defaultValidations.required.call( this, v );
},
'requiredgroup': function( v )
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf && vf.requiredgroup !== false )
{
$f = $();
$(_INPUTS_).each(
function()
{
var tf = $(this).data( _FIELD_ );
if ( tf && tf.requiredgroup == vf.requiredgroup )
{
$f = $f.add( this );
}
}
);
}
var result = false;
$f.each(
function()
{
var f = this;
if ( $.fn[ _PLUGIN_ ].defaultValidations.required.call( f, trim( $(f).val() ) ) )
{
result = true;
}
}
);
return result;
},
'corresponding': function( v )
{
var org = '',
vf = $(this).data( _FIELD_ );
if ( vf && vf.corresponding !== false )
{
var $f = $(_INPUTS_).filter('[name="' + vf.corresponding + '"]'),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.clearPlaceholderValue();
org = trim( $f.val() );
vf.restorePlaceholderValue();
}
return ( v == org );
}
return false;
},
'number': function( v )
{
v = stripWhitespace( v );
if ( v.length == 0 )
{
return true;
}
if ( isNaN( v ) )
{
return false;
}
return true;
},
'email': function( v )
{
if ( v.length == 0 )
{
return true;
}
var r = /^([a-zA-Z0-9_\.\-+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
return r.test( v );
},
'url': function( v )
{
if ( v.length == 0 )
{
return true;
}
if ( v.match(/^www\./) )
{
v = "http://" + v;
}
return v.match(/^(http\:\/\/|https\:\/\/)(.{4,})$/);
},
'pattern': function( v )
{
if ( v.length == 0 )
{
return true;
}
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
var p = vf.pattern;
if ( p.slice( 0, 1 ) == '/' )
{
p = p.slice( 1 );
}
if ( p.slice( -1 ) == '/' )
{
p = p.slice( 0, -1 );
}
return new RegExp( p ).test( v );
}
}
};
// test for borwser support
$.fn[ _PLUGIN_ ].support = {
touch: (function()
{
return 'ontouchstart' in document.documentElement;
})(),
placeholder: (function()
{
return 'placeholder' in document.createElement( 'input' );
})()
};
$.fn[ _PLUGIN_ ].debug = function( msg ) {};
$.fn[ _PLUGIN_ ].deprecated = function( func, alt )
{
if ( typeof console != 'undefined' )
{
if ( typeof console.error != 'undefined' )
{
console.error( func + ' is DEPRECATED, use ' + alt + ' instead.' );
}
}
};
// Create debugger is it doesn't already excists
if ( !$.fn.validValDebug )
{
$.fn.validValDebug = function( b )
{
$.fn[ _PLUGIN_ ].debug( 'validVal debugger not installed!' );
return this;
}
}
function isHtmlElement( field )
{
if ( typeof HTMLElement != 'undefined' )
{
return field instanceof HTMLElement;
}
return ( field.nodeType && field.nodeType == Node.ELEMENT_NODE );
}
function namespace( events )
{
if ( typeof events == 'string' )
{
events = events.split( ' ' );
}
return events.join( '.vv ' ) + '.vv';
}
function unique( arr )
{
return $.grep(
arr,
function( v, k )
{
return $.inArray( v, arr ) === k;
}
);
}
function trim( str )
{
if ( str === null )
{
return '';
}
if ( typeof str == 'object' )
{
var arr = [];
for ( var a in str )
{
arr[ a ] = trim( str[ a ] );
}
return arr;
}
if ( typeof str != 'string' )
{
return '';
}
if ( str.length == 0 )
{
return '';
}
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
function stripWhitespace( str )
{
if ( str === null )
{
return '';
}
if ( typeof str == 'object' )
{
for ( var a in str )
{
str[ a ] = stripWhitespace( str[ a ] );
}
return str;
}
if ( typeof str != 'string' )
{
return '';
}
if ( str.length == 0 )
{
return '';
}
str = trim( str );
var r = [ ' ', '-', '+', '(', ')', '/', '\\' ];
for ( var i = 0, l = r.length; i < l; i++ )
{
str = str.split( r[ i ] ).join( '' );
}
return str;
}
function preventkeyup( kc )
{
switch( kc ) {
case 9: // tab
case 13: // enter
case 16: // shift
case 17: // control
case 18: // alt
case 37: // left
case 38: // up
case 39: // right
case 40: // down
case 224: // command
return true;
break;
default:
return false;
break;
}
}
})( jQuery );
\ No newline at end of file
......@@ -29,14 +29,15 @@
<script type="text/javascript" src="ext/libs/jio/erp5storage.js"></script>
<!-- 3rd party plugins -->
<script type="text/javascript" src="js/plugins/state/state.js"></script>
<script type="text/javascript" src="js/plugins/validval/jquery.validVal.js"></script>
<script type="text/javascript" src="js/plugins/i18next/i18next.js"></script>
<script type="text/javascript" src="js/plugins/modernizr/modernizr.js"></script>
<script type="text/javascript" src="js/plugins/selectivzr/selectivzr.js"></script>
<script type="text/javascript" src="js/plugins/hellojs/hellojs.js"></script>
<!-- <script type="text/javascript" src="js/plugins/jspdf/jspdf.js"></script> -->
<script type="text/javascript" src="js/shims.js"></script>
<script type="text/javascript" src="ext/plugins/modernizr/modernizr.js"></script>
<script type="text/javascript" src="ext/plugins/state/state.js"></script>
<script type="text/javascript" src="ext/plugins/validval/jquery.validVal.js"></script>
<script type="text/javascript" src="ext/plugins/i18next/i18next.js"></script>
<script type="text/javascript" src="ext/plugins/hellojs/hellojs.js"></script>
<!-- <script type="text/javascript" src="ext/plugins/jspdf/jspdf.js"></script> -->
<!-- IE8 and worse -->
<!-- <script type="text/javascript" src="ext/plugins/selectivzr/selectivzr.js"></script> -->
<!-- stuff happens here -->
<script type="text/javascript" data-storage="data/storages.json" data-config="data/global.json" src="js/erp5_loader.js"></script>
......
/*
* jQuery validVal version 5.0.1
* demo's and documentation:
* validval.frebsite.nl
*
* Copyright (c) 2013 Fred Heusschen
* www.frebsite.nl
*
* Dual licensed under the MIT and GPL licenses.
* http://en.wikipedia.org/wiki/MIT_License
* http://en.wikipedia.org/wiki/GNU_General_Public_License
*/
(function( $ )
{
var _PLUGIN_ = 'validVal',
_FIELD_ = 'validValField',
_VERSION_ = '5.0.1',
_INPUTS_ = 'textarea, select, input:not( [type="button"], [type="submit"], [type="reset"] )';
// validVal already excists
if ( $.fn[ _PLUGIN_ ] )
{
return;
}
function ValidVal( form, opts )
{
this.form = form;
this.opts = $.extend( true, {}, $.fn[ _PLUGIN_ ].defaults, opts );
this._gatherValidation();
this._bindEvents();
this._bindCustomEvents();
this.addField( this.opts.validate.fields.filter( $(_INPUTS_, this.form) ) );
}
ValidVal.prototype = {
// Public methods
addField: function( $field )
{
if ( isHtmlElement( $field ) || typeof $field == 'string' )
{
$field = $( $field );
}
if ( !( $field instanceof $ ) )
{
$.fn[ _PLUGIN_ ].debug( 'Not a valid argument for "$field"' );
return this;
}
var that = this;
return $field.each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.destroy();
}
$f.data( _FIELD_, new ValidValField( $f, that ) );
}
);
},
validate: function( body, callCallback )
{
var that = this;
// Complement arguments
if ( typeof body == 'undefined' )
{
body = this.form;
callCallback = true;
}
else if ( typeof callCallback != 'boolean' )
{
callCallback = false;
}
if ( typeof this.opts.form.onValidate == 'function' )
{
this.opts.form.onValidate.call( this.form[ 0 ], this.opts.language );
}
// Set varialbes
var miss_arr = $(),
data_obj = {};
// Validate fields
this.opts.validate.fields.filter( $(_INPUTS_, body) ).each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.validate( that.opts.validate.onSubmit )
if ( vf.valid )
{
var v = $f.val();
if ( $f.is( '[type="radio"]' ) || $f.is( '[type="checkbox"]' ) )
{
if ( !$f.is( ':checked' ) )
{
v = '';
}
}
if ( typeof v == 'undefined' || v == null )
{
v = '';
}
data_obj[ $f.attr( 'name' ) ] = v;
}
else
{
if ( that.opts.validate.onSubmit !== false )
{
miss_arr = miss_arr.add( $f );
}
}
}
}
);
// Not valid
if ( miss_arr.length > 0 )
{
if ( typeof this.opts.form.onInvalid == 'function' && callCallback )
{
this.opts.form.onInvalid.call( this.form[ 0 ], miss_arr, this.opts.language );
}
return false;
}
// Valid
else
{
if ( typeof this.opts.form.onValid == 'function' && callCallback )
{
this.opts.form.onValid.call( this.form[ 0 ], this.opts.language );
}
return data_obj;
}
},
submitForm: function()
{
var result = this.validate();
if ( result )
{
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf )
{
vf.clearPlaceholderValue();
}
}
);
}
return result;
},
resetForm: function()
{
var that = this;
if ( typeof this.opts.form.onReset == 'function' )
{
this.opts.form.onReset.call( this.form[ 0 ], this.opts.language );
}
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf )
{
if ( vf.placeholderValue !== false )
{
$f.addClass( 'inactive' );
$f.val( vf.placeholderValue );
}
else
{
$f.val( vf.originalValue );
}
vf.isValid( true, true );
}
}
);
return true;
},
options: function( o )
{
if ( typeof o == 'object' )
{
this.opts = $.extend( this.opts, o );
}
return this.opts;
},
destroy: function()
{
this.form.unbind( '.vv' );
this.form.data( _PLUGIN_, null );
this.opts.validate.fields.filter( $(_INPUTS_, this.form) ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf )
{
vf.destroy();
}
}
);
return true;
},
// Protected methods
_gatherValidation: function()
{
this.opts.validations = {};
if ( $.fn[ _PLUGIN_ ].customValidations )
{
this.opts.validations = $.extend( this.opts.validations, $.fn[ _PLUGIN_ ].customValidations );
}
if ( this.opts.customValidations )
{
this.opts.validations = $.extend( this.opts.validations, this.opts.customValidations );
}
this.opts.validations = $.extend( this.opts.validations, $.fn[ _PLUGIN_ ].defaultValidations );
return this;
},
_bindEvents: function ()
{
var that = this;
if ( this.form.is( 'form' ) )
{
this.form.attr( 'novalidate', 'novalidate' );
this.form.bind(
namespace( 'submit' ),
function( event, validate )
{
if ( typeof validate != 'boolean' )
{
validate = true;
}
return ( validate )
? that.submitForm()
: true;
}
);
this.form.bind(
namespace( 'reset' ),
function( event )
{
return that.resetForm();
}
);
}
return this;
},
_bindCustomEvents: function()
{
var that = this;
this.form.bind(
namespace([
'addField',
'destroy',
'validate',
'submitForm',
'resetForm',
'options'
]),
function()
{
arguments = Array.prototype.slice.call( arguments );
var event = arguments.shift(),
type = event.type;
event.stopPropagation();
if ( typeof that[ type ] != 'function' )
{
$.fn.validVal.debug( 'Public method "' + type + '" not found.' );
return false;
}
return that[ type ].apply( that, arguments );
}
);
return this;
}
};
function ValidValField( field, form )
{
this.field = field;
this.form = form;
this.originalValue = this.field.attr( 'value' ) || '';
this._gatherValidations();
this._bindEvents();
this._bindCustomEvents();
this._init();
}
ValidValField.prototype = {
// Public methods
validate: function( onEvent, fixPlaceholder )
{
var that = this;
if ( onEvent === false )
{
return;
}
if ( typeof fixPlaceholder != 'boolean' )
{
fixPlaceholder = true;
}
this.valid = true;
if ( ( this.field.is( ':hidden' ) && !this.form.opts.validate.fields.hidden ) ||
( this.field.is( ':disabled' ) && !this.form.opts.validate.fields.disabled )
) {
return true;
}
if ( fixPlaceholder )
{
this.clearPlaceholderValue();
}
if ( typeof this.form.opts.fields.onValidate == 'function' )
{
this.form.opts.fields.onValidate.call( this.field[ 0 ], this.form.form, this.form.opts.language );
}
var invalid_check = false,
val = trim( this.field.val() );
for ( var v in this.form.opts.validations )
{
var f = this.form.opts.validations[ v ];
if ( typeof f == 'function' && $.inArray( v, this.validations ) != -1 )
{
if ( !f.call( this.field[ 0 ], val ) )
{
invalid_check = v;
break;
}
}
}
this.valid = ( invalid_check ) ? false : true;
var callCallback = ( this.valid )
? ( onEvent !== 'invalid' )
: ( onEvent !== 'valid' );
this.isValid( this.valid, callCallback, invalid_check );
if ( this.validationgroup !== false )
{
$(_INPUTS_).not( this.field ).each(
function()
{
var vf = $(this).data( _FIELD_ );
if ( vf && vf.validationgroup == that.validationgroup )
{
vf.isValid( that.valid, true );
}
}
);
}
if ( fixPlaceholder )
{
this.restorePlaceholderValue();
}
if ( invalid_check )
{
$.fn[ _PLUGIN_ ].debug( 'invalid validation: ' + invalid_check );
}
return this.valid;
},
isValid: function( valid, callCallback )
{
if ( typeof valid == 'boolean' )
{
this.valid = valid;
if ( callCallback )
{
var fn = ( valid ) ? 'onValid' : 'onInvalid';
if ( typeof this.form.opts.fields[ fn ] == 'function' )
{
this.form.opts.fields[ fn ].call( this.field[ 0 ], this.form.form, this.form.opts.language );
}
}
}
return this.valid;
},
getValidations: function()
{
return this.validations;
},
setValidations: function( validations )
{
if ( typeof validations == 'string' )
{
this.validations = validations.split( ' ' );
}
else if ( validations instanceof Array )
{
this.validations = validations;
}
else
{
$.fn.validVal.debug( 'Argument "validations" should be an array.' );
}
return this.validations;
},
addValidation: function( validation )
{
if ( typeof validation == 'string' )
{
validation = validation.split( ' ' );
}
for( var v in validation )
{
this.validations.push( validation[ v ] );
}
return this.validations;
},
removeValidation: function( validation )
{
if ( typeof validation == 'string' )
{
validation = validation.split( ' ' );
}
for( var v in validation )
{
var pos = $.inArray( validation[ v ], this.validations );
if ( pos != -1 )
{
this.validations.splice( pos, 1 );
}
}
return this.validations;
},
clearPlaceholderValue: function()
{
this._togglePlaceholderValue( 'clear' );
return true;
},
restorePlaceholderValue: function()
{
this._togglePlaceholderValue( 'restore' );
return true;
},
destroy: function()
{
this.field.unbind( '.vv' );
this.field.data( _FIELD_, null );
return true;
},
// Protected methods
_gatherValidations: function()
{
this.autotab = false;
this.corresponding = false;
this.requiredgroup = false;
this.validationgroup = false;
this.placeholderValue = false;
this.placeholderNumber = false;
this.passwordplaceholder = false;
this.validations = [];
if ( this.field.is( 'select' ) )
{
this.originalValue = this.field.find( 'option:first' ).attr( 'value' ) || '';
}
else if ( this.field.is( 'textarea' ) )
{
this.originalValue = this.field.text();
}
// Refactor HTML5 usage
if ( this.form.opts.supportHtml5 )
{
var valids = this.field.data( 'vv-validations' );
if ( valids )
{
this.validations.push( valids );
this.__removeAttr( 'data-vv-validations' );
}
// Placeholder attribute, only use if placeholder not supported by browser or placeholder not in keepAttributes-option
if ( this.__hasHtml5Attr( 'placeholder' ) && this.field.attr( 'placeholder' ).length > 0 )
{
if ( !$.fn[ _PLUGIN_ ].support.placeholder || $.inArray( 'placeholder', this.form.opts.keepAttributes ) == -1 )
{
this.placeholderValue = this.field.attr( 'placeholder' );
}
}
if ( this.placeholderValue !== false )
{
this.__removeAttr( 'placeholder' );
}
// Pattern attribute
if ( this.__hasHtml5Attr( 'pattern' ) && this.field.attr( 'pattern' ).length > 0 )
{
this.pattern = this.field.attr( 'pattern' );
this.validations.push( 'pattern' );
this.__removeAttr( 'pattern' );
}
// Corresponding, required group and validation group
var dts = [ 'corresponding', 'requiredgroup', 'validationgroup' ];
for ( var d = 0, l = dts.length; d < l; d++ )
{
var dt = this.field.data( 'vv-' + dts[ d ] );
if ( dt )
{
this[ dts[ d ] ] = dt;
this.validations.push( dts[ d ] );
this.__removeAttr( 'data-vv-' + dts[ d ] );
}
}
// Attributes
var atr = [ 'required', 'autofocus' ];
for ( var a = 0, l = atr.length; a < l; a++ )
{
if ( this.__hasHtml5Attr( atr[ a ] ) )
{
this.validations.push( atr[ a ] );
this.__removeAttr( atr[ a ] );
}
}
// Type-values
var typ = [ 'number', 'email', 'url' ];
for ( var t = 0, l = typ.length; t < l; t++ )
{
if ( this.__hasHtml5Type( typ[ t ] ) )
{
this.validations.push( typ[ t ] );
}
}
// Autotab
if ( this.field.data( 'vv-autotab' ) )
{
this.autotab = true;
this.__removeAttr( 'data-vv-autotab' );
}
}
// Refactor non-HTML5 usage
var classes = this.field.attr( 'class' );
if ( classes && classes.length )
{
// Placeholder
if ( this.field.hasClass( 'placeholder' ) )
{
if ( this.field.is( 'select' ) )
{
var num = 0,
opt = this.field.data( 'vv-placeholder-number' );
if ( opt )
{
num = opt;
this.__removeAttr( 'data-vv-placeholder-number' );
}
else if ( typeof this.form.opts.selectPlaceholder == 'number' )
{
num = this.form.opts.selectPlaceholder;
}
else
{
var $options = this.field.find( 'option' ),
selected = $options.index( $options.filter( '[selected]' ) );
if ( selected > -1 )
{
num = selected;
}
}
this.placeholderNumber = num;
this.originalValue = this.field.find( 'option:eq( ' + num + ' )' ).attr( 'value' ) || '';
}
this.placeholderValue = this.originalValue;
this.originalValue = '';
this.__removeClass( 'placeholder' );
}
// Corresponding
var corsp = 'corresponding:',
start = classes.indexOf( corsp );
if ( start != -1 )
{
var corrcls = classes.substr( start ).split( ' ' )[ 0 ],
corresp = corrcls.substr( corsp.length );
if ( corresp.length )
{
this.corresponding = corresp;
this.validations.push( 'corresponding' );
this.field.removeClass( corrcls );
}
}
// Pattern
// still uses alt-attribute...
if ( this.field.hasClass( 'pattern' ) )
{
this.pattern = this.field.attr( 'alt' ) || '';
this.validations.push( 'pattern' );
this.__removeAttr( 'alt' );
this.__removeClass( 'pattern' );
}
// Groups
var grp = [ 'requiredgroup', 'validationgroup' ];
for ( var g = 0, l = grp.length; g < l; g++ )
{
var group = grp[ g ] + ':',
start = classes.indexOf( group );
if ( start != -1 )
{
var groupclass = classes.substr( start ).split( ' ' )[ 0 ],
groupname = groupclass.substr( group.length );
if ( groupname.length )
{
this[ grp[ g ] ] = groupname;
this.validations.push( grp[ g ]);
this.field.removeClass( groupclass );
}
}
}
// Autotab
if ( this.field.hasClass( 'autotab' ) )
{
this.autotab = true;
this.__removeClass( 'autotab' );
}
}
// Password placeholder
if ( this.placeholderValue !== false && this.field.is( '[type="password"]' ) )
{
this.passwordplaceholder = true;
}
// Add all remaining classes
var classes = this.field.attr( 'class' );
if ( classes && classes.length )
{
this.validations.push( classes );
}
this.validations = unique( this.validations.join( ' ' ).split( ' ' ) );
return this;
},
_bindEvents: function()
{
var that = this;
this.field.bind(
namespace( 'focus' ),
function( event )
{
$(this).addClass( 'focus' );
that.clearPlaceholderValue();
}
);
this.field.bind(
namespace( 'blur' ),
function( event )
{
$(this).removeClass( 'focus' );
that.validate( that.form.opts.validate.onBlur );
}
);
this.field.bind(
namespace( 'keyup' ),
function( event )
{
if ( !preventkeyup( event.keyCode ) )
{
that.validate( that.form.opts.validate.onKeyup, false );
}
}
);
if ( this.field.is( 'select, input[type="checkbox"], input[type="radio"]' ) )
{
this.field.bind(
namespace( 'change' ),
function( event )
{
$(this).trigger( namespace( 'blur' ) );
}
);
}
return this;
},
_bindCustomEvents: function()
{
var that = this;
this.field.bind(
namespace([
'validate',
'isValid',
'destroy',
'addValidation',
'removeValidation'
]),
function()
{
arguments = Array.prototype.slice.call( arguments );
var event = arguments.shift(),
type = event.type;
event.stopPropagation();
if ( typeof that[ type ] != 'function' )
{
$.fn.validVal.debug( 'Public method "' + type + '" not found.' );
return false;
}
return that[ type ].apply( that, arguments );
}
);
this.field.bind(
namespace([ 'validations' ]),
function( event, validations, callCallback )
{
if ( typeof validations == 'undefined' )
{
return this.getValidations();
}
else
{
return this.setValidations( validations, callCallback );
}
}
);
return this;
},
_init: function()
{
var that = this;
// Placeholder
if ( this.placeholderValue !== false )
{
if ( this.field.val() == '' )
{
this.field.val( this.placeholderValue );
}
if ( this.passwordplaceholder )
{
if ( this.field.val() == this.placeholderValue ) try
{
this.field[ 0 ].type = 'text';
}
catch( err ) {};
}
if ( this.field.val() == this.placeholderValue )
{
this.field.addClass( 'inactive' );
}
if ( this.field.is( 'select' ) )
{
this.field.find( 'option:eq(' + this.placeholderNumber + ')' ).addClass( 'inactive' );
this.field.bind(
namespace( 'change' ),
function( event )
{
$(this)[ that.field.val() == that.placeholderValue ? 'addClass' : 'removeClass' ]( 'inactive' );
}
);
}
}
// Corresponding
if ( this.corresponding !== false )
{
$(_INPUTS_).filter('[name="' + this.corresponding + '"]').bind(
namespace( 'blur' ),
function( event )
{
that.validate( that.form.opts.validate.onBlur );
}
).bind(
namespace( 'keyup' ),
function( event )
{
if ( !preventkeyup( event.keyCode ) )
{
that.validate( that.form.opts.validate.onKeyup, false );
}
}
);
}
// Autotabbing
if ( this.autotab )
{
var max = this.field.attr( 'maxlength' ),
tab = this.field.attr( 'tabindex' ),
$next = $(_INPUTS_).filter('[tabindex="' + ( parseInt( tab ) + 1 ) + '"]');
if ( this.field.is( 'select' ) )
{
if ( tab )
{
this.field.bind(
namespace( 'change' ),
function( event )
{
if ( $next.length )
{
$next.focus();
}
}
);
}
}
else
{
if ( max && tab )
{
this.field.bind(
namespace( 'keyup' ),
function( event )
{
if ( $(this).val().length == max )
{
if ( !preventkeyup( event.keyCode ) )
{
$(this).trigger( namespace( 'blur' ) );
if ( $next.length )
{
$next.focus();
}
}
}
}
);
}
}
}
// Autofocus
if ( $.inArray( 'autofocus', this.validations ) != -1 && !this.field.is( ':disabled' ) )
{
this.field.focus();
}
return this;
},
_togglePlaceholderValue: function( toggle )
{
if ( this.placeholderValue !== false )
{
if ( toggle == 'clear' )
{
var v1 = this.placeholderValue,
v2 = '',
cl = 'removeClass',
tp = 'password';
}
else
{
var v1 = '',
v2 = this.placeholderValue,
cl = 'addClass',
tp = 'text';
}
if ( this.field.val() == v1 && !this.field.is( 'select' ) )
{
this.field.val( v2 );
this.field[ cl ]( 'inactive' );
if ( this.passwordplaceholder ) try
{
this.field[ 0 ].type = tp;
}
catch( err ) {};
}
}
return this;
},
// Private methods
__hasHtml5Attr: function( a )
{
// non HTML5 browsers
if ( typeof this.field.attr( a ) == 'undefined' )
{
return false;
}
// HTML5 browsers
if ( this.field.attr( a ) === 'false' || this.field.attr( a ) === false )
{
return false;
}
return true;
},
__hasHtml5Type: function( t )
{
// cool HTML5 browsers
if ( this.field.attr( 'type' ) == t )
{
return true;
}
// non-HTML5 but still cool browsers
if ( this.field.is( 'input[type="' + t + '"]' ) )
{
return true;
}
// non-HTML5, non-cool browser
var $c = $( '<div />' ).append( this.field.clone() ).html()
if ( $c.indexOf( 'type="' + t + '"' ) != -1 || $c.indexOf( 'type=\'' + t + '\'' ) != -1 || $c.indexOf( 'type=' + t + '' ) != -1 )
{
return true;
}
return false;
},
__removeAttr: function( a )
{
if ( $.inArray( a, this.form.opts.keepAttributes ) == -1 )
{
this.field.removeAttr( a );
}
return this;
},
__removeClass: function( c )
{
if ( $.inArray( c, this.form.opts.keepClasses ) == -1 )
{
this.field.removeClass( c );
}
return this;
}
};
$.fn[ _PLUGIN_ ] = function( o, c )
{
return this.each(
function()
{
var $t = $(this);
if ( $t.data( _PLUGIN_ ) )
{
$t.data( _PLUGIN_ ).destroy();
}
$t.data( _PLUGIN_, new ValidVal( $t, o, c ) );
}
);
};
$.fn[ _PLUGIN_ ].version = _VERSION_;
$.fn[ _PLUGIN_ ].defaults = {
'selectPlaceholder' : 0,
'supportHtml5' : true,
'language' : 'en',
'customValidations' : {},
'validate' : {
'onBlur' : true,
'onSubmit' : true,
'onKeyup' : false,
'fields' : {
'hidden' : false,
'disabled' : false,
'filter' : function( $i )
{
return $i;
}
}
},
'fields' : {
'onValidate' : null,
'onValid' : function()
{
$(this).add( $(this).parent() ).removeClass( 'invalid' );
},
'onInvalid' : function()
{
$(this).add( $(this).parent() ).addClass( 'invalid' );
}
},
'form' : {
'onReset' : null,
'onValidate': null,
'onValid' : null,
'onInvalid' : function( fieldArr, language )
{
switch ( language )
{
case 'nl':
msg = 'Let op, niet alle velden zijn correct ingevuld.';
break;
case 'de':
msg = 'Achtung, nicht alle Felder sind korrekt ausgefuellt.';
break;
case 'es':
msg = 'Atención, no se han completado todos los campos correctamente.';
break;
case 'en':
default:
msg = 'Attention, not all fields have been filled out correctly.';
break;
}
alert( msg );
fieldArr.first().focus();
}
},
'keepClasses' : [ 'required' ],
'keepAttributes': [ 'pattern', 'placeholder' ]
};
$.fn[ _PLUGIN_ ].defaultValidations = {
'required': function( v )
{
var $f = $(this);
if ( $f.is( '[type="radio"]' ) || $f.is( '[type="checkbox"]' ) )
{
if ( $f.is( '[type="radio"]' ) )
{
var name = $f.attr( 'name' );
if ( name && name.length > 0 )
{
$f = $( 'input[name="' + name + '"]' );
}
}
if ( !$f.is( ':checked' ) )
{
return false;
}
}
else if ( $f.is( 'select' ) )
{
var vf = $f.data( _FIELD_ );
if ( vf && vf.placeholderValue !== false )
{
if ( $f.val() == vf.placeholderValue )
{
return false;
}
}
else
{
if ( v.length == 0 )
{
return false;
}
}
}
else
{
if ( v.length == 0 )
{
return false;
}
}
return true;
},
'Required': function( v )
{
return $.fn[ _PLUGIN_ ].defaultValidations.required.call( this, v );
},
'requiredgroup': function( v )
{
var $f = $(this),
vf = $f.data( _FIELD_ );
if ( vf && vf.requiredgroup !== false )
{
$f = $();
$(_INPUTS_).each(
function()
{
var tf = $(this).data( _FIELD_ );
if ( tf && tf.requiredgroup == vf.requiredgroup )
{
$f = $f.add( this );
}
}
);
}
var result = false;
$f.each(
function()
{
var f = this;
if ( $.fn[ _PLUGIN_ ].defaultValidations.required.call( f, trim( $(f).val() ) ) )
{
result = true;
}
}
);
return result;
},
'corresponding': function( v )
{
var org = '',
vf = $(this).data( _FIELD_ );
if ( vf && vf.corresponding !== false )
{
var $f = $(_INPUTS_).filter('[name="' + vf.corresponding + '"]'),
vf = $f.data( _FIELD_ );
if ( vf )
{
vf.clearPlaceholderValue();
org = trim( $f.val() );
vf.restorePlaceholderValue();
}
return ( v == org );
}
return false;
},
'number': function( v )
{
v = stripWhitespace( v );
if ( v.length == 0 )
{
return true;
}
if ( isNaN( v ) )
{
return false;
}
return true;
},
'email': function( v )
{
if ( v.length == 0 )
{
return true;
}
var r = /^([a-zA-Z0-9_\.\-+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
return r.test( v );
},
'url': function( v )
{
if ( v.length == 0 )
{
return true;
}
if ( v.match(/^www\./) )
{
v = "http://" + v;
}
return v.match(/^(http\:\/\/|https\:\/\/)(.{4,})$/);
},
'pattern': function( v )
{
if ( v.length == 0 )
{
return true;
}
var $f = $(this),
vf = $f.data( 'validVal' );
if ( vf )
{
var p = vf.pattern;
if ( p.slice( 0, 1 ) == '/' )
{
p = p.slice( 1 );
}
if ( p.slice( 1 ) == '/' )
{
p = p.slice( 0, -1 );
}
return new RegExp( p ).test( v );
}
}
};
// test for borwser support
$.fn[ _PLUGIN_ ].support = {
touch: (function()
{
return 'ontouchstart' in document.documentElement;
})(),
placeholder: (function()
{
return 'placeholder' in document.createElement( 'input' );
})()
};
$.fn[ _PLUGIN_ ].debug = function( msg ) {};
$.fn[ _PLUGIN_ ].deprecated = function( func, alt )
{
if ( typeof console != 'undefined' )
{
if ( typeof console.error != 'undefined' )
{
console.error( func + ' is DEPRECATED, use ' + alt + ' instead.' );
}
}
};
// Create debugger is it doesn't already excists
if ( !$.fn.validValDebug )
{
$.fn.validValDebug = function( b )
{
$.fn[ _PLUGIN_ ].debug( 'validVal debugger not installed!' );
return this;
}
}
function isHtmlElement( field )
{
if ( typeof HTMLElement != 'undefined' )
{
return field instanceof HTMLElement;
}
return ( field.nodeType && field.nodeType == Node.ELEMENT_NODE );
}
function namespace( events )
{
if ( typeof events == 'string' )
{
events = events.split( ' ' );
}
return events.join( '.vv ' ) + '.vv';
}
function unique( arr )
{
return $.grep(
arr,
function( v, k )
{
return $.inArray( v, arr ) === k;
}
);
}
function trim( str )
{
if ( str === null )
{
return '';
}
if ( typeof str == 'object' )
{
var arr = [];
for ( var a in str )
{
arr[ a ] = trim( str[ a ] );
}
return arr;
}
if ( typeof str != 'string' )
{
return '';
}
if ( str.length == 0 )
{
return '';
}
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
function stripWhitespace( str )
{
if ( str === null )
{
return '';
}
if ( typeof str == 'object' )
{
for ( var a in str )
{
str[ a ] = stripWhitespace( str[ a ] );
}
return str;
}
if ( typeof str != 'string' )
{
return '';
}
if ( str.length == 0 )
{
return '';
}
str = trim( str );
var r = [ ' ', '-', '+', '(', ')', '/', '\\' ];
for ( var i = 0, l = r.length; i < l; i++ )
{
str = str.split( r[ i ] ).join( '' );
}
return str;
}
function preventkeyup( kc )
{
switch( kc ) {
case 9: // tab
case 13: // enter
case 16: // shift
case 17: // control
case 18: // alt
case 37: // left
case 38: // up
case 39: // right
case 40: // down
case 224: // command
return true;
break;
default:
return false;
break;
}
}
})( jQuery );
\ No newline at end of file
/*jslint indent: 2, maxlen: 80, nomen: true, sloppy: true, todo: true */
/*global console, window, document */
(function (window, document) {
"use strict";
// NOTE: old browsers need all of these
var shim_dict = {};
/* ====================================================================== */
/* SHIMS */
/* ====================================================================== */
// NOTE: add more: https://github.com/kriskowal/es5-shim
// NOTE: to support IE8+/Windows Mobile where possible, test via modernizr
// =============================== indexOf ================================
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(searchElement /*, fromIndex */) {
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (len === 0)
return -1;
var n = 0;
if (arguments.length > 0)
{
n = Number(arguments[1]);
if (n !== n)
n = 0;
else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
if (n >= len)
return -1;
var k = n >= 0
? n
: Math.max(len - Math.abs(n), 0);
for (; k < len; k++)
{
if (k in t && t[k] === searchElement)
return k;
}
return -1;
};
}
// =============================== BASE64 encoding ========================
// https://gist.github.com/yahiko/229984
shim_dict.Base64 = {
characters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ,
/**
* Shim for atob (not available on IE8+9+Windows Mobile?)
* @method Base64.encode
* @param {string} string String to be hashed
* @return {string} encoded string
*/
encode: function( string ) {
var characters = shim_dict.Base64.characters;
var result = '';
var i = 0;
do {
var a = string.charCodeAt(i++);
var b = string.charCodeAt(i++);
var c = string.charCodeAt(i++);
a = a ? a : 0;
b = b ? b : 0;
c = c ? c : 0;
var b1 = ( a >> 2 ) & 0x3F;
var b2 = ( ( a & 0x3 ) << 4 ) | ( ( b >> 4 ) & 0xF );
var b3 = ( ( b & 0xF ) << 2 ) | ( ( c >> 6 ) & 0x3 );
var b4 = c & 0x3F;
if( ! b ) {
b3 = b4 = 64;
} else if( ! c ) {
b4 = 64;
}
result += characters.charAt( b1 ) + characters.charAt( b2 ) +
characters.charAt( b3 ) + characters.charAt( b4 );
} while ( i < string.length );
return result;
},
/**
* Shim for btoa (not available on IE8+9+Windows Mobile?)
* @method Base64.decode
* @param {string} string String to be hashed
* @return {string} encoded string
*/
decode: function( string ) {
var characters = shim_dict.Base64.characters;
var result = '';
var i = 0;
do {
var b1 = characters.indexOf( string.charAt(i++) );
var b2 = characters.indexOf( string.charAt(i++) );
var b3 = characters.indexOf( string.charAt(i++) );
var b4 = characters.indexOf( string.charAt(i++) );
var a = ( ( b1 & 0x3F ) << 2 ) | ( ( b2 >> 4 ) & 0x3 );
var b = ( ( b2 & 0xF ) << 4 ) | ( ( b3 >> 2 ) & 0xF );
var c = ( ( b3 & 0x3 ) << 6 ) | ( b4 & 0x3F );
result += String.fromCharCode(a) + (b?String.fromCharCode(b):'') + (c?String.fromCharCode(c):'');
} while( i < string.length );
return result;
}
};
window.shim = shim_dict;
}(window, document));
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment