Files
OMS/app/wap/statics/js/mobile.js
2025-12-28 23:13:25 +08:00

2080 lines
77 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Shopex OMS
*
* Copyright (c) 2025 Shopex (http://www.shopex.cn)
* Licensed under Apache-2.0 with additional terms (See LICENSE file)
*/
/*
* Mobile's Front-end Library
*/
(function($, window, document, undefined) {
'use strict';
var header_helpers = function(class_array) {
var head = $('head');
head.prepend($.map(class_array, function(class_name) {
if (head.has('.' + class_name).length === 0) {
return '<meta class="' + class_name + '" />';
}
}));
};
header_helpers([
'mobile-mq-small',
'mobile-mq-small-only',
'mobile-mq-medium',
'mobile-mq-medium-only',
'mobile-data-attribute-namespace'
]);
// Enable FastClick if present
$(function() {
if (typeof FastClick !== 'undefined') {
// Don't attach to body if undefined
if (typeof document.body !== 'undefined') {
FastClick.attach(document.body);
}
}
});
// Namespace functions.
var attr_name = function(init) {
var arr = [];
if (!init) {
arr.push('data');
}
if (this.namespace.length > 0) {
arr.push(this.namespace);
}
arr.push(this.name);
return arr.join('-');
};
var add_namespace = function(str) {
var parts = str.split('-'),
i = parts.length,
arr = [];
while (i--) {
if (i !== 0) {
arr.push(parts[i]);
} else {
if (this.namespace.length > 0) {
arr.push(this.namespace, parts[i]);
} else {
arr.push(parts[i]);
}
}
}
return arr.reverse().join('-');
};
// Event binding and data-options updating.
var bindings = function(method, options) {
var self = this,
config = ($.isArray(options) ? options[0] : options) || method,
bind = function() {
var $this = $(this),
should_bind_events = !$(self).data(self.attr_name(true) + '-init');
$this.data(self.attr_name(true) + '-init', $.extend(true, {}, self.settings, config, self.data_options($this)));
if (should_bind_events) {
self.events(this);
}
};
if ($(this.scope).is('[' + this.attr_name() + ']')) {
bind.call(this.scope);
} else {
$('[' + this.attr_name() + ']', this.scope).each(bind);
}
// # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating.
if (typeof method === 'string') {
if($.isArray(options)) return this[method].apply(this, options);
else return this[method].call(this, options);
}
};
var single_image_loaded = function(image, callback) {
function loaded() {
callback(image[0]);
}
function bindLoad() {
this.one('load', loaded);
}
if (!image.attr('src')) {
loaded();
return;
}
if (image[0].complete || image[0].readyState === 4) {
loaded();
} else {
bindLoad.call(image);
}
};
/*
* jquery.requestAnimationFrame
* https://github.com/gnarf37/jquery-requestAnimationFrame
* Requires jQuery 1.8+
*
* Copyright (c) 2012 Corey Frang
* Licensed under the MIT license.
*/
(function(jQuery) {
// requestAnimationFrame polyfill adapted from Erik Möller
// fixes from Paul Irish and Tino Zijdel
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
var animating,
lastTime = 0,
vendors = ['webkit'],
requestAnimationFrame = window.requestAnimationFrame,
cancelAnimationFrame = window.cancelAnimationFrame,
jqueryFxAvailable = 'undefined' !== typeof jQuery.fx;
for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) {
requestAnimationFrame = window[vendors[lastTime] + 'RequestAnimationFrame'];
cancelAnimationFrame = cancelAnimationFrame ||
window[vendors[lastTime] + 'CancelAnimationFrame'] ||
window[vendors[lastTime] + 'CancelRequestAnimationFrame'];
}
function raf() {
if (animating) {
requestAnimationFrame(raf);
if (jqueryFxAvailable) {
jQuery.fx.tick();
}
}
}
if (requestAnimationFrame) {
// use rAF
window.requestAnimationFrame = requestAnimationFrame;
window.cancelAnimationFrame = cancelAnimationFrame;
if (jqueryFxAvailable) {
jQuery.fx.timer = function(timer) {
if (timer() && jQuery.timers.push(timer) && !animating) {
animating = true;
raf();
}
};
jQuery.fx.stop = function() {
animating = false;
};
}
} else {
// polyfill
window.requestAnimationFrame = function(callback) {
var currTime = new Date().getTime(),
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}($));
function removeQuotes(string) {
if (typeof string === 'string' || string instanceof String) {
string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, '');
}
return string;
}
function MediaQuery(selector) {
this.selector = selector;
this.query = '';
}
MediaQuery.prototype.toString = function() {
     return this.query = this.query || $(this.selector).css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '');
};
window.Mobile = {
name: 'Mobile',
media_queries: {
'small': new MediaQuery('.mobile-mq-small'),
'small-only': new MediaQuery('.mobile-mq-small-only'),
'medium': new MediaQuery('.mobile-mq-medium'),
'medium-only': new MediaQuery('.mobile-mq-medium-only')
},
stylesheet: $('<style></style>').appendTo('head')[0].sheet,
global: {
namespace: undefined
},
init: function(scope, libraries, method, options, response) {
var args = [scope, method, options, response],
responses = [];
// set mobile global scope
this.scope = scope || this.scope;
this.set_namespace();
if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) {
if (this.libs.hasOwnProperty(libraries)) {
responses.push(this.init_lib(libraries, args));
}
} else {
for (var lib in this.libs) {
responses.push(this.init_lib(lib, libraries));
}
}
// $(window).load(function() {
// $(window)
// .trigger('resize.imagesbox')
// .trigger('resize.dropdown')
// .trigger('resize.equalizer')
// .trigger('resize.responsive')
// .trigger('resize.topbar')
// .trigger('resize.slides');
// });
return scope;
},
init_lib: function(lib, args) {
if (this.libs.hasOwnProperty(lib)) {
this.patch(this.libs[lib]);
if (args && args.hasOwnProperty(lib)) {
if (typeof this.libs[lib].settings !== 'undefined') {
$.extend(true, this.libs[lib].settings, args[lib]);
} else if (typeof this.libs[lib].defaults !== 'undefined') {
$.extend(true, this.libs[lib].defaults, args[lib]);
}
return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]);
}
args = args instanceof Array ? args : new Array(args);
return this.libs[lib].init.apply(this.libs[lib], args);
}
return function() {};
},
patch: function(lib) {
lib.scope = this.scope;
lib.namespace = this.global.namespace;
lib['data_options'] = this.utils.data_options;
lib['attr_name'] = attr_name;
lib['add_namespace'] = add_namespace;
lib['bindings'] = bindings;
},
inherit: function(scope, methods) {
var methods_arr = methods.split(' '),
i = methods_arr.length;
while (i--) {
if (this.utils.hasOwnProperty(methods_arr[i])) {
scope[methods_arr[i]] = this.utils[methods_arr[i]];
}
}
},
set_namespace: function() {
// Description:
// Don't bother reading the namespace out of the meta tag
// if the namespace has been set globally in javascript
//
// Example:
// Mobile.global.namespace = 'my-namespace';
// or make it an empty string:
// Mobile.global.namespace = '';
//
//
// If the namespace has not been set (is undefined), try to read it out of the meta element.
// Otherwise use the globally defined namespace, even if it's empty ('')
var namespace = (this.global.namespace === undefined) ? $('.mobile-data-attribute-namespace').css('font-family') : this.global.namespace;
// Finally, if the namsepace is either undefined or false, set it to an empty string.
// Otherwise use the namespace value.
this.global.namespace = (namespace === undefined || /false/i.test(namespace)) ? '' : namespace;
},
libs: {},
// methods that can be inherited in libraries
utils: {
// Description:
// Parses data-options attribute
//
// Arguments:
// El (jQuery Object): Element to be parsed.
//
// Returns:
// Options (Javascript Object): Contents of the element's data-options
// attribute.
data_options: function(el, data_attr_name) {
data_attr_name = data_attr_name || 'options';
var opts = {},
ii, p, opts_arr,
data_options = function(el) {
var namespace = Mobile.global.namespace;
if (namespace.length > 0) {
return el.data(namespace + '-' + data_attr_name);
}
return el.data(data_attr_name);
};
var cached_options = data_options(el);
if (typeof cached_options === 'object') {
return cached_options;
}
opts_arr = (cached_options || ':').split(';');
ii = opts_arr.length;
function isNumber(o) {
return !isNaN(o - 0) && o !== null && o !== '' && o !== false && o !== true;
}
function trim(str) {
if (typeof str === 'string') {
return $.trim(str);
}
return str;
}
while (ii--) {
p = opts_arr[ii].split(':');
p = [p[0], p.slice(1).join(':')];
if (/true/i.test(p[1])) {
p[1] = true;
}
if (/false/i.test(p[1])) {
p[1] = false;
}
if (isNumber(p[1])) {
if (p[1].indexOf('.') === -1) {
p[1] = parseInt(p[1], 10);
} else {
p[1] = parseFloat(p[1]);
}
}
if (p.length === 2 && p[0].length > 0) {
opts[trim(p[0])] = trim(p[1]);
}
}
return opts;
},
// Description:
// Adds JS-recognizable media queries
//
// Arguments:
// Media (String): Key string for the media query to be stored as in
// Mobile.media_queries
//
// Class (String): Class name for the generated <meta> tag
register_media: function(media, media_class) {
if (Mobile.media_queries[media] === undefined) {
$('head').append('<meta class="' + media_class + '"/>');
Mobile.media_queries[media] = removeQuotes($('.' + media_class).css('font-family'));
}
},
// Description:
// Add custom CSS within a JS-defined media query
//
// Arguments:
// Rule (String): CSS rule to be appended to the document.
//
// Media (String): Optional media query string for the CSS rule to be
// nested under.
add_custom_rule: function(rule, media) {
if (media === undefined && Mobile.stylesheet) {
Mobile.stylesheet.insertRule(rule, Mobile.stylesheet.cssRules.length);
} else {
var query = Mobile.media_queries[media];
if (query !== undefined) {
Mobile.stylesheet.insertRule('@media ' +
Mobile.media_queries[media] + '{ ' + rule + ' }', Mobile.stylesheet.cssRules.length);
}
}
},
// Description:
// Performs a callback function when an image is fully loaded
//
// Arguments:
// Image (jQuery Object): Image(s) to check if loaded.
//
// Callback (Function): Function to execute when image is fully loaded.
image_loaded: function(images, callback) {
var self = this,
unloaded = images.length;
function pictures_has_height(images) {
var pictures_number = images.length;
for (var i = pictures_number - 1; i >= 0; i--) {
if (images.attr('height') === undefined) {
return false;
};
};
return true;
}
if (unloaded === 0 || pictures_has_height(images)) {
callback(images);
}
images.each(function() {
single_image_loaded($(this), function() {
unloaded -= 1;
if (unloaded === 0) {
callback(images);
}
});
});
},
// Description:
// Returns a random, alphanumeric string
//
// Arguments:
// Length (Integer): Length of string to be generated. Defaults to random
// integer.
//
// Returns:
// Rand (String): Pseudo-random, alphanumeric string.
random_str: function() {
if (!this.fidx) {
this.fidx = 0;
}
this.prefix = this.prefix || [(this.name || 'M'), (+new Date).toString(36)].join('-');
return this.prefix + (this.fidx++).toString(36);
},
// Description:
// Helper for window.matchMedia
//
// Arguments:
// mq (String): Media query
//
// Returns:
// (Boolean): Whether the media query passes or not
match: function(mq) {
return window.matchMedia(mq).matches;
},
// Description:
// Helpers for checking Mobile default media queries with JS
//
// Returns:
// (Boolean): Whether the media query passes or not
is_small_up: function() {
return this.match(Mobile.media_queries.small);
},
is_medium_up: function() {
return this.match(Mobile.media_queries.medium);
},
is_small_only: function() {
return !this.is_medium_up();
},
is_medium_only: function() {
return this.is_medium_up();
}
}
};
$.fn.mobile = function() {
var args = Array.prototype.slice.call(arguments, 0);
return this.each(function() {
Mobile.init.apply(Mobile, [this].concat(args));
return this;
});
};
}(jQuery, window, window.document));
(function($, window, document, undefined) {
'use strict';
Mobile.libs.alert = {
name: 'alert',
settings: {
callback: function() {}
},
init: function(scope, method, options) {
this.bindings(method, options);
},
events: function() {
var self = this;
$(this.scope).off('.alert').on('click.alert', '[' + this.attr_name() + '] .close', function(e) {
var alertBox = $(this).closest('[' + self.attr_name() + ']'),
settings = alertBox.data(self.attr_name(true) + '-init') || self.settings;
e.preventDefault();
alertBox.addClass('alert-close');
alertBox.on('transitionend webkitTransitionEnd', function(e) {
$(this).trigger('close.alert').remove();
settings.callback();
});
});
},
reflow: function() {}
};
}(jQuery, window, window.document));
(function($, window, document, undefined) {
'use strict';
var openModals = [];
Mobile.libs.modal = {
name: 'modal',
locked: false,
settings: {
animation: 'fade',
animation_speed: 250,
close_on_backdrop_click: true,
close_on_esc: true,
close_modal_class: 'close-modal',
multiple_opened: false,
backdrop: true,
backdrop_class: 'backdrop',
root_element: 'body',
no_scroll: true,
preventTargetDefault: true,
open: $.noop,
opened: $.noop,
close: $.noop,
closed: $.noop,
on_ajax_error: $.noop,
css: {
open: {
'opacity': 0,
'visibility': 'visible'
},
close: {
'opacity': 1,
'visibility': 'hidden'
}
}
},
init: function(scope, method, options) {
$.extend(true, this.settings, method, options);
this.bindings(method, options);
},
events: function(scope) {
var self = this;
$(this.scope)
.off('.modal')
.on('click.modal', '[' + this.add_namespace('data-modal-id') + ']:not(:disabled):not(.disabled)', function(e) {
if(self.settings.preventTargetDefault) e.preventDefault();
if (!self.locked) {
var element = $(this),
ajax = element.data('modal-ajax'),
replaceContentSel = element.data('modal-replace-content');
self.locked = true;
if (typeof ajax === 'undefined') {
self.open.call(self, element);
} else {
var url = ajax === true ? element.attr('href') : ajax;
self.open.call(self, element, {
url: url
}, {
replaceContentSel: replaceContentSel
});
}
}
});
$(document)
.on('click.modal', this.close_targets(), function(e) {
if (self.settings.preventTargetDefault) e.preventDefault();
if (!self.locked) {
var settings = $('[' + self.attr_name() + '].open').data(self.attr_name(true) + '-init') || self.settings,
backdrop_clicked = settings.backdrop && ($(e.target)[0] === $('.' + settings.backdrop_class)[0]);
if (backdrop_clicked) {
if (settings.close_on_backdrop_click) {
e.stopPropagation();
} else {
return;
}
}
self.locked = true;
self.close.call(self, backdrop_clicked ? $('[' + self.attr_name() + '].open:not(.toback)') : $(this).closest('[' + self.attr_name() + ']'));
}
});
if ($('[' + this.attr_name() + ']', this.scope).length > 0) {
$(this.scope)
// .off('.modal')
.on('open.modal', this.settings.open)
.on('opened.modal', this.settings.opened)
.on('opened.modal', this.open_video)
.on('close.modal', this.settings.close)
.on('closed.modal', this.settings.closed)
.on('closed.modal', this.close_video);
} else {
$(this.scope)
// .off('.modal')
.on('open.modal', '[' + this.attr_name() + ']', this.settings.open)
.on('opened.modal', '[' + this.attr_name() + ']', this.settings.opened)
.on('opened.modal', '[' + this.attr_name() + ']', this.open_video)
.on('close.modal', '[' + this.attr_name() + ']', this.settings.close)
.on('closed.modal', '[' + this.attr_name() + ']', this.settings.closed)
.on('closed.modal', '[' + this.attr_name() + ']', this.close_video);
}
return true;
},
open: function(target, ajax_settings) {
var self = this,
modal;
if (target) {
if (typeof target.selector !== 'undefined') {
// Find the named node; only use the first one found, since the rest of the code assumes there's only one node
modal = $('#' + target.data('modal-id')).first();
} else {
modal = $(this.scope);
ajax_settings = target;
}
} else {
modal = $(this.scope);
}
var settings = modal.data(this.attr_name(true) + '-init');
settings = settings || this.settings;
if (modal.hasClass('open') && target !== undefined && target.attr('data-modal-id') == modal.attr('id')) {
return this.close(modal);
}
if (!modal.hasClass('open')) {
var open_modal = $('[' + this.attr_name() + '].open');
modal.attr('tabindex', '0').attr('aria-hidden', 'false');
// prevents annoying scroll positioning bug with position: absolute;
if (settings.no_scroll) {
var $doc = $('html');
$doc.one('open.modal', function() {
$(this).addClass('modal-open');
}).on('touchmove', function(e) {
e.preventDefault();
});
}
// Prevent namespace event from triggering twice
modal.on('open.modal', function(e) {
if (e.namespace !== 'modal') return;
});
modal.on('open.modal').trigger('open.modal');
if (open_modal.length < 1) {
this.toggle_backdrop(modal, true);
}
if (typeof ajax_settings === 'string') {
ajax_settings = {
url: ajax_settings
};
}
var openModal = function() {
if (open_modal.length > 0) {
if (settings.multiple_opened) {
self.to_back(open_modal);
} else {
self.hide(open_modal, settings.css.close);
}
}
// bl: add the open_modal that isn't already in the background to the openModals array
if (settings.multiple_opened) {
openModals.push(modal);
}
self.show(modal, settings.css.open);
};
if (typeof ajax_settings === 'undefined' || !ajax_settings.url) {
openModal();
} else {
var old_success = typeof ajax_settings.success !== 'undefined' ? ajax_settings.success : null;
$.extend(ajax_settings, {
success: function(data, textStatus, jqXHR) {
if ($.isFunction(old_success)) {
var result = old_success(data, textStatus, jqXHR);
if (typeof result == 'string') {
data = result;
}
}
if (typeof options !== 'undefined' && typeof options.replaceContentSel !== 'undefined') {
modal.find(options.replaceContentSel).html(data);
} else {
modal.html(data);
}
$(modal).mobile('section', 'reflow');
$(modal).children().mobile();
openModal();
}
});
// check for if user initalized with error callback
if (settings.on_ajax_error !== $.noop) {
$.extend(ajax_settings, {
error: settings.on_ajax_error
});
}
$.ajax(ajax_settings);
}
}
$(window).trigger('resize');
},
close: function(modal) {
var modal = modal && modal.length ? modal : $(this.scope),
open_modals = $('[' + this.attr_name() + '].open'),
settings = modal.data(this.attr_name(true) + '-init') || this.settings,
self = this;
if (open_modals.length > 0) {
modal.removeAttr('tabindex', '0').attr('aria-hidden', 'true');
// prevents annoying scroll positioning bug with position: absolute;
if (settings.no_scroll) {
var $doc = $('html');
$doc.one('close.modal', function() {
$(this).removeClass('modal-open');
})
.off('touchmove');
}
this.locked = true;
modal.trigger('close.modal');
if ((settings.multiple_opened && open_modals.length === 1) || !settings.multiple_opened || modal.length > 1) {
this.toggle_backdrop(modal, false);
this.to_front(modal);
}
if (settings.multiple_opened) {
var isCurrent = modal.is(':not(.toback)');
this.hide(modal, settings.css.close, settings);
if (isCurrent) {
// remove the last modal since it is now closed
openModals.pop();
} else {
// if this isn't the current modal, then find it in the array and remove it
openModals = $.grep(openModals, function(elt) {
var isThis = elt[0] === modal[0];
if (isThis) {
// since it's not currently in the front, put it in the front now that it is hidden
// so that if it's re-opened, it won't be .toback
self.to_front(modal);
}
return !isThis;
});
}
// finally, show the next modal in the stack, if there is one
if (openModals.length > 0) {
this.to_front(openModals[openModals.length - 1]);
}
} else {
this.hide(open_modals, settings.css.close, settings);
}
}
},
close_targets: function() {
var base = '.' + this.settings.close_modal_class;
if (this.settings.backdrop && this.settings.close_on_backdrop_click) {
return base + ', .' + this.settings.backdrop_class;
}
return base;
},
toggle_backdrop: function(modal, state) {
if (!this.settings.backdrop) return;
if ($('.' + this.settings.backdrop_class).length === 0) {
this.settings.backdrop = $('<div />', {
'class': this.settings.backdrop_class
})
.appendTo('body').hide();
}
var visible = this.settings.backdrop.filter(':visible').length > 0;
if (state != visible) {
if (state == undefined ? visible : !state) {
this.hide(this.settings.backdrop);
} else {
this.show(this.settings.backdrop);
}
}
},
show: function(el, css) {
// is modal
if (css) {
var settings = el.data(this.attr_name(true) + '-init') || this.settings,
root_element = settings.root_element,
context = this;
if (el.parent(root_element).length === 0) {
var placeholder = el.wrap('<div style="display: none;" />').parent();
el.on('closed.modal.wrapped', function() {
el.detach().appendTo(placeholder);
el.unwrap().unbind('closed.modal.wrapped');
});
el.detach().appendTo(root_element);
}
var animData = getAnimationData(settings.animation);
if (!animData.animate) {
this.locked = false;
}
if (animData.fade) {
var end_css = {
opacity: 1
};
return requestAnimationFrame(function() {
return el
.css(css)
.animate(end_css, settings.animation_speed, 'linear', function() {
context.locked = false;
el.trigger('opened.modal');
})
.addClass('open')
.trigger('open.modal');
});
}
return el.css(css)
.addClass('open')
.trigger('opened.modal');
}
var settings = this.settings;
// should we animate the background?
if (getAnimationData(settings.animation).fade) {
return el.fadeIn(settings.animation_speed);
}
this.locked = false;
return el.show();
},
to_back: function(el) {
el.addClass('toback');
},
to_front: function(el) {
el.removeClass('toback');
},
hide: function(el, css) {
// is modal
if (css) {
var settings = el.data(this.attr_name(true) + '-init'),
context = this;
settings = settings || this.settings;
var animData = getAnimationData(settings.animation);
if (!animData.animate) {
this.locked = false;
}
if (animData.fade) {
var end_css = {
opacity: 0
};
return requestAnimationFrame(function() {
return el
.animate(end_css, settings.animation_speed, 'linear', function() {
context.locked = false;
el.css(css).trigger('closed.modal');
})
.removeClass('open');
});
}
return el.css(css).removeClass('open').trigger('closed.modal');
}
var settings = this.settings;
// should we animate the background?
if (getAnimationData(settings.animation).fade) {
return el.fadeOut(settings.animation_speed);
}
return el.hide();
},
close_video: function(e) {
var video = $('.flex-video', e.target),
iframe = $('iframe', video);
if (iframe.length > 0) {
iframe.attr('data-src', iframe[0].src);
iframe.attr('src', iframe.attr('src'));
video.hide();
}
},
open_video: function(e) {
var video = $('.flex-video', e.target),
iframe = video.find('iframe');
if (iframe.length > 0) {
var data_src = iframe.attr('data-src');
if (typeof data_src === 'string') {
iframe[0].src = iframe.attr('data-src');
} else {
var src = iframe[0].src;
iframe[0].src = undefined;
iframe[0].src = src;
}
video.show();
}
},
off: function() {
$(this.scope).off('.modal');
},
reflow: function() {}
};
/*
* getAnimationData('fade') // {animate: true, fade: true}
* getAnimationData(null) // {animate: false, fade: false}
*/
function getAnimationData(str) {
var fade = /fade/i.test(str);
return {
animate: fade,
fade: fade
};
}
}(jQuery, window, window.document));
(function($, window, document, undefined) {
'use strict';
Mobile.libs.tab = {
name: 'tab',
settings: {
active_class: 'active',
content_class: 'tabs-content',
panel_class: 'content',
callback: function() {},
deep_linking: false,
scroll_to_content: true
},
default_tab_hashes: [],
init: function(scope, method, options) {
var self = this;
// Store the default active tabs which will be referenced when the
// location hash is absent, as in the case of navigating the tabs and
// returning to the first viewing via the browser Back button.
$('[' + this.attr_name() + '] > .active > a', this.scope).each(function() {
self.default_tab_hashes.push(this.hash);
});
// store the initial href, which is used to allow correct behaviour of the
// browser back button when deep linking is turned on.
this.entry_location = window.location.href;
this.bindings(method, options);
this.handle_location_hash_change();
},
events: function() {
var self = this;
var usual_tab_behavior = function(e, target) {
var settings = $(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
if ('ontouchstart' in document) {
e.preventDefault();
e.stopPropagation();
self.toggle_active_tab($(target).parent());
}
};
$(this.scope)
.off('.tab')
// Click event: tab title
.on('click.tab', '[' + this.attr_name() + '] > * > a', function(e) {
var el = this;
usual_tab_behavior(e, el);
});
// Location hash change event
$(window).on('hashchange.tab', function(e) {
e.preventDefault();
self.handle_location_hash_change();
});
},
handle_location_hash_change: function() {
var self = this;
$('[' + this.attr_name() + ']', this.scope).each(function() {
var settings = $(this).data(self.attr_name(true) + '-init');
if (settings.deep_linking) {
// Match the location hash to a label
var hash;
if (settings.scroll_to_content) {
hash = self.scope.location.hash;
} else {
// prefix the hash to prevent anchor scrolling
hash = self.scope.location.hash.replace('mob-', '');
}
if (hash != '') {
// Check whether the location hash references a tab content div or
// another element on the page (inside or outside the tab content div)
var hash_element = $(hash);
if (hash_element.hasClass(settings.panel_class) && hash_element.parent().hasClass(settings.content_class)) {
// Tab content div
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent());
} else {
// Not the tab content div. If inside the tab content, find the
// containing tab and toggle it as active.
var hash_tab_container_id = hash_element.closest('.' + settings.panel_class).attr('id');
if (hash_tab_container_id != undefined) {
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash);
}
}
} else {
// Reference the default tab hashes which were initialized in the init function
for (var ind = 0; ind < self.default_tab_hashes.length; ind++) {
self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent());
}
}
}
});
},
toggle_active_tab: function(tab, location_hash) {
var self = this,
tabs = tab.closest('[' + this.attr_name() + ']'),
tab_link = tab.find('a'),
anchor = tab.children('a').first(),
target_hash = '#' + anchor.attr('href').split('#')[1],
target = $(target_hash),
siblings = tab.siblings(),
settings = tabs.data(this.attr_name(true) + '-init'),
go_to_hash = function(hash) {
// This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it
// the user would get continually redirected to the default hash.
var is_entry_location = window.location.href === self.entry_location,
default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash : 'mob-' + self.default_tab_hashes[0].replace('#', '')
if (!(is_entry_location && hash === default_hash)) {
window.location.hash = hash;
}
};
// allow usage of data-tab-content attribute instead of href
if (anchor.data('tab-content')) {
target_hash = '#' + anchor.data('tab-content').split('#')[1];
target = $(target_hash);
}
if (settings.deep_linking) {
if (settings.scroll_to_content) {
// retain current hash to scroll to content
go_to_hash(location_hash || target_hash);
if (location_hash == undefined || location_hash == target_hash) {
tab.parent()[0].scrollIntoView();
} else {
$(target_hash)[0].scrollIntoView();
}
} else {
// prefix the hashes so that the browser doesn't scroll down
if (location_hash != undefined) {
go_to_hash('mob-' + location_hash.replace('#', ''));
} else {
go_to_hash('mob-' + target_hash.replace('#', ''));
}
}
}
// WARNING: The activation and deactivation of the tab content must
// occur after the deep linking in order to properly refresh the browser window.
// Clean up multiple attr instances to done once
tab.addClass(settings.active_class).triggerHandler('opened');
tab_link.attr('aria-selected', 'true');
siblings.removeClass(settings.active_class);
siblings.find('a').attr('aria-selected', 'false');
target.siblings().removeClass(settings.active_class).attr('aria-hidden', 'true');
target.addClass(settings.active_class).attr('aria-hidden', 'false');
settings.callback(tab);
target.triggerHandler('toggled', [target]);
tabs.triggerHandler('toggled', [tab]);
},
off: function() {},
reflow: function() {}
};
}(jQuery, window, window.document));
(function($, window, document, undefined) {
'use strict';
Mobile.libs.tips = {
name: 'tips',
settings: {
// to display the massage text and so on
content: '',
// disappear after how many milliseconds.
delay: 3000,
// controll the tips' style.
type: 'pop',
// show on init
show: false,
// extra class
class: '',
// relative positioning of element.
relativeTo: document.body,
// background overlay element.
has_overlay: false,
overlay_class: 'overlay'
},
effect: {
pop: {
in: 'slide-in-down',
out: 'slide-out-up'
},
msg: {
in: 'fade-in',
out: 'fade-out'
},
slide: {
in: 'slide-in-up',
out: 'slide-out-down'
},
overlay: {
in: 'fade-in',
out: 'fade-out'
}
},
init: function(scope, method, options) {
this.bindings(method, options);
this.settings.show && this.show();
},
events: function() {
var self = this;
var attr = this.attr_name();
$(this.scope)
.on('click.tips', '[' + attr + ']', function(e) {
e.preventDefault();
var content = $(this).attr(attr + '-content');
var type = $(this).attr(attr);
self.show(content, type);
});
},
create: function(content, type) {
var tipTpl = '<div class="' + type + 'tip ' + this.settings.class + '">' +
'<div class="content animated">' +
content +
'</div>' +
'</div>';
this.element = $(tipTpl).appendTo(document.body);
if(this.settings.has_overlay) {
var overlayTpl = '<div class="' + this.settings.overlay_class + ' animated"></div>';
this.overlay = $(overlayTpl).appendTo(document.body);
}
},
show: function(content, type) {
content = content || this.settings.content;
type = type || this.settings.type;
clearTimeout(this.timer);
if(!this.element) this.create(content, type);
else {
this.element
.off('animationend webkitAnimationEnd')
.find('.content')
.html(content);
if(this.overlay) this.overlay.off('animationend webkitAnimationEnd');
}
if(type === 'pop' && this.settings.relativeTo) {
this.element.css('top', $(this.settings.relativeTo).offset().top);
}
type = this.effect[type];
this.element
.show()
.trigger('show.tips')
.find('.content')
.removeClass(type.out)
.addClass(type.in);
if(this.overlay) {
this.overlay
.show()
.trigger('show.overlay')
.removeClass(this.effect.overlay.out)
.addClass(this.effect.overlay.in)
}
if (this.settings.delay) {
this.timer = setTimeout($.proxy(function() {
this.hide(type);
}, this), this.settings.delay);
}
},
hide: function(type) {
var self = this;
type = type || this.effect[this.settings.type];
this.element
.trigger('hide.tips')
.find('.content')
.removeClass(type.in)
.addClass(type.out)
.one('animationend webkitAnimationEnd', function() {
$(this).parent().remove();
self.element = null;
});
if(this.overlay) {
this.overlay
.trigger('hide.overlay')
.removeClass(this.effect.overlay.in)
.addClass(this.effect.overlay.out)
.one('animationend webkitAnimationEnd', function() {
$(this).remove();
self.overlay = null;
});
}
},
reflow: function() {}
};
})(jQuery, window, window.document);
(function($, window, document, undefined) {
'use strict';
Mobile.libs.topbar = {
name: 'topbar',
settings: {
sticky_class: 'sticky',
start_offset: 0,
is_hover: true
},
init: function(section, method, options) {
Mobile.inherit(this, 'add_custom_rule');
var self = this;
this.bindings(method, options);
$('[' + this.attr_name() + ']', this.scope).each(function() {
var topbar = $(this),
topbarContainer = topbar.parent(),
maxHeight = Math.max(topbarContainer.outerHeight(), topbar.outerHeight()),
settings = topbar.data(self.attr_name(true) + '-init');
if (topbarContainer.hasClass('fixed')) {
if (topbarContainer.hasClass('bottom')) {
$('body').css('padding-bottom', maxHeight);
}
else {
$('body').css('padding-top', maxHeight);
}
return;
}
if (self.stickable(topbarContainer, settings)) {
self.settings.sticky_class = settings.sticky_class;
self.settings.sticky_topbar = topbar;
topbar.data('height', topbarContainer.outerHeight(true));
topbar.data('stickyOffset', topbarContainer.offset().top);
if (!settings.sticked) {
settings.start_offset && topbarContainer.css('top', settings.start_offset);
self.sticked(topbar);
// Pad body when sticky (scrolled) or fixed.
self.add_custom_rule('.act-topbar-fixed { padding-top: ' + topbar.data('height') + 'px; }');
}
}
});
},
stickable: function(topbarContainer, settings) {
return topbarContainer.hasClass(settings.sticky_class);
},
timer: null,
events: function(bar) {
var self = this;
$(this.scope)
.off('.topbar')
.on('click.topbar contextmenu.topbar', '.top-bar .top-bar-section li a[href^="#"],[' + this.attr_name() + '] .top-bar-section li a[href^="#"]', function(e) {
var li = $(this).closest('li'),
topbar = li.closest('[' + self.attr_name() + ']'),
settings = topbar.data(self.attr_name(true) + '-init');
if (settings.is_hover) {
var hoverLi = $(this).closest('.hover');
hoverLi.removeClass('hover');
}
});
$(window).off('.topbar')
.on('resize.topbar', this.resize())
.trigger('resize.topbar')
.load(function() {
// Ensure that the offset is calculated after all of the pages resources have loaded
$(this).trigger('resize.topbar');
});
$('body').off('.topbar').on('click.topbar', function(e) {
var parent = $(e.target).closest('li').closest('li.hover');
if (parent.length > 0) {
return;
}
$('[' + self.attr_name() + '] li.hover').removeClass('hover');
});
// Show dropdown menus when their items are focused
$(this.scope).find('.dropdown a')
.focus(function() {
$(this).parents('.has-dropdown').addClass('hover');
})
.blur(function() {
$(this).parents('.has-dropdown').removeClass('hover');
});
},
resize: function() {
var self = this;
$('[' + this.attr_name() + ']').each(function() {
var topbar = $(this),
settings = topbar.data(self.attr_name(true) + '-init');
var stickyContainer = topbar.parent('.' + self.settings.sticky_class);
var stickyOffset;
if (self.stickable(stickyContainer, self.settings)) {
if (stickyContainer.hasClass('fixed')) {
// Remove the fixed to allow for correct calculation of the offset.
stickyContainer.removeClass('fixed');
stickyOffset = stickyContainer.offset().top;
if ($(document.body).hasClass('act-topbar-fixed')) {
stickyOffset -= topbar.data('height');
}
topbar.data('stickyOffset', stickyOffset);
stickyContainer.addClass('fixed');
} else {
stickyOffset = stickyContainer.offset().top;
topbar.data('stickyOffset', stickyOffset);
}
}
});
},
sticked: function(topbar) {
// check for sticky
this.sticky(topbar.parent());
topbar.data(this.attr_name(true), $.extend({}, topbar.data(this.attr_name(true)), {
sticked: true
}));
},
sticky: function(element) {
var self = this;
$(window).on('scroll', function() {
if(!self.supportSticky(element)) {
self.update_sticky_positioning();
}
self.changeStatus(element, 'sticking');
});
},
changeStatus: function(element, className) {
var stickier = this.settings.sticky_topbar;
if(stickier) {
if (this.isSticky(stickier)) {
element.addClass(className);
}
else {
element.removeClass(className);
}
}
},
isSticky: function(element) {
var $window = $(window),
distance = element.data('stickyOffset') - this.settings.start_offset;
return $window.scrollTop() > distance;
},
supportSticky: function(element) {
var dom = document.createElement('test');
dom.style.position = '-webkit-sticky';
dom.style.position = 'sticky';
return /sticky/.test(dom.style.position) && ['visible', ''].indexOf($(element).parent().css('overflow')) > -1;
},
update_sticky_positioning: function() {
var klass = '.' + this.settings.sticky_class,
stickier = this.settings.sticky_topbar;
if (stickier && this.stickable(stickier.parent(), this.settings)) {
if (this.isSticky(stickier)) {
if (!$(klass).hasClass('fixed')) {
$(klass).addClass('fixed');
$('body').addClass('act-topbar-fixed');
}
} else {
if ($(klass).hasClass('fixed')) {
$(klass).removeClass('fixed');
$('body').removeClass('act-topbar-fixed');
}
}
}
},
off: function() {
$(this.scope).off('.topbar');
$(window).off('.topbar');
},
reflow: function() {}
};
}(jQuery, window, window.document));
(function($, window, document, undefined) {
'use strict';
Mobile.libs.validator = {
name: 'validator',
settings: {
validate_on: 'manual', // change (when input value changes), blur (when input blur), manual (when call custom events)
exception: ':hidden, [data-validator-ignore]', // ignore validate with 'exception' setting
focus_on_invalid: false, // automatically bring the focus to an invalid input field
has_hint: true, // popup a alert window if invalid
error_labels: true, // labels with a for="inputId" will receive an `error` class
error_class: 'has-error', // labels with a for="inputId" will receive an `error` class
feedback: '.form-row', // support a parent(s) selector for feedback an error message box
alert_element: '.alert-box', // for an error message box class
isAjax: false, // You can set ajax mode
preventDefault: false,
// the amount of time Validator will take before it validates the form (in ms).
// smaller time will result in faster validation
timeout: 1000,
patterns: {
alpha: /^[a-zA-Z]*$/,
digital: /^\d*$/,
alpha_digital: /^[a-zA-Z\d]*$/,
int: /^[-+]?\d*$/,
positive: /^\+?\d*(?:[\.]\d+)?$/,
negative: /^-\d*(?:[\.]\d+)?$/,
number: /^[-+]?\d*(?:[\.]\d+)?$/,
// http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
email: /^[\w.!#$%&'*+\/=?^`{|}~-]+@[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?(?:\.[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?)*$/,
// http://blogs.lse.ac.uk/lti/2008/04/23/a-regular-expression-to-match-any-url/
url: /^(https?|ftp|file|ssh):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z\d\.]+)+:?(\d+)?((\/[-\+~%\/\.\w]+)?\??([-\+=&;%@\.\w]+)?#?([\w]+)?)?/,
// abc.de
domain: /^([a-zA-Z\d]([a-zA-Z\d\-]{0,61}[a-zA-Z\d])?\.)+[a-zA-Z]{2,8}$/,
datetime: /^([0-2]\d{3})\-([0-1]\d)\-([0-3]\d)\s([0-2]\d):([0-5]\d):([0-5]\d)([-+]([0-1]\d)\:00)?$/,
// YYYY-MM-DD
date: /(?:19|20)\d{2}[-/.](?:(?:0?[1-9]|1[0-2])[-/.](?:0?[1-9]|1\d|2\d)|(?:(?!02)(?:0?[1-9]|1[0-2])[-/.](?:30))|(?:(?:0?[13578]|1[02])[-/.]31))$/,
// HH:MM:SS
time: /^(0?\d|1\d|2[0-3])(:[0-5]\d){2}$/,
// #FFF or #FFFFFF
color: /^#([a-fA-F\d]{6}|[a-fA-F\d]{3})$/,
mobile: /^0?(?:1(?:[38]\d)|(?:4[579])|(?:[57][0-35-9]))\d{8}$/,
tel: /^(0\d{2,3}-?)?[2-9]\d{5,7}(-\d{1,5})?$/,
zip: /^\d{6}$/
},
verifiers: {
requiredone: function(el, required, parent) {
return $(el).closest('[' + this.attr_name() + ']').find('input[type="' + el.type + '"][name="' + el.name + '"]:checked:not(:disabled)').length;
},
equalto: function(el, required, parent) {
var from = document.querySelector(el.getAttribute(this.add_namespace(this.attr_name() + '-equalto')));
return from && (from.value === el.value);
},
oneof: function(el, required, parent) {
var els = document.querySelectorAll(el.getAttribute(this.add_namespace(this.attr_name() + '-oneof')));
return this.valid_oneof(els, required, parent);
}
},
alerts: {
required: '请{how}{placeholder}',
alpha: '请填写英文字母!',
digital: '只允许填写数字!',
alpha_digital: '请填写英文字母或数字!',
int: '请填写整数!',
positive: '请填写正数!',
negative: '请填写负数!',
number: '请填写数值!',
email: '请填写正确的邮箱地址!',
url: '请填写正确的 URL 地址!',
domain: '请填写正确的域名!',
datetime: '请填写正确的日期和时间格式!',
date: '请填写正确的日期格式!',
time: '请填写正确的时间格式!',
color: '请填写十六进制颜色格式!',
mobile: '手机号码有误,请重新填写!',
tel: '电话号码有误,请重新填写!',
zip: '邮政编码格式有误,请重新填写!'
}
},
timer: null,
init: function(scope, method) {
this.bindings(method, Array.prototype.slice.call(arguments, 2));
},
events: function(scope) {
var self = this,
form = $(scope).attr('novalidate', 'novalidate'),
settings = form.data(this.attr_name(true) + '-init') || {};
this.invalid_attr = this.add_namespace('data-invalid');
function validate(el, originalSelf, e) {
clearTimeout(self.timer);
self.timer = setTimeout(function() {
self.validate(el, [originalSelf], e);
}.bind(originalSelf), settings.timeout);
}
form
.off('.validator')
.on('submit.validator', function(e) {
var $this = $(this);
var is_ajax = $this.attr(self.attr_name()) === 'ajax' || self.settings.isAjax;
$this.find('[type=submit]').prop('disabled', true);
return self.validate($this, $this.find('input, textarea, select, [' + self.attr_name() + '-verifier]').not(settings.exception).get(), e, is_ajax);
})
.on('validate.validator', function(e) {
if (settings.validate_on === 'manual') {
self.validate($(this), [e.target], e);
}
})
.on('reset', function(e) {
return self.reset($(this), e);
})
.find('input, textarea, select').not(settings.exception)
.off('.validator')
.on('blur.validator', function(e) {
var id = this.id,
parent = $(this).closest('form'),
eqTo = parent.find('[' + self.attr_name() + '-equalto="#' + id + '"]')[0];
// checks if there is an equalTo equivalent related by id
if (eqTo && eqTo.value) {
validate(parent, eqTo, e);
}
if (settings.validate_on === 'blur') {
validate(parent, this, e);
}
})
.on('change.validator', function(e) {
var id = this.id,
parent = $(this).closest('form'),
eqTo = parent.find('[' + self.attr_name() + '-equalto="#' + id + '"]')[0];
// checks if there is an equalTo equivalent related by id
if (eqTo && eqTo.value) {
validate(parent, eqTo, e);
}
if (settings.validate_on === 'change') {
validate(parent, this, e);
}
});
// Not compatible, so commet it for a while
// .on('focus.validator', function(e) {
// if (navigator.userAgent.match(/iPad|iPhone|Android|BlackBerry|Windows Phone|webOS/i)) {
// $('html, body').animate({
// scrollTop: $(e.target).offset().top
// }, 100);
// }
// });
},
reset: function(form, e) {
form.removeAttr(this.invalid_attr);
var settings = form.data(this.attr_name(true) + '-init') || {};
$('[' + this.invalid_attr + ']', form).removeAttr(this.invalid_attr);
$('.' + settings.error_class, form).not(settings.alert_element).removeClass(settings.error_class);
$(':input', form).not(':radio, :checkbox, :button, :submit, :reset,' + settings.exception).val('').removeAttr(this.invalid_attr);
$('input:radio, input:checkbox', form).prop('checked', false).removeAttr(this.invalid_attr);
},
validate: function(form, els, e, is_ajax) {
var validations = this.parse_patterns(form, els),
validation_count = validations.length,
submit_event = /submit/i.test(e.type);
// Has to count up to make sure the focus gets applied to the top error
for (var i = 0; i < validation_count; i++) {
if (!validations[i] && (submit_event || is_ajax)) {
if (this.settings.focus_on_invalid) {
els[i].focus();
}
form.trigger('invalid.validator', [e]);
$(els[i]).closest('form').attr(this.invalid_attr, '');
form.find('button[type=submit]').prop('disabled', false);
return false;
}
}
if (submit_event || is_ajax) {
if (this.settings.preventDefault) e.preventDefault();
form.trigger('valid.validator', [e]);
}
form.removeAttr(this.invalid_attr);
if (is_ajax) {
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
dataType: 'json',
beforeSend: function() {
$(document).mobile('tips', 'show', ['<div class="text-align"><i class="spinner"></i></div>', 'msg']);
}
})
.done(function(rs) {
form.trigger('complete.validator', [rs]);
form.find('[type=submit]').prop('disabled', false);
})
.fail(function() {
form.find('[type=submit]').prop('disabled', false);
});
return false;
}
return true;
},
parse_patterns: function(form, els) {
var i = els.length,
el_patterns = [];
while (i--) {
el_patterns.push(this.pattern(els[i]));
}
if (el_patterns.length) {
el_patterns = this.check_validation(form, el_patterns);
}
return el_patterns;
},
pattern: function(el) {
var type = el.type,
required = el.hasAttribute('required'),
pattern = el.getAttribute('pattern') || '',
verifier = el.getAttribute(this.add_namespace(this.attr_name() + '-verifier')) || '',
eqTo = el.hasAttribute(this.add_namespace(this.attr_name() + '-equalto')),
oneof = el.hasAttribute(this.add_namespace(this.attr_name() + '-oneof'));
if (this.settings.patterns.hasOwnProperty(pattern)) {
return [el, pattern, this.settings.patterns[pattern], required];
} else if (pattern) {
return [el, null, new RegExp('^' + pattern + '$'), required];
} else if (verifier) {
return [el, verifier, this.settings.patterns[type], required];
} else if (this.settings.patterns.hasOwnProperty(type)) {
return [el, type, this.settings.patterns[type], required];
} else if (eqTo || oneof) {
return [el, eqTo ? 'equalto' : 'oneof', pattern, required];
} else {
pattern = /^[\s\S]*$/;
return [el, required ? 'required' : null, pattern, required];
}
},
// TODO: Break this up into smaller methods, getting hard to read.
check_validation: function(form, el_patterns) {
var i = el_patterns.length,
validations = [],
settings = form.data(this.attr_name(true) + '-init') || {};
while (i--) {
var el = el_patterns[i][0],
required = el_patterns[i][3],
value = el.value.trim(),
is_radio = el.type === 'radio',
is_checkbox = el.type === 'checkbox',
direct_parent = $(el).parent(),
verifier = el.getAttribute(this.add_namespace(this.attr_name() + '-verifier')),
label = (function() {
var label = $(el).siblings('label');
if (!label.length) {
label = $('label[for="' + el.id + '"]');
}
return label;
})(),
valid_length = required ? (value.length > 0) : true,
el_validations = [],
parent,
valid;
if ((is_radio || is_checkbox) && required) {
verifier = 'requiredone';
}
// support old way to do equalTo validations
if (el.getAttribute(this.add_namespace(this.attr_name() + '-equalto'))) {
verifier = 'equalto';
}
if (el.getAttribute(this.add_namespace(this.attr_name() + '-oneof'))) {
verifier = 'oneof';
}
if (settings.feedback) {
parent = $(el).parents(settings.feedback).eq(0);
}
if (!parent || !parent.length) {
if (direct_parent.is('label')) {
parent = direct_parent.parent();
} else {
parent = direct_parent;
}
}
if (verifier) {
// Validate using each of the specified (space-delimited) verifiers.
var verifiers = verifier.split(' ');
var last_valid = true,
all_valid = true;
for (var iv = 0; iv < verifiers.length; iv++) {
valid = this.settings.verifiers[verifiers[iv]].apply(this, [el, required, parent]);
el_validations.push(valid);
all_valid = valid && last_valid;
last_valid = valid;
}
if (all_valid) {
this.validSuccess(el, parent, label);
} else {
validations = this.validError(el, parent, label, i, el_patterns, el_validations);
if(validations.length) break;
}
} else {
el_validations.push(el_patterns[i][2].test(value) && valid_length || !required && !value.length || el.disabled);
el_validations = [el_validations.every(function(valid) {
return valid;
})];
if (el_validations[0]) {
this.validSuccess(el, parent, label);
} else {
validations = this.validError(el, parent, label, i, el_patterns, el_validations);
if(validations.length) break;
}
}
validations = validations.concat(el_validations);
}
return validations;
},
validSuccess: function(el, parent, label) {
el.removeAttribute(this.invalid_attr);
el.setAttribute('aria-invalid', 'false');
el.removeAttribute('aria-describedby');
parent.removeClass(this.settings.error_class);
if (label.length > 0 && this.settings.error_labels) {
label.removeClass(this.settings.error_class).removeAttr('role');
}
$(el).triggerHandler('valid');
},
validError: function(el, parent, label, i, el_patterns, el_validations) {
var validations = [];
el.setAttribute(this.invalid_attr, '');
el.setAttribute('aria-invalid', 'true');
// Try to find the error associated with the input
var errorElement = parent.find(this.settings.alert_element);
var type = this.settings.alerts[el_patterns[i][1]];
var dataset = el_patterns[i][0].dataset;
var msg = dataset.alerts;
// var alertKeys = Object.keys(dataset).filter(function(k, v) {
// return k.indexOf('alerts') === 0;
// });
// var msg = '';
// $.each(alertKeys, function() {
// if (this.replace('alerts', '').toLowerCase() == el_patterns[i][1]) {
// msg = dataset[this];
// }
// });
var how = '输入';
if(!msg) {
if (type) {
if (['radio', 'checked'].indexOf(el.type) > -1 || el.tagName === 'select') {
how = '选择';
}
msg = type.replace('{how}', how).replace('{placeholder}', label.text().replace(/[:]$/, '') || el_patterns[i][0].placeholder || '其中一项');
} else {
msg = '输入不符合要求,请检查!';
}
}
if (!errorElement.length) {
if(this.settings.has_hint) {
alert(msg);
$(el).triggerHandler('invalid');
return validations.concat(el_validations);
}
} else {
// errorElement.html(msg);
var errorID = errorElement.attr('id');
if (errorID) {
el.setAttribute('aria-describedby', errorID);
}
}
// el.setAttribute('aria-describedby', $(el).find('.error')[0].id);
parent.addClass(this.settings.error_class);
if (label.length > 0 && this.settings.error_labels) {
label.addClass(this.settings.error_class).attr('role', 'alert');
}
$(el).triggerHandler('invalid');
return validations;
},
// valid_checkbox: function(el, required) {
// var el = $(el),
// valid = (el.is(':checked') || !required || el.get(0).getAttribute('disabled'));
// if (valid) {
// el.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class);
// $(el).triggerHandler('valid');
// } else {
// el.attr(this.invalid_attr, '').parent().addClass(this.settings.error_class);
// $(el).triggerHandler('invalid');
// }
// return valid;
// },
// valid_radio: function(el, required) {
// var name = el.getAttribute('name'),
// group = $(el).closest('[data-' + this.attr_name(true) + ']').find("[name='" + name + "']"),
// count = group.length,
// valid = false,
// disabled = false;
// // Has to count up to make sure the focus gets applied to the top error
// for (var i = 0; i < count; i++) {
// if (group[i].getAttribute('disabled')) {
// disabled = true;
// valid = true;
// } else {
// if (group[i].checked) {
// valid = true;
// } else {
// if (disabled) {
// valid = false;
// }
// }
// }
// }
// // Has to count up to make sure the focus gets applied to the top error
// for (var i = 0; i < count; i++) {
// if (valid) {
// $(group[i]).removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class);
// $(group[i]).triggerHandler('valid');
// } else {
// $(group[i]).attr(this.invalid_attr, '').parent().addClass(this.settings.error_class);
// $(group[i]).triggerHandler('invalid');
// }
// }
// return valid;
// },
// valid_equal: function(el, required, parent) {
// var from = document.getElementById(el.getAttribute(this.add_namespace(this.attr_name() + '-equalto'))).value,
// to = el.value,
// valid = (from === to);
// if (valid) {
// $(el).removeAttr(this.invalid_attr);
// parent.removeClass(this.settings.error_class);
// if (label.length > 0 && settings.error_labels) {
// label.removeClass(this.settings.error_class);
// }
// } else {
// $(el).attr(this.invalid_attr, '');
// parent.addClass(this.settings.error_class);
// if (label.length > 0 && settings.error_labels) {
// label.addClass(this.settings.error_class);
// }
// }
// return valid;
// },
valid_oneof: function(el, required, parent, doNotValidateOthers) {
var el = $(el),
valid = el.filter(function() {
return ['radio', 'checkbox'].indexOf(this.type) > -1 ? this.checked : !!this.value.trim();
}).length > 0;
if (valid) {
el.removeAttr(this.invalid_attr);
parent.removeClass(this.settings.error_class);
} else {
el.attr(this.invalid_attr, '');
parent.addClass(this.settings.error_class);
}
if (!doNotValidateOthers) {
var _this = this;
el.each(function() {
_this.valid_oneof.call(_this, this, null, parent, true);
});
}
return valid;
},
reflow: function(scope, options) {
var self = this,
form = $('[' + this.attr_name() + ']'); //.attr('novalidate', 'novalidate');
form.each(function() {
self.events(this);
});
}
};
}(jQuery, window, window.document));