You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
21960 lines
1.0 MiB
21960 lines
1.0 MiB
/*!
|
|
* DevExpress PhoneJS
|
|
* Version: 13.2.7
|
|
* Build date: Feb 10, 2014
|
|
*
|
|
* Copyright (c) 2012 - 2014 Developer Express Inc. ALL RIGHTS RESERVED
|
|
* EULA: http://phonejs.devexpress.com/EULA
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
if (!window.DevExpress) {
|
|
/*! Module core, file devexpress.js */
|
|
(function($, global, undefined) {
|
|
(function checkjQueryVersion(version) {
|
|
version = version.split(".");
|
|
if (version[0] < 1 || version[0] === 1 && version[1] < 10)
|
|
throw Error("Your version of jQuery is too old. Please upgrade jQuery to 1.10.0 or later.");
|
|
})($.fn.jquery);
|
|
var Class = function() {
|
|
var wrapOverridden = function(baseProto, methodName, method) {
|
|
return function() {
|
|
var prevCallBase = this.callBase;
|
|
this.callBase = baseProto[methodName];
|
|
try {
|
|
return method.apply(this, arguments)
|
|
}
|
|
finally {
|
|
this.callBase = prevCallBase
|
|
}
|
|
}
|
|
};
|
|
var clonePrototype = function(obj) {
|
|
var func = function(){};
|
|
func.prototype = obj.prototype;
|
|
return new func
|
|
};
|
|
var classImpl = function(){};
|
|
var redefine = function(members) {
|
|
var self = this;
|
|
if (!members)
|
|
return self;
|
|
var memberNames = $.map(members, function(_, k) {
|
|
return k
|
|
});
|
|
$.each(["toString", "toLocaleString", "valueOf"], function() {
|
|
if (members[this])
|
|
memberNames.push(this)
|
|
});
|
|
$.each(memberNames, function() {
|
|
var overridden = $.isFunction(self.prototype[this]) && $.isFunction(members[this]);
|
|
self.prototype[this] = overridden ? wrapOverridden(self.parent.prototype, this, members[this]) : members[this]
|
|
});
|
|
return self
|
|
};
|
|
var include = function() {
|
|
var classObj = this;
|
|
$.each(arguments, function() {
|
|
if (this.ctor)
|
|
classObj._includedCtors.push(this.ctor);
|
|
for (var name in this) {
|
|
if (name === "ctor")
|
|
continue;
|
|
if (name in classObj.prototype)
|
|
throw Error("Member name collision: " + name);
|
|
classObj.prototype[name] = this[name]
|
|
}
|
|
});
|
|
return classObj
|
|
};
|
|
var subclassOf = function(parentClass) {
|
|
if (this.parent === parentClass)
|
|
return true;
|
|
if (!this.parent || !this.parent.subclassOf)
|
|
return false;
|
|
return this.parent.subclassOf(parentClass)
|
|
};
|
|
classImpl.inherit = function(members) {
|
|
var inheritor = function() {
|
|
if (!this || this.constructor !== inheritor)
|
|
throw Error("A class must be instantiated using the 'new' keyword");
|
|
var instance = this,
|
|
ctor = instance.ctor;
|
|
if (ctor)
|
|
ctor.apply(instance, arguments);
|
|
$.each(instance.constructor._includedCtors, function() {
|
|
this.call(instance)
|
|
})
|
|
};
|
|
inheritor.prototype = clonePrototype(this);
|
|
inheritor.inherit = this.inherit;
|
|
inheritor.redefine = redefine;
|
|
inheritor.include = include;
|
|
inheritor.subclassOf = subclassOf;
|
|
inheritor.parent = this;
|
|
inheritor._includedCtors = this._includedCtors ? this._includedCtors.slice(0) : [];
|
|
inheritor.prototype.constructor = inheritor;
|
|
inheritor.redefine(members);
|
|
return inheritor
|
|
};
|
|
return classImpl
|
|
}();
|
|
function createQueue(discardPendingTasks) {
|
|
var _tasks = [],
|
|
_busy = false;
|
|
function exec() {
|
|
while (_tasks.length) {
|
|
var task = _tasks.shift(),
|
|
result = task();
|
|
if (result === undefined)
|
|
continue;
|
|
if (result.then) {
|
|
_busy = true;
|
|
$.when(result).always(exec);
|
|
return
|
|
}
|
|
throw Error("Queued task returned unexpected result");
|
|
}
|
|
_busy = false
|
|
}
|
|
function add(task, removeTaskCallback) {
|
|
if (!discardPendingTasks)
|
|
_tasks.push(task);
|
|
else {
|
|
if (_tasks[0] && removeTaskCallback)
|
|
removeTaskCallback(_tasks[0]);
|
|
_tasks = [task]
|
|
}
|
|
if (!_busy)
|
|
exec()
|
|
}
|
|
function busy() {
|
|
return _busy
|
|
}
|
|
return {
|
|
add: add,
|
|
busy: busy
|
|
}
|
|
}
|
|
var parseUrl = function() {
|
|
var a = document.createElement("a"),
|
|
props = ["protocol", "hostname", "port", "pathname", "search", "hash"];
|
|
var normalizePath = function(value) {
|
|
if (value.charAt(0) !== "/")
|
|
value = "/" + value;
|
|
return value
|
|
};
|
|
return function(url) {
|
|
a.href = url;
|
|
var result = {};
|
|
$.each(props, function() {
|
|
result[this] = a[this]
|
|
});
|
|
result.pathname = normalizePath(result.pathname);
|
|
return result
|
|
}
|
|
}();
|
|
global.DevExpress = global.DevExpress || {};
|
|
var enqueueAsync = function(task) {
|
|
var deferred = $.Deferred();
|
|
setTimeout(function() {
|
|
deferred.resolve(task())
|
|
}, 60);
|
|
return deferred
|
|
};
|
|
var backButtonCallback = function() {
|
|
var callbacks = [];
|
|
return {
|
|
add: function(callback) {
|
|
callbacks.push(callback)
|
|
},
|
|
remove: function(callback) {
|
|
var indexOfCallback = $.inArray(callback, callbacks);
|
|
if (indexOfCallback !== -1)
|
|
callbacks.splice(indexOfCallback, 1)
|
|
},
|
|
fire: function() {
|
|
var callback = callbacks.pop(),
|
|
result = !!callback;
|
|
if (result)
|
|
callback();
|
|
return result
|
|
},
|
|
hasCallback: function() {
|
|
return callbacks.length > 0
|
|
},
|
|
reset: function() {
|
|
callbacks = []
|
|
}
|
|
}
|
|
}();
|
|
var overlayTargetContainer = function() {
|
|
var defaultTargetContainer = "body";
|
|
return function(targetContainer) {
|
|
if (arguments.length)
|
|
defaultTargetContainer = targetContainer;
|
|
return defaultTargetContainer
|
|
}
|
|
}();
|
|
$.extend(global.DevExpress, {
|
|
abstract: function() {
|
|
throw Error("Not implemented");
|
|
},
|
|
Class: Class,
|
|
createQueue: createQueue,
|
|
enqueue: createQueue().add,
|
|
enqueueAsync: enqueueAsync,
|
|
parseUrl: parseUrl,
|
|
backButtonCallback: backButtonCallback,
|
|
overlayTargetContainer: overlayTargetContainer
|
|
})
|
|
})(jQuery, this);
|
|
/*! Module core, file inflector.js */
|
|
(function($, DX, undefined) {
|
|
var _normalize = function(text) {
|
|
if (text === undefined || text === null)
|
|
return "";
|
|
return String(text)
|
|
};
|
|
var _ucfirst = function(text) {
|
|
return _normalize(text).charAt(0).toUpperCase() + text.substr(1)
|
|
};
|
|
var _chop = function(text) {
|
|
return _normalize(text).replace(/([a-z\d])([A-Z])/g, "$1 $2").split(/[\s_-]+/)
|
|
};
|
|
var dasherize = function(text) {
|
|
return $.map(_chop(text), function(p) {
|
|
return p.toLowerCase()
|
|
}).join("-")
|
|
};
|
|
var underscore = function(text) {
|
|
return dasherize(text).replace(/-/g, "_")
|
|
};
|
|
var camelize = function(text, upperFirst) {
|
|
return $.map(_chop(text), function(p, i) {
|
|
p = p.toLowerCase();
|
|
if (upperFirst || i > 0)
|
|
p = _ucfirst(p);
|
|
return p
|
|
}).join("")
|
|
};
|
|
var humanize = function(text) {
|
|
return _ucfirst(dasherize(text).replace(/-/g, " "))
|
|
};
|
|
var titleize = function(text) {
|
|
return $.map(_chop(text), function(p) {
|
|
return _ucfirst(p.toLowerCase())
|
|
}).join(" ")
|
|
};
|
|
DX.inflector = {
|
|
dasherize: dasherize,
|
|
camelize: camelize,
|
|
humanize: humanize,
|
|
titleize: titleize,
|
|
underscore: underscore
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file devices.js */
|
|
(function($, DX, undefined) {
|
|
var knownUATable = {
|
|
iPhone: "iPhone",
|
|
iPhone5: "iPhone 5",
|
|
iPad: "iPad",
|
|
iPadMini: "iPad Mini",
|
|
androidPhone: "Android Mobile",
|
|
androidTablet: "Android",
|
|
win8: "MSAppHost",
|
|
win8Phone: "Windows Phone 8",
|
|
msSurface: "MSIE ARM Tablet PC",
|
|
desktop: "desktop",
|
|
tizen: "Tizen Mobile"
|
|
};
|
|
var knownMajorVersion = {
|
|
ios: [5, 6, 7],
|
|
android: [2, 3, 4],
|
|
win8: [8],
|
|
tizen: [2],
|
|
desktop: [],
|
|
generic: []
|
|
};
|
|
var device;
|
|
var current = function(deviceOrName) {
|
|
if (deviceOrName)
|
|
device = getDevice(deviceOrName);
|
|
else {
|
|
if (!device) {
|
|
deviceOrName = undefined;
|
|
try {
|
|
deviceOrName = getDeviceOrNameFromWindowScope()
|
|
}
|
|
catch(e) {
|
|
deviceOrName = getDeviceNameFromSessionStorage()
|
|
}
|
|
finally {
|
|
if (!deviceOrName)
|
|
deviceOrName = getDeviceNameFromSessionStorage()
|
|
}
|
|
device = getDevice(deviceOrName)
|
|
}
|
|
return device
|
|
}
|
|
};
|
|
var getDevice = function(deviceName) {
|
|
if (deviceName === "genericPhone")
|
|
return {
|
|
deviceType: "phone",
|
|
platform: "generic",
|
|
generic: true
|
|
};
|
|
if ($.isPlainObject(deviceName))
|
|
return fromConfig(deviceName);
|
|
else {
|
|
var ua;
|
|
if (deviceName) {
|
|
ua = knownUATable[deviceName];
|
|
if (!ua)
|
|
throw Error("Unknown device");
|
|
}
|
|
else
|
|
ua = navigator.userAgent;
|
|
return fromUA(ua)
|
|
}
|
|
};
|
|
var fromConfig = function(config) {
|
|
var shortcuts = {
|
|
phone: config.deviceType === "phone",
|
|
tablet: config.deviceType === "tablet",
|
|
android: config.platform === "android",
|
|
ios: config.platform === "ios",
|
|
win8: config.platform === "win8",
|
|
tizen: config.platform === "tizen",
|
|
generic: config.platform === "generic"
|
|
};
|
|
return $.extend({}, defaultDevice, shortcuts, config)
|
|
};
|
|
var fromUA = function(ua) {
|
|
return deviceParser.ios(ua) || deviceParser.android(ua) || deviceParser.win8(ua) || deviceParser.tizen(ua) || deviceParser.desktop(ua) || genericDevice
|
|
};
|
|
var defaultDevice = {
|
|
deviceType: "",
|
|
platform: "",
|
|
version: [],
|
|
phone: false,
|
|
tablet: false,
|
|
android: false,
|
|
ios: false,
|
|
win8: false,
|
|
tizen: false,
|
|
generic: false
|
|
};
|
|
var genericDevice = $.extend(defaultDevice, {
|
|
platform: "generic",
|
|
deviceType: "phone",
|
|
generic: true
|
|
});
|
|
var deviceParser = {
|
|
ios: function(userAgent) {
|
|
if (!/ip(hone|od|ad)/i.test(userAgent))
|
|
return;
|
|
var isPhone = /ip(hone|od)/i.test(userAgent);
|
|
var matches = userAgent.match(/os (\d+)_(\d+)_?(\d+)?/i);
|
|
var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10), parseInt(matches[3] || 0, 10)] : [];
|
|
return fromConfig({
|
|
deviceType: isPhone ? "phone" : "tablet",
|
|
platform: "ios",
|
|
version: version
|
|
})
|
|
},
|
|
android: function(userAgent) {
|
|
if (!/android|htc_|silk/i.test(userAgent))
|
|
return;
|
|
var isPhone = /mobile/i.test(userAgent);
|
|
var matches = userAgent.match(/android (\d+)\.(\d+)\.?(\d+)?/i);
|
|
var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10), parseInt(matches[3] || 0, 10)] : [];
|
|
return fromConfig({
|
|
deviceType: isPhone ? "phone" : "tablet",
|
|
platform: "android",
|
|
version: version
|
|
})
|
|
},
|
|
win8: function(userAgent) {
|
|
var isPhone = /windows phone/i.test(userAgent),
|
|
isTablet = /msie(.*)arm(.*)tablet\spc/i.test(userAgent),
|
|
isDesktop = !isTablet && /msapphost/i.test(userAgent);
|
|
if (!(isPhone || isTablet || isDesktop))
|
|
return;
|
|
var matches = userAgent.match(/windows phone (\d+).(\d+)/i) || userAgent.match(/windows nt (\d+).(\d+)/i),
|
|
version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10)] : [];
|
|
return fromConfig({
|
|
deviceType: isPhone ? "phone" : isTablet ? "tablet" : "desktop",
|
|
platform: "win8",
|
|
version: version
|
|
})
|
|
},
|
|
tizen: function(userAgent) {
|
|
if (!/tizen/i.test(userAgent))
|
|
return;
|
|
var isPhone = /mobile/i.test(userAgent);
|
|
var matches = userAgent.match(/tizen (\d+)\.(\d+)/i);
|
|
var version = matches ? [parseInt(matches[1], 10), parseInt(matches[2], 10)] : [];
|
|
return fromConfig({
|
|
deviceType: isPhone ? "phone" : "tablet",
|
|
platform: "tizen",
|
|
version: version
|
|
})
|
|
},
|
|
desktop: function(userAgent) {
|
|
if (!/desktop/i.test(userAgent))
|
|
return;
|
|
return fromConfig({
|
|
deviceType: "desktop",
|
|
platform: "desktop"
|
|
})
|
|
}
|
|
};
|
|
var getDeviceOrNameFromWindowScope = function() {
|
|
var result;
|
|
if (window.top["dx-force-device-object"] || window.top["dx-force-device"])
|
|
result = window.top["dx-force-device-object"] || window.top["dx-force-device"];
|
|
return result
|
|
};
|
|
var getDeviceNameFromSessionStorage = function() {
|
|
return window.sessionStorage && (sessionStorage.getItem("dx-force-device") || sessionStorage.getItem("dx-simulator-device"))
|
|
};
|
|
var getDeviceMajorVersionClass = function(device) {
|
|
var versions = knownMajorVersion[device.platform],
|
|
deviceVersion = device.version && device.version[0],
|
|
lastVersion = versions[versions.length - 1];
|
|
if (deviceVersion) {
|
|
var isKnownVersion = $.inArray(parseInt(deviceVersion, 10), versions) !== -1,
|
|
version = isKnownVersion ? deviceVersion : lastVersion;
|
|
return " dx-version-major-" + version
|
|
}
|
|
return lastVersion ? " dx-version-major-" + lastVersion : ""
|
|
};
|
|
DX.devices = {
|
|
attachCss: function(element, device) {
|
|
var $element = $(element);
|
|
device = device || this.current();
|
|
var deviceTypeClass = device.deviceType ? " dx-device-" + device.deviceType : "";
|
|
$element.addClass("dx-theme-" + device.platform).addClass("dx-theme-" + device.platform + "-typography").addClass(deviceTypeClass).addClass(getDeviceMajorVersionClass(device))
|
|
},
|
|
current: current,
|
|
real: getDevice(),
|
|
isRippleEmulator: function() {
|
|
return !!window.tinyHippos
|
|
},
|
|
isSimulator: function() {
|
|
try {
|
|
return window.top !== window.self && window.top["dx-force-device"]
|
|
}
|
|
catch(e) {
|
|
return false
|
|
}
|
|
}
|
|
};
|
|
DX.devices.__internals = {fromUA: fromUA}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file browser.js */
|
|
(function($, DX, global, undefined) {
|
|
var webkitRegExp = /(webkit)[ \/]([\w.]+)/,
|
|
operaRegExp = /(opera)(?:.*version)?[ \/]([\w.]+)/,
|
|
ieRegExp = /(msie) ([\w.]+)/,
|
|
mozillaRegExp = /(mozilla)(?:.*? rv:([\w.]+))?/;
|
|
var ua = navigator.userAgent.toLowerCase();
|
|
var browser = function() {
|
|
var result = {},
|
|
matches = webkitRegExp.exec(ua) || operaRegExp.exec(ua) || ieRegExp.exec(ua) || ua.indexOf("compatible") < 0 && mozillaRegExp.exec(ua) || [],
|
|
browserName = matches[1],
|
|
browserVersion = matches[2];
|
|
if (browserName) {
|
|
result[browserName] = true;
|
|
result.version = browserVersion
|
|
}
|
|
return result
|
|
}();
|
|
DX.browser = browser
|
|
})(jQuery, DevExpress, this);
|
|
/*! Module core, file support.js */
|
|
(function($, DX, window) {
|
|
var cssPrefixes = ["", "Webkit", "Moz", "O", "ms"],
|
|
styles = document.createElement("dx").style;
|
|
var transitionEndEventNames = {
|
|
WebkitTransition: 'webkitTransitionEnd',
|
|
MozTransition: 'transitionend',
|
|
OTransition: 'oTransitionEnd',
|
|
msTransition: 'MsTransitionEnd',
|
|
transition: 'transitionend'
|
|
};
|
|
var styleProp = function(prop) {
|
|
prop = DX.inflector.camelize(prop, true);
|
|
for (var i = 0, cssPrefixesCount = cssPrefixes.length; i < cssPrefixesCount; i++) {
|
|
var specific = cssPrefixes[i] + prop;
|
|
if (specific in styles)
|
|
return specific
|
|
}
|
|
};
|
|
var supportProp = function(prop) {
|
|
return !!styleProp(prop)
|
|
};
|
|
var isRetinaIPad = DX.devices.real.ios && DX.devices.real.deviceType === "tablet" && window.devicePixelRatio > 1,
|
|
isDesktopIE = (DX.devices.real.deviceType === "desktop" || DX.devices.isSimulator()) && DX.browser.msie;
|
|
DX.support = {
|
|
touch: "ontouchstart" in window,
|
|
pointer: window.navigator.pointerEnabled,
|
|
transform3d: !isDesktopIE && !isRetinaIPad && supportProp("perspective"),
|
|
transition: !isRetinaIPad && supportProp("transition"),
|
|
transitionEndEventName: transitionEndEventNames[styleProp("transition")],
|
|
animation: !isRetinaIPad && supportProp("animation"),
|
|
winJS: "WinJS" in window,
|
|
styleProp: styleProp,
|
|
supportProp: supportProp,
|
|
hasKo: !!window.ko,
|
|
hasNg: !window.ko && !!window.angular,
|
|
inputType: function(type) {
|
|
if (type === "text")
|
|
return true;
|
|
var input = document.createElement("input");
|
|
try {
|
|
input.setAttribute("type", type);
|
|
input.value = "wrongValue";
|
|
return !input.value
|
|
}
|
|
catch(e) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
})(jQuery, DevExpress, this);
|
|
/*! Module core, file position.js */
|
|
(function($, DX, undefined) {
|
|
var horzRe = /left|right/,
|
|
vertRe = /top|bottom/,
|
|
collisionRe = /fit|flip|none/;
|
|
var splitPair = function(raw) {
|
|
switch (typeof raw) {
|
|
case"string":
|
|
return raw.split(/\s+/, 2);
|
|
case"object":
|
|
return [raw.x || raw.h, raw.y || raw.v];
|
|
case"number":
|
|
return [raw];
|
|
default:
|
|
return raw
|
|
}
|
|
};
|
|
var normalizeAlign = function(raw) {
|
|
var result = {
|
|
h: "center",
|
|
v: "center"
|
|
};
|
|
var pair = splitPair(raw);
|
|
if (pair)
|
|
$.each(pair, function() {
|
|
var w = String(this).toLowerCase();
|
|
if (horzRe.test(w))
|
|
result.h = w;
|
|
else if (vertRe.test(w))
|
|
result.v = w
|
|
});
|
|
return result
|
|
};
|
|
var normalizeOffset = function(raw) {
|
|
var pair = splitPair(raw),
|
|
h = parseInt(pair && pair[0], 10),
|
|
v = parseInt(pair && pair[1], 10);
|
|
if (!isFinite(h))
|
|
h = 0;
|
|
if (!isFinite(v))
|
|
v = h;
|
|
return {
|
|
h: h,
|
|
v: v
|
|
}
|
|
};
|
|
var normalizeCollision = function(raw) {
|
|
var pair = splitPair(raw),
|
|
h = String(pair && pair[0]).toLowerCase(),
|
|
v = String(pair && pair[1]).toLowerCase();
|
|
if (!collisionRe.test(h))
|
|
h = "none";
|
|
if (!collisionRe.test(v))
|
|
v = h;
|
|
return {
|
|
h: h,
|
|
v: v
|
|
}
|
|
};
|
|
var getAlignFactor = function(align) {
|
|
switch (align) {
|
|
case"center":
|
|
return 0.5;
|
|
case"right":
|
|
case"bottom":
|
|
return 1;
|
|
default:
|
|
return 0
|
|
}
|
|
};
|
|
var inverseAlign = function(align) {
|
|
switch (align) {
|
|
case"left":
|
|
return "right";
|
|
case"right":
|
|
return "left";
|
|
case"top":
|
|
return "bottom";
|
|
case"bottom":
|
|
return "top";
|
|
default:
|
|
return align
|
|
}
|
|
};
|
|
var initMyLocation = function(data) {
|
|
data.myLocation = data.atLocation + getAlignFactor(data.atAlign) * data.atSize - getAlignFactor(data.myAlign) * data.mySize + data.offset
|
|
};
|
|
var decolliders = {
|
|
fit: function(data, bounds) {
|
|
var result = false;
|
|
if (data.myLocation > bounds.max) {
|
|
data.myLocation = bounds.max;
|
|
result = true
|
|
}
|
|
if (data.myLocation < bounds.min) {
|
|
data.myLocation = bounds.min;
|
|
result = true
|
|
}
|
|
return result
|
|
},
|
|
flip: function(data, bounds) {
|
|
if (data.myAlign === "center" && data.atAlign === "center")
|
|
return false;
|
|
if (data.myLocation < bounds.min || data.myLocation > bounds.max) {
|
|
var inverseData = $.extend({}, data, {
|
|
myAlign: inverseAlign(data.myAlign),
|
|
atAlign: inverseAlign(data.atAlign),
|
|
offset: -data.offset
|
|
});
|
|
initMyLocation(inverseData);
|
|
if (inverseData.myLocation >= bounds.min && inverseData.myLocation <= bounds.max || inverseData.myLocation > data.myLocation) {
|
|
data.myLocation = inverseData.myLocation;
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
};
|
|
var scrollbarWidth;
|
|
var defaultPositionResult = {
|
|
h: {
|
|
location: 0,
|
|
flip: false,
|
|
fit: false
|
|
},
|
|
v: {
|
|
location: 0,
|
|
flip: false,
|
|
fit: false
|
|
}
|
|
};
|
|
var calculatePosition = function(what, options) {
|
|
var $what = $(what),
|
|
currentOffset = $what.offset(),
|
|
result = $.extend(true, {}, defaultPositionResult, {
|
|
h: {location: currentOffset.left},
|
|
v: {location: currentOffset.top}
|
|
});
|
|
if (!options)
|
|
return result;
|
|
var my = normalizeAlign(options.my),
|
|
at = normalizeAlign(options.at),
|
|
of = options.of || window,
|
|
offset = normalizeOffset(options.offset),
|
|
collision = normalizeCollision(options.collision);
|
|
var h = {
|
|
mySize: $what.outerWidth(),
|
|
myAlign: my.h,
|
|
atAlign: at.h,
|
|
offset: offset.h,
|
|
collision: collision.h
|
|
};
|
|
var v = {
|
|
mySize: $what.outerHeight(),
|
|
myAlign: my.v,
|
|
atAlign: at.v,
|
|
offset: offset.v,
|
|
collision: collision.v
|
|
};
|
|
if (of.preventDefault) {
|
|
h.atLocation = of.pageX;
|
|
v.atLocation = of.pageY;
|
|
h.atSize = 0;
|
|
v.atSize = 0
|
|
}
|
|
else {
|
|
of = $(of);
|
|
if ($.isWindow(of[0])) {
|
|
h.atLocation = of.scrollLeft();
|
|
v.atLocation = of.scrollTop();
|
|
h.atSize = of.width();
|
|
v.atSize = of.height()
|
|
}
|
|
else if (of[0].nodeType === 9) {
|
|
h.atLocation = 0;
|
|
v.atLocation = 0;
|
|
h.atSize = of.width();
|
|
v.atSize = of.height()
|
|
}
|
|
else {
|
|
var o = of.offset();
|
|
h.atLocation = o.left;
|
|
v.atLocation = o.top;
|
|
h.atSize = of.outerWidth();
|
|
v.atSize = of.outerHeight()
|
|
}
|
|
}
|
|
initMyLocation(h);
|
|
initMyLocation(v);
|
|
var bounds = function() {
|
|
var win = $(window),
|
|
windowWidth = win.width(),
|
|
windowHeight = win.height(),
|
|
left = win.scrollLeft(),
|
|
top = win.scrollTop(),
|
|
hScrollbar = document.width > document.documentElement.clientWidth,
|
|
vScrollbar = document.height > document.documentElement.clientHeight,
|
|
hZoomLevel = DX.support.touch ? document.documentElement.clientWidth / (vScrollbar ? windowWidth - scrollbarWidth : windowWidth) : 1,
|
|
vZoomLevel = DX.support.touch ? document.documentElement.clientHeight / (hScrollbar ? windowHeight - scrollbarWidth : windowHeight) : 1;
|
|
if (scrollbarWidth === undefined)
|
|
scrollbarWidth = calculateScrollbarWidth();
|
|
return {
|
|
h: {
|
|
min: left,
|
|
max: left + win.width() / hZoomLevel - h.mySize
|
|
},
|
|
v: {
|
|
min: top,
|
|
max: top + win.height() / vZoomLevel - v.mySize
|
|
}
|
|
}
|
|
}();
|
|
if (decolliders[h.collision])
|
|
result.h[h.collision] = decolliders[h.collision](h, bounds.h);
|
|
if (decolliders[v.collision])
|
|
result.v[v.collision] = decolliders[v.collision](v, bounds.v);
|
|
$.extend(true, result, {
|
|
h: {location: Math.round(h.myLocation)},
|
|
v: {location: Math.round(v.myLocation)}
|
|
});
|
|
return result
|
|
};
|
|
var position = function(what, options) {
|
|
var $what = $(what);
|
|
if (!options)
|
|
return $what.offset();
|
|
var targetPosition = options.h && options.v ? options : calculatePosition($what, options);
|
|
$what.offset({
|
|
left: targetPosition.h.location,
|
|
top: targetPosition.v.location
|
|
});
|
|
return targetPosition
|
|
};
|
|
$.extend(DX, {
|
|
calculatePosition: calculatePosition,
|
|
position: position,
|
|
inverseAlign: inverseAlign
|
|
});
|
|
var calculateScrollbarWidth = function() {
|
|
var $scrollDiv = $("<div>").css({
|
|
width: 100,
|
|
height: 100,
|
|
overflow: "scroll",
|
|
position: "absolute",
|
|
top: -9999
|
|
}).appendTo($("body")),
|
|
result = $scrollDiv.get(0).offsetWidth - $scrollDiv.get(0).clientWidth;
|
|
$scrollDiv.remove();
|
|
return result
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file action.js */
|
|
(function($, DX, undefined) {
|
|
var actionExecutors = {};
|
|
var registerExecutor = function(name, executor) {
|
|
if ($.isPlainObject(name)) {
|
|
$.each(name, registerExecutor);
|
|
return
|
|
}
|
|
actionExecutors[name] = executor
|
|
};
|
|
var unregisterExecutor = function(name) {
|
|
var args = $.makeArray(arguments);
|
|
$.each(args, function() {
|
|
delete actionExecutors[this]
|
|
})
|
|
};
|
|
registerExecutor({
|
|
func: {execute: function(e) {
|
|
if ($.isFunction(e.action)) {
|
|
e.result = e.action.apply(e.context, e.args);
|
|
e.handled = true
|
|
}
|
|
}},
|
|
url: {execute: function(e) {
|
|
if (typeof e.action === "string" && e.action.charAt(0) !== "#")
|
|
document.location = e.action
|
|
}},
|
|
hash: {execute: function(e) {
|
|
if (typeof e.action === "string" && e.action.charAt(0) === "#")
|
|
document.location.hash = e.action
|
|
}}
|
|
});
|
|
var Action = DX.Class.inherit({
|
|
ctor: function(action, config) {
|
|
config = config || {};
|
|
this._action = action || $.noop;
|
|
this._context = config.context || window;
|
|
this._beforeExecute = config.beforeExecute || $.noop;
|
|
this._afterExecute = config.afterExecute || $.noop;
|
|
this._component = config.component;
|
|
this._excludeValidators = config.excludeValidators
|
|
},
|
|
execute: function() {
|
|
var e = {
|
|
action: this._action,
|
|
args: Array.prototype.slice.call(arguments),
|
|
context: this._context,
|
|
component: this._component,
|
|
canceled: false,
|
|
handled: false
|
|
};
|
|
if (!this._validateAction(e))
|
|
return;
|
|
this._beforeExecute.call(this._context, e);
|
|
if (e.canceled)
|
|
return;
|
|
var result = this._executeAction(e);
|
|
this._afterExecute.call(this._context, e);
|
|
return result
|
|
},
|
|
_validateAction: function(e) {
|
|
var excludeValidators = this._excludeValidators;
|
|
$.each(actionExecutors, function(name, executor) {
|
|
if (excludeValidators && $.inArray(name, excludeValidators) > -1)
|
|
return;
|
|
if (executor.validate)
|
|
executor.validate(e);
|
|
if (e.canceled)
|
|
return false
|
|
});
|
|
return !e.canceled
|
|
},
|
|
_executeAction: function(e) {
|
|
var result;
|
|
$.each(actionExecutors, function(index, executor) {
|
|
if (executor.execute)
|
|
executor.execute(e);
|
|
if (e.handled) {
|
|
result = e.result;
|
|
return false
|
|
}
|
|
});
|
|
return result
|
|
}
|
|
});
|
|
$.extend(DX, {
|
|
registerActionExecutor: registerExecutor,
|
|
unregisterActionExecutor: unregisterExecutor,
|
|
Action: Action
|
|
});
|
|
DX.__internals = {actionExecutors: actionExecutors}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file utils.js */
|
|
(function($, DX, undefined) {
|
|
var PI = Math.PI,
|
|
LN10 = Math.LN10;
|
|
var cos = Math.cos,
|
|
sin = Math.sin,
|
|
abs = Math.abs,
|
|
log = Math.log,
|
|
floor = Math.floor,
|
|
ceil = Math.ceil,
|
|
max = Math.max,
|
|
min = Math.min,
|
|
isNaN = window.isNaN,
|
|
Number = window.Number,
|
|
NaN = window.NaN;
|
|
var dateUnitIntervals = ['millisecond', 'second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'];
|
|
var isDefined = function(object) {
|
|
return object !== null && object !== undefined
|
|
};
|
|
var isString = function(object) {
|
|
return $.type(object) === 'string'
|
|
};
|
|
var isNumber = function(object) {
|
|
return $.isNumeric(object)
|
|
};
|
|
var isObject = function(object) {
|
|
return $.type(object) === 'object'
|
|
};
|
|
var isArray = function(object) {
|
|
return $.type(object) === 'array'
|
|
};
|
|
var isDate = function(object) {
|
|
return $.type(object) === 'date'
|
|
};
|
|
var isFunction = function(object) {
|
|
return $.type(object) === 'function'
|
|
};
|
|
var toMilliseconds = function(value) {
|
|
switch (value) {
|
|
case'millisecond':
|
|
return 1;
|
|
case'second':
|
|
return toMilliseconds('millisecond') * 1000;
|
|
case'minute':
|
|
return toMilliseconds('second') * 60;
|
|
case'hour':
|
|
return toMilliseconds('minute') * 60;
|
|
case'day':
|
|
return toMilliseconds('hour') * 24;
|
|
case'week':
|
|
return toMilliseconds('day') * 7;
|
|
case'month':
|
|
return toMilliseconds('day') * 30;
|
|
case'quarter':
|
|
return toMilliseconds('month') * 3;
|
|
case'year':
|
|
return toMilliseconds('day') * 365;
|
|
default:
|
|
return 0
|
|
}
|
|
};
|
|
var convertDateUnitToMilliseconds = function(dateUnit, count) {
|
|
return toMilliseconds(dateUnit) * count
|
|
};
|
|
var convertMillisecondsToDateUnits = function(value) {
|
|
var i,
|
|
dateUnitCount,
|
|
dateUnitInterval,
|
|
dateUnitIntervals = ['millisecond', 'second', 'minute', 'hour', 'day', 'month', 'year'],
|
|
result = {};
|
|
for (i = dateUnitIntervals.length - 1; i >= 0; i--) {
|
|
dateUnitInterval = dateUnitIntervals[i];
|
|
dateUnitCount = Math.floor(value / toMilliseconds(dateUnitInterval));
|
|
if (dateUnitCount > 0) {
|
|
result[dateUnitInterval + 's'] = dateUnitCount;
|
|
value -= convertDateUnitToMilliseconds(dateUnitInterval, dateUnitCount)
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
var convertDateTickIntervalToMilliseconds = function(tickInterval) {
|
|
var milliseconds = 0;
|
|
if (isObject(tickInterval))
|
|
$.each(tickInterval, function(key, value) {
|
|
milliseconds += convertDateUnitToMilliseconds(key.substr(0, key.length - 1), value)
|
|
});
|
|
if (isString(tickInterval))
|
|
milliseconds = convertDateUnitToMilliseconds(tickInterval, 1);
|
|
return milliseconds
|
|
};
|
|
var getDatesDifferences = function(date1, date2) {
|
|
var differences,
|
|
counter = 0;
|
|
differences = {
|
|
year: date1.getFullYear() !== date2.getFullYear(),
|
|
month: date1.getMonth() !== date2.getMonth(),
|
|
day: date1.getDate() !== date2.getDate(),
|
|
hour: date1.getHours() !== date2.getHours(),
|
|
minute: date1.getMinutes() !== date2.getMinutes(),
|
|
second: date1.getSeconds() !== date2.getSeconds()
|
|
};
|
|
$.each(differences, function(key, value) {
|
|
if (value)
|
|
counter++
|
|
});
|
|
differences.count = counter;
|
|
return differences
|
|
};
|
|
var sameMonthAndYear = function(date1, date2) {
|
|
return date1 && date2 && date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth()
|
|
};
|
|
var getFirstMonthDate = function(date) {
|
|
return new Date(date.getFullYear(), date.getMonth(), 1)
|
|
};
|
|
var getFraction = function(value) {
|
|
var valueString,
|
|
dotIndex;
|
|
if (isNumber(value)) {
|
|
valueString = value.toString();
|
|
dotIndex = valueString.indexOf('.');
|
|
if (dotIndex >= 0)
|
|
if (isExponential(value))
|
|
return valueString.substr(dotIndex + 1, valueString.indexOf('e') - dotIndex - 1);
|
|
else {
|
|
valueString = value.toFixed(20);
|
|
return valueString.substr(dotIndex + 1, valueString.length - dotIndex + 1)
|
|
}
|
|
}
|
|
return ''
|
|
};
|
|
var getSignificantDigitPosition = function(value) {
|
|
var fraction = getFraction(value),
|
|
i;
|
|
if (fraction)
|
|
for (i = 0; i < fraction.length; i++)
|
|
if (fraction.charAt(i) !== '0')
|
|
return i + 1;
|
|
return 0
|
|
};
|
|
var addSubValues = function(value1, value2, isSub) {
|
|
return value1 + (isSub ? -1 : 1) * value2
|
|
};
|
|
var isExponential = function(value) {
|
|
return isNumber(value) && value.toString().indexOf('e') !== -1
|
|
};
|
|
var addInterval = function(value, interval, isNegative) {
|
|
var result = null,
|
|
intervalObject;
|
|
if (isDate(value)) {
|
|
intervalObject = isString(interval) ? getDateIntervalByString(interval.toLowerCase()) : interval;
|
|
result = new Date(value.getTime());
|
|
if (intervalObject.years)
|
|
result.setFullYear(addSubValues(result.getFullYear(), intervalObject.years, isNegative));
|
|
if (intervalObject.quarters)
|
|
result.setMonth(addSubValues(result.getMonth(), 3 * intervalObject.quarters, isNegative));
|
|
if (intervalObject.months)
|
|
result.setMonth(addSubValues(result.getMonth(), intervalObject.months, isNegative));
|
|
if (intervalObject.weeks)
|
|
result.setDate(addSubValues(result.getDate(), 7 * intervalObject.weeks, isNegative));
|
|
if (intervalObject.days)
|
|
result.setDate(addSubValues(result.getDate(), intervalObject.days, isNegative));
|
|
if (intervalObject.hours)
|
|
result.setHours(addSubValues(result.getHours(), intervalObject.hours, isNegative));
|
|
if (intervalObject.minutes)
|
|
result.setMinutes(addSubValues(result.getMinutes(), intervalObject.minutes, isNegative));
|
|
if (intervalObject.seconds)
|
|
result.setSeconds(addSubValues(result.getSeconds(), intervalObject.seconds, isNegative));
|
|
if (intervalObject.milliseconds)
|
|
result.setMilliseconds(addSubValues(value.getMilliseconds(), intervalObject.milliseconds, isNegative))
|
|
}
|
|
else
|
|
result = addSubValues(value, interval, isNegative);
|
|
return result
|
|
};
|
|
var getDateUnitInterval = function(tickInterval) {
|
|
var maxInterval = -1,
|
|
i;
|
|
if (isString(tickInterval))
|
|
return tickInterval;
|
|
if (isObject(tickInterval)) {
|
|
$.each(tickInterval, function(key, value) {
|
|
for (i = 0; i < dateUnitIntervals.length; i++)
|
|
if (value && (key === dateUnitIntervals[i] + 's' || key === dateUnitIntervals[i]) && maxInterval < i)
|
|
maxInterval = i
|
|
});
|
|
return dateUnitIntervals[maxInterval]
|
|
}
|
|
return ''
|
|
};
|
|
var correctDateWithUnitBeginning = function(date, dateInterval) {
|
|
var dayMonth,
|
|
firstQuarterMonth,
|
|
dateUnitInterval = getDateUnitInterval(dateInterval);
|
|
switch (dateUnitInterval) {
|
|
case'second':
|
|
date.setMilliseconds(0);
|
|
break;
|
|
case'minute':
|
|
date.setSeconds(0, 0);
|
|
break;
|
|
case'hour':
|
|
date.setMinutes(0, 0, 0);
|
|
break;
|
|
case'year':
|
|
date.setMonth(0);
|
|
case'month':
|
|
date.setDate(1);
|
|
case'day':
|
|
date.setHours(0, 0, 0, 0);
|
|
break;
|
|
case'week':
|
|
dayMonth = date.getDate();
|
|
if (date.getDay() !== 0)
|
|
dayMonth += 7 - date.getDay();
|
|
date.setDate(dayMonth);
|
|
date.setHours(0, 0, 0, 0);
|
|
break;
|
|
case'quarter':
|
|
firstQuarterMonth = DX.formatHelper.getFirstQuarterMonth(date.getMonth());
|
|
if (date.getMonth() !== firstQuarterMonth)
|
|
date.setMonth(firstQuarterMonth);
|
|
date.setDate(1);
|
|
date.setHours(0, 0, 0, 0);
|
|
break
|
|
}
|
|
};
|
|
var roundValue = function(value, precision) {
|
|
if (precision > 20)
|
|
precision = 20;
|
|
if (isNumber(value))
|
|
if (isExponential(value))
|
|
return Number(value.toExponential(precision));
|
|
else
|
|
return Number(value.toFixed(precision))
|
|
};
|
|
var getPrecision = function(value) {
|
|
var stringFraction,
|
|
stringValue = value.toString(),
|
|
pointIndex = stringValue.indexOf('.'),
|
|
startIndex,
|
|
precision;
|
|
if (isExponential(value)) {
|
|
precision = getDecimalOrder(value);
|
|
if (precision < 0)
|
|
return Math.abs(precision);
|
|
else
|
|
return 0
|
|
}
|
|
if (pointIndex !== -1) {
|
|
startIndex = pointIndex + 1;
|
|
stringFraction = stringValue.substring(startIndex, startIndex + 20);
|
|
return stringFraction.length
|
|
}
|
|
return 0
|
|
};
|
|
var applyPrecisionByMinDelta = function(min, delta, value) {
|
|
var minPrecision = getPrecision(min),
|
|
deltaPrecision = getPrecision(delta);
|
|
return roundValue(value, minPrecision < deltaPrecision ? deltaPrecision : minPrecision)
|
|
};
|
|
var adjustValue = function(value) {
|
|
var fraction = getFraction(value),
|
|
nextValue,
|
|
i;
|
|
if (fraction)
|
|
for (i = 1; i <= fraction.length; i++) {
|
|
nextValue = roundValue(value, i);
|
|
if (nextValue !== 0 && fraction[i - 2] && fraction[i - 1] && fraction[i - 2] === fraction[i - 1])
|
|
return nextValue
|
|
}
|
|
return value
|
|
};
|
|
var getDateIntervalByString = function(intervalString) {
|
|
var result = {};
|
|
switch (intervalString) {
|
|
case'year':
|
|
result.years = 1;
|
|
break;
|
|
case'month':
|
|
result.months = 1;
|
|
break;
|
|
case'quarter':
|
|
result.months = 3;
|
|
break;
|
|
case'week':
|
|
result.days = 7;
|
|
break;
|
|
case'day':
|
|
result.days = 1;
|
|
break;
|
|
case'hour':
|
|
result.hours = 1;
|
|
break;
|
|
case'minute':
|
|
result.minutes = 1;
|
|
break;
|
|
case'second':
|
|
result.seconds = 1;
|
|
break;
|
|
case'millisecond':
|
|
result.milliseconds = 1;
|
|
break
|
|
}
|
|
return result
|
|
};
|
|
var normalizeAngle = function(angle) {
|
|
return (angle % 360 + 360) % 360
|
|
};
|
|
var convertAngleToRendererSpace = function(angle) {
|
|
return 90 - angle
|
|
};
|
|
var degreesToRadians = function(value) {
|
|
return PI * value / 180
|
|
};
|
|
var getCosAndSin = function(angle) {
|
|
var angleInRadians = degreesToRadians(angle);
|
|
return {
|
|
cos: cos(angleInRadians),
|
|
sin: sin(angleInRadians)
|
|
}
|
|
};
|
|
var DECIMAL_ORDER_THRESHOLD = 1E-14;
|
|
var getDecimalOrder = function(number) {
|
|
var n = abs(number),
|
|
cn;
|
|
if (!isNaN(n)) {
|
|
if (n > 0) {
|
|
n = log(n) / LN10;
|
|
cn = ceil(n);
|
|
return cn - n < DECIMAL_ORDER_THRESHOLD ? cn : floor(n)
|
|
}
|
|
return 0
|
|
}
|
|
return NaN
|
|
};
|
|
var getAppropriateFormat = function(start, end, count) {
|
|
var order = max(getDecimalOrder(start), getDecimalOrder(end)),
|
|
precision = -getDecimalOrder(abs(end - start) / count),
|
|
format;
|
|
if (!isNaN(order) && !isNaN(precision)) {
|
|
if (abs(order) <= 4) {
|
|
format = 'fixedPoint';
|
|
precision < 0 && (precision = 0);
|
|
precision > 4 && (precision = 4)
|
|
}
|
|
else {
|
|
format = 'exponential';
|
|
precision += order - 1;
|
|
precision > 3 && (precision = 3)
|
|
}
|
|
return {
|
|
format: format,
|
|
precision: precision
|
|
}
|
|
}
|
|
return null
|
|
};
|
|
var createResizeHandler = function(callback) {
|
|
var $window = $(window),
|
|
timeout;
|
|
var debug_callback = arguments[1];
|
|
var handler = function() {
|
|
var width = $window.width(),
|
|
height = $window.height();
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(function() {
|
|
$window.width() === width && $window.height() === height && callback();
|
|
debug_callback && debug_callback()
|
|
}, 100)
|
|
};
|
|
handler.stop = function() {
|
|
clearTimeout(timeout);
|
|
return this
|
|
};
|
|
return handler
|
|
};
|
|
var logger = function() {
|
|
var console = window.console;
|
|
function info(text) {
|
|
if (!console || !$.isFunction(console.info))
|
|
return;
|
|
console.info(text)
|
|
}
|
|
function warn(text) {
|
|
if (!console || !$.isFunction(console.warn))
|
|
return;
|
|
console.warn(text)
|
|
}
|
|
function error(text) {
|
|
if (!console || !$.isFunction(console.error))
|
|
return;
|
|
console.error(text)
|
|
}
|
|
return {
|
|
info: info,
|
|
warn: warn,
|
|
error: error
|
|
}
|
|
}();
|
|
var debug = function() {
|
|
function assert(condition, message) {
|
|
if (!condition)
|
|
throw new Error(message);
|
|
}
|
|
function assertParam(parameter, message) {
|
|
assert(parameter !== null && parameter !== undefined, message)
|
|
}
|
|
return {
|
|
assert: assert,
|
|
assertParam: assertParam
|
|
}
|
|
}();
|
|
var windowResizeCallbacks = function() {
|
|
var prevSize,
|
|
callbacks = $.Callbacks(),
|
|
jqWindow = $(window);
|
|
var formatSize = function() {
|
|
return [jqWindow.width(), jqWindow.height()].join()
|
|
};
|
|
var handleResize = function() {
|
|
var now = formatSize();
|
|
if (now === prevSize)
|
|
return;
|
|
prevSize = now;
|
|
callbacks.fire()
|
|
};
|
|
jqWindow.on("resize", handleResize);
|
|
prevSize = formatSize();
|
|
return callbacks
|
|
}();
|
|
var resetActiveElement = function() {
|
|
var android4nativeBrowser = DX.devices.real.platform === "android" && /^4\.0(\.\d)?/.test(DX.devices.real.version.join(".")) && navigator.userAgent.indexOf("Chrome") === -1;
|
|
function androidInputBlur() {
|
|
var $specInput = $("<input>").addClass("dx-hidden-input").appendTo("body");
|
|
setTimeout(function() {
|
|
$specInput.focus();
|
|
setTimeout(function() {
|
|
$specInput.hide();
|
|
$specInput.remove()
|
|
}, 100)
|
|
}, 100)
|
|
}
|
|
function standardInputBlur() {
|
|
var activeElement = document.activeElement;
|
|
if (activeElement && activeElement !== document.body && activeElement.blur)
|
|
activeElement.blur()
|
|
}
|
|
if (android4nativeBrowser)
|
|
androidInputBlur();
|
|
else
|
|
standardInputBlur()
|
|
};
|
|
var createMarkupFromString = function(str) {
|
|
var tempElement = $("<div />");
|
|
if (window.WinJS)
|
|
WinJS.Utilities.setInnerHTMLUnsafe(tempElement.get(0), str);
|
|
else
|
|
tempElement.append(str);
|
|
return tempElement.contents()
|
|
};
|
|
var getNextClipId = function() {
|
|
var numClipRect = 1;
|
|
return function() {
|
|
return 'DevExpress_' + numClipRect++
|
|
}
|
|
}();
|
|
var getNextPatternId = function() {
|
|
var numPattern = 1;
|
|
return function() {
|
|
return 'DevExpressPattern_' + numPattern++
|
|
}
|
|
}();
|
|
var extendFromObject = function(target, source, overrideExistingValues) {
|
|
target = target || {};
|
|
for (var prop in source)
|
|
if (source.hasOwnProperty(prop)) {
|
|
var value = source[prop];
|
|
if (!(prop in target) || overrideExistingValues)
|
|
target[prop] = value
|
|
}
|
|
return target
|
|
};
|
|
var clone = function() {
|
|
function Clone(){}
|
|
return function(obj) {
|
|
Clone.prototype = obj;
|
|
return new Clone
|
|
}
|
|
}();
|
|
var executeAsync = function(action, context) {
|
|
var deferred = $.Deferred(),
|
|
normalizedContext = context || this;
|
|
setTimeout(function() {
|
|
var result = action.call(normalizedContext);
|
|
if (result && result.done && $.isFunction(result.done))
|
|
result.done(function() {
|
|
deferred.resolveWith(normalizedContext)
|
|
});
|
|
else
|
|
deferred.resolveWith(normalizedContext)
|
|
}, 0);
|
|
return deferred.promise()
|
|
};
|
|
var getLog = function(value, base) {
|
|
return Math.log(value) / Math.log(base)
|
|
};
|
|
var raiseTo = function(power, base) {
|
|
return Math.pow(base, power)
|
|
};
|
|
var stringFormat = function() {
|
|
var s = arguments[0];
|
|
for (var i = 0; i < arguments.length - 1; i++) {
|
|
var reg = new RegExp("\\{" + i + "\\}", "gm");
|
|
s = s.replace(reg, arguments[i + 1])
|
|
}
|
|
return s
|
|
};
|
|
var getRootOffset = function(renderer) {
|
|
var node,
|
|
result = {
|
|
left: {},
|
|
top: {}
|
|
},
|
|
root = renderer.getRoot();
|
|
if (root) {
|
|
node = root.element;
|
|
if (node.getScreenCTM) {
|
|
var ctm = node.getScreenCTM();
|
|
if (ctm) {
|
|
result.left = node.createSVGPoint().matrixTransform(ctm).x + (document.body.scrollLeft || document.documentElement.scrollLeft);
|
|
result.top = node.createSVGPoint().matrixTransform(ctm).y + (document.body.scrollTop || document.documentElement.scrollTop)
|
|
}
|
|
else {
|
|
result.left = document.body.scrollLeft || document.documentElement.scrollLeft;
|
|
result.top = document.body.scrollTop || document.documentElement.scrollTop
|
|
}
|
|
}
|
|
else {
|
|
result.left = $(node).offset().left;
|
|
result.top = $(node).offset().top
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
var findBestMatches = function(targetFilter, items, mapFn) {
|
|
var bestMatches = [],
|
|
maxMatchCount = 0;
|
|
$.each(items, function(index, itemSrc) {
|
|
var matchCount = 0,
|
|
item = mapFn ? mapFn(itemSrc) : itemSrc;
|
|
$.each(item, function(paramName) {
|
|
var value = targetFilter[paramName];
|
|
if (value !== item[paramName] && value !== undefined) {
|
|
matchCount = 0;
|
|
return false
|
|
}
|
|
else
|
|
matchCount++
|
|
});
|
|
if (matchCount === maxMatchCount && matchCount > 0)
|
|
bestMatches.push(itemSrc);
|
|
else if (matchCount > maxMatchCount) {
|
|
bestMatches.length = 0;
|
|
bestMatches.push(itemSrc);
|
|
maxMatchCount = matchCount
|
|
}
|
|
});
|
|
return bestMatches
|
|
};
|
|
var preg_quote = function(str) {
|
|
return (str + "").replace(/([\+\*\?\\\.\[\^\]\$\(\)\{\}\>\<\|\=\!\:])/g, "\\$1")
|
|
};
|
|
var replaceAll = function(text, searchToken, replacementToken) {
|
|
return text.replace(new RegExp("(" + preg_quote(searchToken) + ")", "gi"), replacementToken)
|
|
};
|
|
function icontains(elem, text) {
|
|
return (elem.textContent || elem.innerText || $(elem).text() || "").toLowerCase().indexOf((text || "").toLowerCase()) > -1
|
|
}
|
|
$.expr[":"].dxicontains = $.expr.createPseudo(function(text) {
|
|
return function(elem) {
|
|
return icontains(elem, text)
|
|
}
|
|
});
|
|
function deepExtendArraySafe(target, changes) {
|
|
var prevValue,
|
|
newValue;
|
|
for (var name in changes) {
|
|
prevValue = target[name];
|
|
newValue = changes[name];
|
|
if (target === newValue)
|
|
continue;
|
|
if ($.isPlainObject(newValue))
|
|
target[name] = deepExtendArraySafe($.isPlainObject(prevValue) ? prevValue : {}, newValue);
|
|
else if (newValue !== undefined)
|
|
target[name] = newValue
|
|
}
|
|
return target
|
|
}
|
|
DX.utils = {
|
|
dateUnitIntervals: dateUnitIntervals,
|
|
isDefined: isDefined,
|
|
isString: isString,
|
|
isNumber: isNumber,
|
|
isObject: isObject,
|
|
isArray: isArray,
|
|
isDate: isDate,
|
|
isFunction: isFunction,
|
|
getLog: getLog,
|
|
raiseTo: raiseTo,
|
|
normalizeAngle: normalizeAngle,
|
|
convertAngleToRendererSpace: convertAngleToRendererSpace,
|
|
degreesToRadians: degreesToRadians,
|
|
getCosAndSin: getCosAndSin,
|
|
getDecimalOrder: getDecimalOrder,
|
|
getAppropriateFormat: getAppropriateFormat,
|
|
getFraction: getFraction,
|
|
adjustValue: adjustValue,
|
|
convertMillisecondsToDateUnits: convertMillisecondsToDateUnits,
|
|
convertDateTickIntervalToMilliseconds: convertDateTickIntervalToMilliseconds,
|
|
convertDateUnitToMilliseconds: convertDateUnitToMilliseconds,
|
|
getDateUnitInterval: getDateUnitInterval,
|
|
getDatesDifferences: getDatesDifferences,
|
|
correctDateWithUnitBeginning: correctDateWithUnitBeginning,
|
|
roundValue: roundValue,
|
|
isExponential: isExponential,
|
|
applyPrecisionByMinDelta: applyPrecisionByMinDelta,
|
|
getSignificantDigitPosition: getSignificantDigitPosition,
|
|
addInterval: addInterval,
|
|
getDateIntervalByString: getDateIntervalByString,
|
|
sameMonthAndYear: sameMonthAndYear,
|
|
getFirstMonthDate: getFirstMonthDate,
|
|
logger: logger,
|
|
debug: debug,
|
|
createResizeHandler: createResizeHandler,
|
|
windowResizeCallbacks: windowResizeCallbacks,
|
|
resetActiveElement: resetActiveElement,
|
|
createMarkupFromString: createMarkupFromString,
|
|
getNextClipId: getNextClipId,
|
|
getNextPatternId: getNextPatternId,
|
|
extendFromObject: extendFromObject,
|
|
clone: clone,
|
|
executeAsync: executeAsync,
|
|
stringFormat: stringFormat,
|
|
getRootOffset: getRootOffset,
|
|
findBestMatches: findBestMatches,
|
|
replaceAll: replaceAll,
|
|
deepExtendArraySafe: deepExtendArraySafe
|
|
};
|
|
DX.utils.getPrecision = getPrecision
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file translator.js */
|
|
(function($, DX, undefined) {
|
|
var support = DX.support,
|
|
TRANSFORM_MATRIX_REGEX = /matrix(3d)?\((.+?)\)/,
|
|
TRANSLATE_REGEX = /translate(?:3d)?\((.+?)\)/;
|
|
var locate = function($element) {
|
|
var result,
|
|
position;
|
|
if (support.transform3d) {
|
|
var translate = getTranslate($element);
|
|
result = {
|
|
left: translate.x,
|
|
top: translate.y
|
|
}
|
|
}
|
|
else {
|
|
position = $element.position();
|
|
result = {
|
|
left: position.left,
|
|
top: position.top
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
var move = function($element, position, config) {
|
|
config = config || {};
|
|
if (!support.transform3d && !config.cssTransform) {
|
|
$element.css(position);
|
|
return
|
|
}
|
|
var translate = getTranslate($element),
|
|
left = position.left,
|
|
top = position.top;
|
|
if (left !== undefined)
|
|
translate.x = left;
|
|
if (top !== undefined)
|
|
translate.y = top;
|
|
$element.css({
|
|
transform: getTranslateCss(translate),
|
|
transformOrigin: "0% 0%"
|
|
})
|
|
};
|
|
var getTranslate = function($element) {
|
|
var transformValue = $element.css("transform") || "translate3d(0, 0, 0)",
|
|
matrix = transformValue.match(TRANSFORM_MATRIX_REGEX),
|
|
is3D = matrix && matrix[1];
|
|
if (matrix) {
|
|
matrix = matrix[2].split(",");
|
|
if (is3D === "3d")
|
|
matrix = matrix.slice(12, 15);
|
|
else {
|
|
matrix.push(0);
|
|
matrix = matrix.slice(4, 7)
|
|
}
|
|
}
|
|
else
|
|
matrix = [0, 0, 0];
|
|
return {
|
|
x: parseFloat(matrix[0]),
|
|
y: parseFloat(matrix[1]),
|
|
z: parseFloat(matrix[2])
|
|
}
|
|
};
|
|
var parseTranslate = function(translateString) {
|
|
var result = translateString.match(TRANSLATE_REGEX);
|
|
if (!result || !result[1])
|
|
return;
|
|
result = result[1].split(",");
|
|
result = {
|
|
x: parseFloat(result[0]),
|
|
y: parseFloat(result[1]),
|
|
z: parseFloat(result[2])
|
|
};
|
|
return result
|
|
};
|
|
var getTranslateCss = function(translate) {
|
|
return "translate3d(" + (translate.x || 0) + "px, " + (translate.y || 0) + "px, " + (translate.z || 0) + "px) scale(1)"
|
|
};
|
|
DX.translator = {
|
|
move: move,
|
|
locate: locate,
|
|
parseTranslate: parseTranslate,
|
|
getTranslate: getTranslate,
|
|
getTranslateCss: getTranslateCss
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file animator.js */
|
|
(function($, DX, undefined) {
|
|
DX.Animator = DX.Class.inherit({
|
|
ctor: function() {
|
|
this._finished = true;
|
|
this._stopped = false
|
|
},
|
|
start: function() {
|
|
this._stopped = false;
|
|
this._finished = false;
|
|
this._stepCore()
|
|
},
|
|
stop: function() {
|
|
this._stopped = true
|
|
},
|
|
_stepCore: function() {
|
|
if (this._isStopped()) {
|
|
this._stop();
|
|
return
|
|
}
|
|
if (this._isFinished()) {
|
|
this._finished = true;
|
|
this._complete();
|
|
return
|
|
}
|
|
this._step();
|
|
DX.requestAnimationFrame.call(window, $.proxy(this._stepCore, this))
|
|
},
|
|
_step: DX.abstract,
|
|
_isFinished: $.noop,
|
|
_stop: $.noop,
|
|
_complete: $.noop,
|
|
_isStopped: function() {
|
|
return this._stopped
|
|
},
|
|
inProgress: function() {
|
|
return !(this._stopped || this._finished)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file fx.js */
|
|
(function($, DX, undefined) {
|
|
var translator = DX.translator,
|
|
support = DX.support,
|
|
transitionEndEventName = support.transitionEndEventName + ".dxFX";
|
|
var CSS_TRANSITION_EASING_REGEX = /cubic-bezier\((\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\)/,
|
|
SIMULATED_TRANSITIONEND_TIMEOUT_DATA_KEY = "dxSimulatedTransitionTimeoutKey",
|
|
ANIM_DATA_KEY = "dxAnimData",
|
|
TRANSFORM_PROP = "transform",
|
|
FRAME_ANIMATION_STEP_TIME = 1000 / 60;
|
|
var TransitionAnimationStrategy = {
|
|
animate: function($element, config) {
|
|
var deferred = $.Deferred(),
|
|
transitionEndFired = $.Deferred(),
|
|
simulatedTransitionEndFired = $.Deferred();
|
|
$element.one(transitionEndEventName, function() {
|
|
transitionEndFired.reject()
|
|
});
|
|
$element.data(SIMULATED_TRANSITIONEND_TIMEOUT_DATA_KEY, setTimeout(function() {
|
|
simulatedTransitionEndFired.reject()
|
|
}, config.duration + config.delay));
|
|
$.when(transitionEndFired, simulatedTransitionEndFired).fail($.proxy(function() {
|
|
this._cleanup($element);
|
|
deferred.resolveWith($element, [config, $element])
|
|
}, this));
|
|
translator.getTranslate($element);
|
|
$element.css({
|
|
transitionProperty: "all",
|
|
transitionDelay: config.delay + "ms",
|
|
transitionDuration: config.duration + "ms",
|
|
transitionTimingFunction: config.easing
|
|
});
|
|
setProps($element, config.to);
|
|
if (!config.duration)
|
|
$element.trigger(transitionEndEventName);
|
|
return deferred.promise()
|
|
},
|
|
_cleanup: function($element) {
|
|
$element.css("transition", "none").off(transitionEndEventName);
|
|
var simulatedEndEventTimer = $element.data(SIMULATED_TRANSITIONEND_TIMEOUT_DATA_KEY);
|
|
clearTimeout(simulatedEndEventTimer);
|
|
$element.removeData(SIMULATED_TRANSITIONEND_TIMEOUT_DATA_KEY)
|
|
},
|
|
stop: function($element, jumpToEnd) {
|
|
var config = $element.data(ANIM_DATA_KEY);
|
|
if (!config)
|
|
return;
|
|
if (jumpToEnd)
|
|
$element.trigger(transitionEndEventName);
|
|
else {
|
|
$.each(config.to, function(key) {
|
|
$element.css(key, $element.css(key))
|
|
});
|
|
this._cleanup($element)
|
|
}
|
|
}
|
|
};
|
|
var requestAnimationFrame = DX.requestAnimationFrame = function() {
|
|
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) {
|
|
window.setTimeout(callback, FRAME_ANIMATION_STEP_TIME)
|
|
}
|
|
}();
|
|
var FrameAnimationStrategy = {
|
|
animate: function($element, config) {
|
|
var deferred = $.Deferred(),
|
|
animationData = $element.data(ANIM_DATA_KEY),
|
|
self = this;
|
|
if (!animationData)
|
|
return deferred.reject().promise();
|
|
$.each(config.to, function(prop) {
|
|
if (config.from[prop] === undefined)
|
|
config.from[prop] = self._normalizeValue($element.css(prop))
|
|
});
|
|
if (config.to[TRANSFORM_PROP]) {
|
|
config.from[TRANSFORM_PROP] = self._parseTransform(config.from[TRANSFORM_PROP]);
|
|
config.to[TRANSFORM_PROP] = self._parseTransform(config.to[TRANSFORM_PROP])
|
|
}
|
|
animationData.frameAnimation = {
|
|
to: config.to,
|
|
from: config.from,
|
|
currentValue: config.from,
|
|
easing: convertTransitionTimingFuncToJQueryEasing(config.easing),
|
|
duration: config.duration,
|
|
startTime: (new Date).valueOf(),
|
|
finish: function() {
|
|
this.currentValue = this.to;
|
|
this.draw();
|
|
deferred.resolve()
|
|
},
|
|
draw: function() {
|
|
var currentValue = $.extend({}, this.currentValue);
|
|
if (currentValue[TRANSFORM_PROP])
|
|
currentValue[TRANSFORM_PROP] = $.map(currentValue[TRANSFORM_PROP], function(value, prop) {
|
|
if (prop === "translate")
|
|
return translator.getTranslateCss(value);
|
|
else if (prop === "scale")
|
|
return "scale(" + value + ")";
|
|
else if (prop.substr(0, prop.length - 1) === "rotate")
|
|
return prop + "(" + value + "deg)"
|
|
}).join(" ");
|
|
$element.css(currentValue)
|
|
}
|
|
};
|
|
if (config.delay) {
|
|
animationData.frameAnimation.startTime += config.delay;
|
|
animationData.frameAnimation.delayTimeout = setTimeout(function() {
|
|
self._animationStep($element)
|
|
}, config.delay)
|
|
}
|
|
else
|
|
self._animationStep($element);
|
|
return deferred.promise()
|
|
},
|
|
_parseTransform: function(transformString) {
|
|
var result = {};
|
|
$.each(transformString.match(/(\w|\d)+\([^\)]*\)\s*/g), function(i, part) {
|
|
var translateData = translator.parseTranslate(part),
|
|
scaleData = part.match(/scale\((.+?)\)/),
|
|
rotateData = part.match(/(rotate.)\((.+)deg\)/);
|
|
if (translateData)
|
|
result.translate = translateData;
|
|
if (scaleData && scaleData[1])
|
|
result.scale = parseFloat(scaleData[1]);
|
|
if (rotateData && rotateData[1])
|
|
result[rotateData[1]] = parseFloat(rotateData[2])
|
|
});
|
|
return result
|
|
},
|
|
stop: function($element, jumpToEnd) {
|
|
var animationData = $element.data(ANIM_DATA_KEY),
|
|
frameAnimation = animationData && animationData.frameAnimation;
|
|
if (!frameAnimation)
|
|
return;
|
|
clearTimeout(frameAnimation.delayTimeout);
|
|
if (jumpToEnd)
|
|
frameAnimation.finish()
|
|
},
|
|
_animationStep: function($element) {
|
|
var animationData = $element.data(ANIM_DATA_KEY),
|
|
frameAnimation = animationData && animationData.frameAnimation;
|
|
if (!frameAnimation)
|
|
return;
|
|
var now = (new Date).valueOf();
|
|
if (now >= frameAnimation.startTime + frameAnimation.duration) {
|
|
frameAnimation.finish();
|
|
return
|
|
}
|
|
frameAnimation.currentValue = this._calcStepValue(frameAnimation, now - frameAnimation.startTime);
|
|
frameAnimation.draw();
|
|
requestAnimationFrame($.proxy(function() {
|
|
this._animationStep($element)
|
|
}, this))
|
|
},
|
|
_calcStepValue: function(frameAnimation, currentDuration) {
|
|
var calcValueRecursively = function(from, to) {
|
|
var result = $.isArray(to) ? [] : {};
|
|
var calcEasedValue = function(propName) {
|
|
var x = currentDuration / frameAnimation.duration,
|
|
t = currentDuration,
|
|
b = 1 * from[propName],
|
|
c = to[propName] - from[propName],
|
|
d = frameAnimation.duration;
|
|
return $.easing[frameAnimation.easing](x, t, b, c, d)
|
|
};
|
|
$.each(to, function(propName, endPropValue) {
|
|
if (typeof endPropValue === "string" && parseFloat(endPropValue, 10) === false)
|
|
return true;
|
|
result[propName] = typeof endPropValue === "object" ? calcValueRecursively(from[propName], endPropValue) : calcEasedValue(propName)
|
|
});
|
|
return result
|
|
};
|
|
return calcValueRecursively(frameAnimation.from, frameAnimation.to)
|
|
},
|
|
_normalizeValue: function(value) {
|
|
var numericValue = parseFloat(value, 10);
|
|
if (numericValue === false)
|
|
return value;
|
|
return numericValue
|
|
}
|
|
};
|
|
var animationStrategies = {
|
|
transition: support.transition ? TransitionAnimationStrategy : FrameAnimationStrategy,
|
|
frame: FrameAnimationStrategy
|
|
};
|
|
var getAnimationStrategy = function(config) {
|
|
return animationStrategies[config && config.strategy || "transition"]
|
|
};
|
|
var TransitionTimingFuncMap = {
|
|
linear: "cubic-bezier(0, 0, 1, 1)",
|
|
ease: "cubic-bezier(0.25, 0.1, 0.25, 1)",
|
|
"ease-in": "cubic-bezier(0.42, 0, 1, 1)",
|
|
"ease-out": "cubic-bezier(0, 0, 0.58, 1)",
|
|
"ease-in-out": "cubic-bezier(0.42, 0, 0.58, 1)"
|
|
};
|
|
var convertTransitionTimingFuncToJQueryEasing = function(cssTransitionEasing) {
|
|
cssTransitionEasing = TransitionTimingFuncMap[cssTransitionEasing] || cssTransitionEasing;
|
|
var bezCoeffs = cssTransitionEasing.match(CSS_TRANSITION_EASING_REGEX);
|
|
if (!bezCoeffs)
|
|
return "linear";
|
|
bezCoeffs = bezCoeffs.slice(1, 5);
|
|
$.each(bezCoeffs, function(index, value) {
|
|
bezCoeffs[index] = parseFloat(value)
|
|
});
|
|
var easingName = "cubicbezier_" + bezCoeffs.join("_").replace(/\./g, "p");
|
|
if (!$.isFunction($.easing[easingName])) {
|
|
var polynomBezier = function(x1, y1, x2, y2) {
|
|
var Cx = 3 * x1,
|
|
Bx = 3 * (x2 - x1) - Cx,
|
|
Ax = 1 - Cx - Bx,
|
|
Cy = 3 * y1,
|
|
By = 3 * (y2 - y1) - Cy,
|
|
Ay = 1 - Cy - By;
|
|
var bezierX = function(t) {
|
|
return t * (Cx + t * (Bx + t * Ax))
|
|
};
|
|
var bezierY = function(t) {
|
|
return t * (Cy + t * (By + t * Ay))
|
|
};
|
|
var findXfor = function(t) {
|
|
var x = t,
|
|
i = 0,
|
|
z;
|
|
while (i < 14) {
|
|
z = bezierX(x) - t;
|
|
if (Math.abs(z) < 1e-3)
|
|
break;
|
|
x = x - z / derivativeX(x);
|
|
i++
|
|
}
|
|
return x
|
|
};
|
|
var derivativeX = function(t) {
|
|
return Cx + t * (2 * Bx + t * 3 * Ax)
|
|
};
|
|
return function(t) {
|
|
return bezierY(findXfor(t))
|
|
}
|
|
};
|
|
$.easing[easingName] = function(x, t, b, c, d) {
|
|
return c * polynomBezier(bezCoeffs[0], bezCoeffs[1], bezCoeffs[2], bezCoeffs[3])(t / d) + b
|
|
}
|
|
}
|
|
return easingName
|
|
};
|
|
var baseConfigValidator = function(config, animationType) {
|
|
$.each(["from", "to"], function() {
|
|
if (!$.isPlainObject(config[this]))
|
|
throw Error("Animation with the '" + animationType + "' type requires '" + this + "' configuration as an plain object.");
|
|
})
|
|
};
|
|
var CustomAnimationConfigurator = {setup: function($element, config){}};
|
|
var SlideAnimationConfigurator = {
|
|
validateConfig: function(config) {
|
|
baseConfigValidator(config, "slide")
|
|
},
|
|
setup: function($element, config) {
|
|
if (!support.transform3d)
|
|
return;
|
|
this._resetLocation($element);
|
|
this._locationToTranslate($element, config.from);
|
|
this._locationToTranslate($element, config.to)
|
|
},
|
|
_resetLocation: function($element) {
|
|
$element.css({
|
|
top: 0,
|
|
left: 0
|
|
})
|
|
},
|
|
_locationToTranslate: function($element, config) {
|
|
var translate = translator.getTranslate($element),
|
|
left = config.left,
|
|
top = config.top;
|
|
if (left !== undefined) {
|
|
translate.x = left;
|
|
delete config.left
|
|
}
|
|
if (top !== undefined) {
|
|
translate.y = top;
|
|
delete config.top
|
|
}
|
|
config[TRANSFORM_PROP] = translator.getTranslateCss(translate)
|
|
}
|
|
};
|
|
var FadeAnimationConfigurator = {setup: function($element, config) {
|
|
var from = config.from,
|
|
fromOpacity = $.isPlainObject(from) ? $element.css("opacity") : String(from),
|
|
toOpacity = String(config.to);
|
|
config.from = {opacity: fromOpacity};
|
|
config.to = {opacity: toOpacity}
|
|
}};
|
|
var PopAnimationConfigurator = {
|
|
validateConfig: function(config) {
|
|
baseConfigValidator(config, "pop")
|
|
},
|
|
setup: function($element, config) {
|
|
var from = config.from,
|
|
to = config.to,
|
|
fromOpacity = "opacity" in from ? from.opacity : $element.css("opacity"),
|
|
toOpacity = "opacity" in to ? to.opacity : 1,
|
|
fromScale = "scale" in from ? from.scale : 0,
|
|
toScale = "scale" in to ? to.scale : 1;
|
|
config.from = {opacity: fromOpacity};
|
|
config.from[TRANSFORM_PROP] = this._getCssTransform(fromScale);
|
|
config.to = {opacity: toOpacity};
|
|
config.to[TRANSFORM_PROP] = this._getCssTransform(toScale)
|
|
},
|
|
_getCssTransform: function(scale) {
|
|
return "scale(" + scale + ")"
|
|
}
|
|
};
|
|
var animationConfigurators = {
|
|
custom: CustomAnimationConfigurator,
|
|
slide: SlideAnimationConfigurator,
|
|
fade: FadeAnimationConfigurator,
|
|
pop: PopAnimationConfigurator
|
|
};
|
|
var getAnimationConfigurator = function(type) {
|
|
var result = animationConfigurators[type];
|
|
if (!result)
|
|
throw Error("Unknown animation type \"" + type + "\"");
|
|
return result
|
|
};
|
|
var defaultConfig = {
|
|
type: "custom",
|
|
from: {},
|
|
to: {},
|
|
duration: 400,
|
|
complete: $.noop,
|
|
easing: "ease",
|
|
delay: 0
|
|
};
|
|
var animate = function(element, config) {
|
|
config = $.extend(true, {}, defaultConfig, config);
|
|
var $element = $(element),
|
|
configurator = getAnimationConfigurator(config.type);
|
|
if (!$element.length)
|
|
return $.Deferred().resolve().promise();
|
|
setupPosition($element, config.from);
|
|
setupPosition($element, config.to);
|
|
if ($.isFunction(configurator.validateConfig))
|
|
configurator.validateConfig(config);
|
|
configurator.setup($element, config);
|
|
stop($element);
|
|
setProps($element, config.from);
|
|
return executeAnimation($element, config).done(config.complete)
|
|
};
|
|
var setupPosition = function($element, config) {
|
|
if (!config.position)
|
|
return;
|
|
var position = DX.calculatePosition($element, config.position);
|
|
$.extend(config, {
|
|
left: position.h.location,
|
|
top: position.v.location
|
|
});
|
|
delete config.position
|
|
};
|
|
var setProps = function($element, props) {
|
|
$.each(props, function(key, value) {
|
|
$element.css(key, value)
|
|
})
|
|
};
|
|
var executeAnimation = function($element, config) {
|
|
var deferred = $.Deferred();
|
|
$element.data(ANIM_DATA_KEY, config);
|
|
if (DX.fx.off)
|
|
config.duration = 0;
|
|
getAnimationStrategy(config).animate($element, config).done(function() {
|
|
$element.removeData(ANIM_DATA_KEY);
|
|
deferred.resolveWith(this, [$element, config])
|
|
});
|
|
return deferred.promise()
|
|
};
|
|
var animating = function($element) {
|
|
return !!$element.data(ANIM_DATA_KEY)
|
|
};
|
|
var stop = function(element, jumpToEnd) {
|
|
var $element = $(element);
|
|
getAnimationStrategy($element.data(ANIM_DATA_KEY)).stop($element, jumpToEnd);
|
|
$element.removeData(ANIM_DATA_KEY)
|
|
};
|
|
DX.fx = {
|
|
off: false,
|
|
animationTypes: animationConfigurators,
|
|
animate: animate,
|
|
animating: animating,
|
|
stop: stop
|
|
};
|
|
DX.fx.__internals = {convertTransitionTimingFuncToJQueryEasing: convertTransitionTimingFuncToJQueryEasing}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file endpointSelector.js */
|
|
(function($, DX, undefined) {
|
|
var location = window.location,
|
|
DXPROXY_HOST = "dxproxy.devexpress.com:8000",
|
|
WIN_JS = location.protocol === "ms-appx:",
|
|
IS_DXPROXY = location.host === DXPROXY_HOST,
|
|
IS_LOCAL = isLocalHostName(location.hostname);
|
|
function isLocalHostName(url) {
|
|
return /^(localhost$|127\.)/i.test(url)
|
|
}
|
|
var extractProxyAppId = function() {
|
|
return location.pathname.split("/")[1]
|
|
};
|
|
var formatProxyUrl = function(localUrl) {
|
|
var urlData = DX.parseUrl(localUrl);
|
|
if (!isLocalHostName(urlData.hostname))
|
|
return localUrl;
|
|
return "http://" + DXPROXY_HOST + "/" + extractProxyAppId() + "_" + urlData.port + urlData.pathname + urlData.search
|
|
};
|
|
var EndpointSelector = DX.EndpointSelector = function(config) {
|
|
this.config = config
|
|
};
|
|
EndpointSelector.prototype = {urlFor: function(key) {
|
|
var bag = this.config[key];
|
|
if (!bag)
|
|
throw Error("Unknown endpoint key");
|
|
if (IS_DXPROXY)
|
|
return formatProxyUrl(bag.local);
|
|
if (bag.production)
|
|
if (WIN_JS && !Debug.debuggerEnabled || !WIN_JS && !IS_LOCAL)
|
|
return bag.production;
|
|
return bag.local
|
|
}}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file formatHelper.js */
|
|
(function($, DX, undefined) {
|
|
var utils = DX.utils;
|
|
DX.NumericFormat = {
|
|
currency: 'C',
|
|
fixedpoint: 'N',
|
|
exponential: '',
|
|
percent: 'P',
|
|
decimal: 'D'
|
|
};
|
|
DX.LargeNumberFormatPostfixes = {
|
|
1: 'K',
|
|
2: 'M',
|
|
3: 'B',
|
|
4: 'T'
|
|
};
|
|
var MAX_LARGE_NUMBER_POWER = 4,
|
|
DECIMAL_BASE = 10;
|
|
DX.LargeNumberFormatPowers = {
|
|
largenumber: 'auto',
|
|
thousands: 1,
|
|
millions: 2,
|
|
billions: 3,
|
|
trillions: 4
|
|
};
|
|
DX.DateTimeFormat = {
|
|
longdate: 'D',
|
|
longtime: 'T',
|
|
monthandday: 'M',
|
|
monthandyear: 'Y',
|
|
quarterandyear: 'qq',
|
|
shortdate: 'd',
|
|
shorttime: 't',
|
|
millisecond: 'fff',
|
|
second: 'T',
|
|
minute: 't',
|
|
hour: 't',
|
|
day: 'dd',
|
|
week: 'dd',
|
|
month: 'MMMM',
|
|
quarter: 'qq',
|
|
year: 'yyyy',
|
|
longdatelongtime: 'D',
|
|
shortdateshorttime: 'd'
|
|
};
|
|
DX.formatHelper = {
|
|
romanDigits: ['I', 'II', 'III', 'IV'],
|
|
_addFormatSeparator: function(format1, format2) {
|
|
var separator = ' ';
|
|
if (format2)
|
|
return format1 + separator + format2;
|
|
return format1
|
|
},
|
|
_getDateTimeFormatPattern: function(dateTimeFormat) {
|
|
return Globalize.findClosestCulture().calendar.patterns[DX.DateTimeFormat[dateTimeFormat.toLowerCase()]]
|
|
},
|
|
_isDateFormatContains: function(format) {
|
|
var result = false;
|
|
$.each(DX.DateTimeFormat, function(key, value) {
|
|
result = key === format.toLowerCase();
|
|
return !result
|
|
});
|
|
return result
|
|
},
|
|
getQuarter: function(month) {
|
|
return Math.floor(month / 3)
|
|
},
|
|
getQuarterString: function(date, format) {
|
|
var resultQuarter = '',
|
|
quarter = this.getQuarter(date.getMonth());
|
|
switch (format) {
|
|
case'q':
|
|
resultQuarter = this.romanDigits[quarter];
|
|
break;
|
|
case'qq':
|
|
resultQuarter = 'Q' + this.romanDigits[quarter];
|
|
break;
|
|
case'Q':
|
|
resultQuarter = (quarter + 1).toString();
|
|
break;
|
|
case'QQ':
|
|
resultQuarter = 'Q' + (quarter + 1).toString();
|
|
break
|
|
}
|
|
return resultQuarter
|
|
},
|
|
getFirstQuarterMonth: function(month) {
|
|
return this.getQuarter(month) * 3
|
|
},
|
|
_formatCustomString: function(value, format) {
|
|
var regExp = /qq|q|QQ|Q/g,
|
|
quarterFormat,
|
|
result = '',
|
|
index = 0;
|
|
while (index < format.length) {
|
|
quarterFormat = regExp.exec(format);
|
|
if (!quarterFormat || quarterFormat.index > index)
|
|
result += Globalize.format(value, format.substring(index, quarterFormat ? quarterFormat.index : format.length));
|
|
if (quarterFormat) {
|
|
result += this.getQuarterString(value, quarterFormat[0]);
|
|
index = quarterFormat.index + quarterFormat[0].length
|
|
}
|
|
else
|
|
index = format.length
|
|
}
|
|
return result
|
|
},
|
|
_parseNumberFormatString: function(format) {
|
|
var formatList,
|
|
formatObject = {};
|
|
if (!format || typeof format !== 'string')
|
|
return;
|
|
formatList = format.toLowerCase().split(' ');
|
|
$.each(formatList, function(index, value) {
|
|
if (value in DX.NumericFormat)
|
|
formatObject.formatType = value;
|
|
else if (value in DX.LargeNumberFormatPowers)
|
|
formatObject.power = DX.LargeNumberFormatPowers[value]
|
|
});
|
|
if (formatObject.power && !formatObject.formatType)
|
|
formatObject.formatType = 'fixedpoint';
|
|
if (formatObject.formatType)
|
|
return formatObject
|
|
},
|
|
_calculateNumberPower: function(value, base, minPower, maxPower) {
|
|
var number = Math.abs(value);
|
|
var power = 0;
|
|
if (number > 1)
|
|
while (number && number >= base && (maxPower === undefined || power < maxPower)) {
|
|
power++;
|
|
number = number / base
|
|
}
|
|
else if (number > 0 && number < 1)
|
|
while (number < 1 && (minPower === undefined || power > minPower)) {
|
|
power--;
|
|
number = number * base
|
|
}
|
|
return power
|
|
},
|
|
_getNumberByPower: function(number, power, base) {
|
|
var result = number;
|
|
while (power > 0) {
|
|
result = result / base;
|
|
power--
|
|
}
|
|
while (power < 0) {
|
|
result = result * base;
|
|
power++
|
|
}
|
|
return result
|
|
},
|
|
_formatNumber: function(value, formatObject, precision) {
|
|
var powerPostfix;
|
|
if (formatObject.power === 'auto')
|
|
formatObject.power = this._calculateNumberPower(value, 1000, 0, MAX_LARGE_NUMBER_POWER);
|
|
if (formatObject.power)
|
|
value = this._getNumberByPower(value, formatObject.power, 1000);
|
|
powerPostfix = DX.LargeNumberFormatPostfixes[formatObject.power] || '';
|
|
return this._formatNumberCore(value, formatObject.formatType, precision) + powerPostfix
|
|
},
|
|
_formatNumberExponential: function(value, precision) {
|
|
var power = this._calculateNumberPower(value, DECIMAL_BASE),
|
|
number = this._getNumberByPower(value, power, DECIMAL_BASE),
|
|
powString;
|
|
precision = precision === undefined ? 1 : precision;
|
|
if (number.toFixed(precision || 0) >= DECIMAL_BASE) {
|
|
power++;
|
|
number = number / DECIMAL_BASE
|
|
}
|
|
powString = (power >= 0 ? '+' : '') + power.toString();
|
|
return this._formatNumberCore(number, 'fixedpoint', precision) + 'E' + powString
|
|
},
|
|
_formatNumberCore: function(value, format, precision) {
|
|
if (format === 'exponential')
|
|
return this._formatNumberExponential(value, precision);
|
|
else
|
|
return Globalize.format(value, DX.NumericFormat[format] + (utils.isNumber(precision) ? precision : 0))
|
|
},
|
|
_formatDate: function(date, format, formatString) {
|
|
var resultFormat = DX.DateTimeFormat[format.toLowerCase()];
|
|
format = format.toLowerCase();
|
|
if (format === 'quarterandyear')
|
|
resultFormat = this.getQuarterString(date, resultFormat) + ' yyyy';
|
|
if (format === 'quarter')
|
|
return this.getQuarterString(date, resultFormat);
|
|
if (format === 'longdatelongtime')
|
|
return this._formatDate(date, 'longdate') + ' ' + this._formatDate(date, 'longtime');
|
|
if (format === 'shortdateshorttime')
|
|
return this._formatDate(date, 'shortDate') + ' ' + this._formatDate(date, 'shortTime');
|
|
return Globalize.format(date, resultFormat)
|
|
},
|
|
format: function(value, format, precision) {
|
|
if (format && format.format)
|
|
if (format.dateType)
|
|
return this._formatDateEx(value, format);
|
|
else if (utils.isNumber(value) && isFinite(value))
|
|
return this._formatNumberEx(value, format);
|
|
return this._format(value, format, precision)
|
|
},
|
|
_format: function(value, format, precision) {
|
|
var numberFormatObject;
|
|
if (!utils.isString(format) || format === '' || !utils.isNumber(value) && !utils.isDate(value))
|
|
return utils.isDefined(value) ? value.toString() : '';
|
|
numberFormatObject = this._parseNumberFormatString(format);
|
|
if (utils.isNumber(value) && numberFormatObject)
|
|
return this._formatNumber(value, numberFormatObject, precision);
|
|
if (utils.isDate(value) && this._isDateFormatContains(format))
|
|
return this._formatDate(value, format);
|
|
if (!numberFormatObject && !this._isDateFormatContains(format))
|
|
return this._formatCustomString(value, format)
|
|
},
|
|
_formatNumberEx: function(value, formatInfo) {
|
|
var self = this,
|
|
numericFormatType = DX.NumericFormat[formatInfo.format.toLowerCase()],
|
|
numberFormat = Globalize.culture().numberFormat,
|
|
currencyFormat = formatInfo.currencyCulture && Globalize.cultures[formatInfo.currencyCulture] ? Globalize.cultures[formatInfo.currencyCulture].numberFormat.currency : numberFormat.currency,
|
|
percentFormat = numberFormat.percent,
|
|
formatSettings = self._getUnitFormatSettings(value, formatInfo),
|
|
unit = formatSettings.unit,
|
|
precision = formatSettings.precision,
|
|
showTrailingZeros = formatSettings.showTrailingZeros,
|
|
includeGroupSeparator = formatSettings.includeGroupSeparator,
|
|
groupSymbol = numberFormat[","],
|
|
floatingSymbol = numberFormat["."],
|
|
number,
|
|
isNegative,
|
|
pattern,
|
|
currentFormat,
|
|
regexParts = /n|\$|-|%/g,
|
|
result = "";
|
|
value = self._applyUnitToValue(value, unit);
|
|
number = Math.abs(value);
|
|
isNegative = value < 0;
|
|
switch (numericFormatType) {
|
|
case"D":
|
|
pattern = "n";
|
|
number = Math[isNegative ? "ceil" : "floor"](number);
|
|
if (precision > 0) {
|
|
var str = "" + number;
|
|
for (var i = str.length; i < precision; i += 1)
|
|
str = "0" + str;
|
|
number = str
|
|
}
|
|
if (isNegative)
|
|
number = "-" + number;
|
|
break;
|
|
case"N":
|
|
currentFormat = numberFormat;
|
|
case"C":
|
|
currentFormat = currentFormat || currencyFormat;
|
|
case"P":
|
|
currentFormat = currentFormat || percentFormat;
|
|
pattern = isNegative ? currentFormat.pattern[0] : currentFormat.pattern[1] || "n";
|
|
number = Globalize.format(number * (numericFormatType === "P" ? 100 : 1), "N" + precision);
|
|
if (!showTrailingZeros)
|
|
number = self._excludeTrailingZeros(number, floatingSymbol);
|
|
if (!includeGroupSeparator)
|
|
number = number.replace(new RegExp('\\' + groupSymbol, 'g'), '');
|
|
break;
|
|
default:
|
|
throw"Illegal numeric format: '" + numericFormatType + "'";
|
|
}
|
|
for (; ; ) {
|
|
var lastIndex = regexParts.lastIndex,
|
|
matches = regexParts.exec(pattern);
|
|
result += pattern.slice(lastIndex, matches ? matches.index : pattern.length);
|
|
if (matches)
|
|
switch (matches[0]) {
|
|
case"-":
|
|
if (/[1-9]/.test(number))
|
|
result += numberFormat["-"];
|
|
break;
|
|
case"$":
|
|
result += currencyFormat.symbol;
|
|
break;
|
|
case"%":
|
|
result += percentFormat.symbol;
|
|
break;
|
|
case"n":
|
|
result += number + unit;
|
|
break
|
|
}
|
|
else
|
|
break
|
|
}
|
|
return (formatInfo.plus && value > 0 ? "+" : '') + result
|
|
},
|
|
_excludeTrailingZeros: function(strValue, floatingSymbol) {
|
|
var floatingIndex = strValue.indexOf(floatingSymbol),
|
|
stopIndex,
|
|
i;
|
|
if (floatingIndex < 0)
|
|
return strValue;
|
|
stopIndex = strValue.length;
|
|
for (i = stopIndex - 1; i >= floatingIndex && (strValue[i] === '0' || i === floatingIndex); i--)
|
|
stopIndex--;
|
|
return strValue.substring(0, stopIndex)
|
|
},
|
|
_getUnitFormatSettings: function(value, formatInfo) {
|
|
var unit = formatInfo.unit || '',
|
|
precision = formatInfo.precision || 0,
|
|
includeGroupSeparator = formatInfo.includeGroupSeparator || false,
|
|
showTrailingZeros = formatInfo.showTrailingZeros === undefined ? true : formatInfo.showTrailingZeros,
|
|
significantDigits = formatInfo.significantDigits || 1,
|
|
absValue;
|
|
if (unit.toLowerCase() === 'auto') {
|
|
showTrailingZeros = false;
|
|
absValue = Math.abs(value);
|
|
if (significantDigits < 1)
|
|
significantDigits = 1;
|
|
if (absValue >= 1000000000) {
|
|
unit = 'B';
|
|
absValue /= 1000000000
|
|
}
|
|
else if (absValue >= 1000000) {
|
|
unit = 'M';
|
|
absValue /= 1000000
|
|
}
|
|
else if (absValue >= 1000) {
|
|
unit = 'K';
|
|
absValue /= 1000
|
|
}
|
|
else
|
|
unit = '';
|
|
if (absValue == 0)
|
|
precision = 0;
|
|
else if (absValue < 1) {
|
|
precision = significantDigits;
|
|
var smallValue = Math.pow(10, -significantDigits);
|
|
while (absValue < smallValue) {
|
|
smallValue /= 10;
|
|
precision++
|
|
}
|
|
}
|
|
else if (absValue >= 100)
|
|
precision = significantDigits - 3;
|
|
else if (absValue >= 10)
|
|
precision = significantDigits - 2;
|
|
else
|
|
precision = significantDigits - 1
|
|
}
|
|
if (precision < 0)
|
|
precision = 0;
|
|
return {
|
|
unit: unit,
|
|
precision: precision,
|
|
showTrailingZeros: showTrailingZeros,
|
|
includeGroupSeparator: includeGroupSeparator
|
|
}
|
|
},
|
|
_applyUnitToValue: function(value, unit) {
|
|
if (unit == 'B')
|
|
return value.toFixed(1) / 1000000000;
|
|
if (unit == 'M')
|
|
return value / 1000000;
|
|
if (unit == 'K')
|
|
return value / 1000;
|
|
return value
|
|
},
|
|
_formatDateEx: function(value, formatInfo) {
|
|
var self = this,
|
|
quarterPrefix = 'Q',
|
|
format = formatInfo.format,
|
|
dateType = formatInfo.dateType,
|
|
calendar = Globalize.culture().calendars.standard,
|
|
time = undefined,
|
|
index,
|
|
dateStr;
|
|
format = format.toLowerCase();
|
|
if (dateType !== 'num' || format === 'dayofweek')
|
|
switch (format) {
|
|
case'monthyear':
|
|
return self._formatDate(value, 'monthandyear');
|
|
case'quarteryear':
|
|
return self.getQuarterString(value, 'QQ') + ' ' + value.getFullYear();
|
|
case'daymonthyear':
|
|
return self._formatDate(value, dateType + 'Date');
|
|
case'datehour':
|
|
time = new Date(value.getTime());
|
|
time.setMinutes(0);
|
|
dateStr = dateType === 'timeOnly' ? '' : self._formatDate(value, dateType + 'Date');
|
|
return dateType === 'timeOnly' ? self._formatDate(time, 'shorttime') : dateStr + ' ' + self._formatDate(time, 'shorttime');
|
|
case'datehourminute':
|
|
dateStr = dateType === 'timeOnly' ? '' : self._formatDate(value, dateType + 'Date');
|
|
return dateType === 'timeOnly' ? self._formatDate(value, 'shorttime') : dateStr + ' ' + self._formatDate(value, 'shorttime');
|
|
case'datehourminutesecond':
|
|
dateStr = dateType === 'timeOnly' ? '' : self._formatDate(value, dateType + 'Date');
|
|
return dateType === 'timeOnly' ? self._formatDate(value, 'longtime') : dateStr + ' ' + self._formatDate(value, 'longtime');
|
|
case'year':
|
|
dateStr = value.toString();
|
|
return dateType === 'abbr' ? dateStr.slice(2, 4) : dateStr;
|
|
case'quarter':
|
|
return quarterPrefix + value.toString();
|
|
case'month':
|
|
index = value - 1;
|
|
return dateType === 'abbr' ? calendar.months.namesAbbr[index] : calendar.months.names[index];
|
|
case'hour':
|
|
if (dateType === 'long') {
|
|
time = new Date;
|
|
time.setHours(value);
|
|
time.setMinutes(0);
|
|
return self._formatDate(time, 'shorttime')
|
|
}
|
|
else
|
|
return value.toString();
|
|
case'dayofweek':
|
|
index = $.inArray(value, ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']);
|
|
if (dateType !== 'num')
|
|
return dateType === 'abbr' ? calendar.days.namesAbbr[index] : calendar.days.names[index];
|
|
else
|
|
return ((index - calendar.firstDay + 1 + 7) % 8).toString();
|
|
default:
|
|
return value.toString()
|
|
}
|
|
else
|
|
return value.toString()
|
|
},
|
|
getTimeFormat: function(showSecond) {
|
|
if (showSecond)
|
|
return this._getDateTimeFormatPattern('longtime');
|
|
return this._getDateTimeFormatPattern('shorttime')
|
|
},
|
|
getDateFormatByDifferences: function(dateDifferences) {
|
|
var resultFormat = '';
|
|
if (dateDifferences.millisecond)
|
|
resultFormat = DX.DateTimeFormat.millisecond;
|
|
if (dateDifferences.hour || dateDifferences.minute || dateDifferences.second)
|
|
resultFormat = this._addFormatSeparator(this.getTimeFormat(dateDifferences.second), resultFormat);
|
|
if (dateDifferences.year && dateDifferences.month && dateDifferences.day)
|
|
return this._addFormatSeparator(this._getDateTimeFormatPattern('shortdate'), resultFormat);
|
|
if (dateDifferences.year && dateDifferences.month)
|
|
return DX.DateTimeFormat['monthandyear'];
|
|
if (dateDifferences.year)
|
|
return DX.DateTimeFormat['year'];
|
|
if (dateDifferences.month && dateDifferences.day)
|
|
return this._addFormatSeparator(this._getDateTimeFormatPattern('monthandday'), resultFormat);
|
|
if (dateDifferences.month)
|
|
return DX.DateTimeFormat['month'];
|
|
if (dateDifferences.day)
|
|
return this._addFormatSeparator('dddd, dd', resultFormat);
|
|
return resultFormat
|
|
},
|
|
getDateFormatByTicks: function(ticks) {
|
|
var resultFormat,
|
|
maxDif,
|
|
currentDif,
|
|
i,
|
|
dateUnitInterval;
|
|
if (ticks.length > 1) {
|
|
maxDif = utils.getDatesDifferences(ticks[0], ticks[1]);
|
|
for (i = 1; i < ticks.length - 1; i++) {
|
|
currentDif = utils.getDatesDifferences(ticks[i], ticks[i + 1]);
|
|
if (maxDif.count < currentDif.count)
|
|
maxDif = currentDif
|
|
}
|
|
}
|
|
else
|
|
maxDif = {
|
|
year: true,
|
|
month: true,
|
|
day: true,
|
|
hour: ticks[0].getHours() > 0,
|
|
minute: ticks[0].getMinutes() > 0,
|
|
second: ticks[0].getSeconds() > 0
|
|
};
|
|
resultFormat = this.getDateFormatByDifferences(maxDif);
|
|
return resultFormat
|
|
},
|
|
getDateFormatByTickInterval: function(startValue, endValue, tickInterval) {
|
|
var resultFormat,
|
|
dateDifferences,
|
|
dateUnitInterval,
|
|
dateDifferencesConverter = {
|
|
quarter: 'month',
|
|
week: 'day'
|
|
},
|
|
correctDateDifferences = function(dateDifferences, tickInterval, value) {
|
|
switch (tickInterval) {
|
|
case'year':
|
|
dateDifferences.month = value;
|
|
case'quarter':
|
|
case'month':
|
|
dateDifferences.day = value;
|
|
case'week':
|
|
case'day':
|
|
dateDifferences.hour = value;
|
|
case'hour':
|
|
dateDifferences.minute = value;
|
|
case'minute':
|
|
dateDifferences.second = value;
|
|
case'second':
|
|
dateDifferences.millisecond = value
|
|
}
|
|
},
|
|
correctDifferencesByMaxDate = function(differences, minDate, maxDate) {
|
|
if (!maxDate.getMilliseconds() && maxDate.getSeconds()) {
|
|
if (maxDate.getSeconds() - minDate.getSeconds() === 1) {
|
|
differences.millisecond = true;
|
|
differences.second = false
|
|
}
|
|
}
|
|
else if (!maxDate.getSeconds() && maxDate.getMinutes()) {
|
|
if (maxDate.getMinutes() - minDate.getMinutes() === 1) {
|
|
differences.second = true;
|
|
differences.minute = false
|
|
}
|
|
}
|
|
else if (!maxDate.getMinutes() && maxDate.getHours()) {
|
|
if (maxDate.getHours() - minDate.getHours() === 1) {
|
|
differences.minute = true;
|
|
differences.hour = false
|
|
}
|
|
}
|
|
else if (!maxDate.getHours() && maxDate.getDate() > 1) {
|
|
if (maxDate.getDate() - minDate.getDate() === 1) {
|
|
differences.hour = true;
|
|
differences.day = false
|
|
}
|
|
}
|
|
else if (maxDate.getDate() === 1 && maxDate.getMonth()) {
|
|
if (maxDate.getMonth() - minDate.getMonth() === 1) {
|
|
differences.day = true;
|
|
differences.month = false
|
|
}
|
|
}
|
|
else if (!maxDate.getMonth() && maxDate.getFullYear())
|
|
if (maxDate.getFullYear() - minDate.getFullYear() === 1) {
|
|
differences.month = true;
|
|
differences.year = false
|
|
}
|
|
};
|
|
tickInterval = utils.isString(tickInterval) ? tickInterval.toLowerCase() : tickInterval;
|
|
dateDifferences = utils.getDatesDifferences(startValue, endValue);
|
|
if (startValue !== endValue)
|
|
correctDifferencesByMaxDate(dateDifferences, startValue > endValue ? endValue : startValue, startValue > endValue ? startValue : endValue);
|
|
dateUnitInterval = utils.getDateUnitInterval(dateDifferences);
|
|
correctDateDifferences(dateDifferences, dateUnitInterval, true);
|
|
dateUnitInterval = utils.getDateUnitInterval(tickInterval || 'second');
|
|
correctDateDifferences(dateDifferences, dateUnitInterval, false);
|
|
dateDifferences[dateDifferencesConverter[dateUnitInterval] || dateUnitInterval] = true;
|
|
resultFormat = this.getDateFormatByDifferences(dateDifferences);
|
|
return resultFormat
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file color.js */
|
|
(function(DX, undefined) {
|
|
var standardColorNames = {
|
|
aliceblue: 'f0f8ff',
|
|
antiquewhite: 'faebd7',
|
|
aqua: '00ffff',
|
|
aquamarine: '7fffd4',
|
|
azure: 'f0ffff',
|
|
beige: 'f5f5dc',
|
|
bisque: 'ffe4c4',
|
|
black: '000000',
|
|
blanchedalmond: 'ffebcd',
|
|
blue: '0000ff',
|
|
blueviolet: '8a2be2',
|
|
brown: 'a52a2a',
|
|
burlywood: 'deb887',
|
|
cadetblue: '5f9ea0',
|
|
chartreuse: '7fff00',
|
|
chocolate: 'd2691e',
|
|
coral: 'ff7f50',
|
|
cornflowerblue: '6495ed',
|
|
cornsilk: 'fff8dc',
|
|
crimson: 'dc143c',
|
|
cyan: '00ffff',
|
|
darkblue: '00008b',
|
|
darkcyan: '008b8b',
|
|
darkgoldenrod: 'b8860b',
|
|
darkgray: 'a9a9a9',
|
|
darkgreen: '006400',
|
|
darkkhaki: 'bdb76b',
|
|
darkmagenta: '8b008b',
|
|
darkolivegreen: '556b2f',
|
|
darkorange: 'ff8c00',
|
|
darkorchid: '9932cc',
|
|
darkred: '8b0000',
|
|
darksalmon: 'e9967a',
|
|
darkseagreen: '8fbc8f',
|
|
darkslateblue: '483d8b',
|
|
darkslategray: '2f4f4f',
|
|
darkturquoise: '00ced1',
|
|
darkviolet: '9400d3',
|
|
deeppink: 'ff1493',
|
|
deepskyblue: '00bfff',
|
|
dimgray: '696969',
|
|
dodgerblue: '1e90ff',
|
|
feldspar: 'd19275',
|
|
firebrick: 'b22222',
|
|
floralwhite: 'fffaf0',
|
|
forestgreen: '228b22',
|
|
fuchsia: 'ff00ff',
|
|
gainsboro: 'dcdcdc',
|
|
ghostwhite: 'f8f8ff',
|
|
gold: 'ffd700',
|
|
goldenrod: 'daa520',
|
|
gray: '808080',
|
|
green: '008000',
|
|
greenyellow: 'adff2f',
|
|
honeydew: 'f0fff0',
|
|
hotpink: 'ff69b4',
|
|
indianred: 'cd5c5c',
|
|
indigo: '4b0082',
|
|
ivory: 'fffff0',
|
|
khaki: 'f0e68c',
|
|
lavender: 'e6e6fa',
|
|
lavenderblush: 'fff0f5',
|
|
lawngreen: '7cfc00',
|
|
lemonchiffon: 'fffacd',
|
|
lightblue: 'add8e6',
|
|
lightcoral: 'f08080',
|
|
lightcyan: 'e0ffff',
|
|
lightgoldenrodyellow: 'fafad2',
|
|
lightgrey: 'd3d3d3',
|
|
lightgreen: '90ee90',
|
|
lightpink: 'ffb6c1',
|
|
lightsalmon: 'ffa07a',
|
|
lightseagreen: '20b2aa',
|
|
lightskyblue: '87cefa',
|
|
lightslateblue: '8470ff',
|
|
lightslategray: '778899',
|
|
lightsteelblue: 'b0c4de',
|
|
lightyellow: 'ffffe0',
|
|
lime: '00ff00',
|
|
limegreen: '32cd32',
|
|
linen: 'faf0e6',
|
|
magenta: 'ff00ff',
|
|
maroon: '800000',
|
|
mediumaquamarine: '66cdaa',
|
|
mediumblue: '0000cd',
|
|
mediumorchid: 'ba55d3',
|
|
mediumpurple: '9370d8',
|
|
mediumseagreen: '3cb371',
|
|
mediumslateblue: '7b68ee',
|
|
mediumspringgreen: '00fa9a',
|
|
mediumturquoise: '48d1cc',
|
|
mediumvioletred: 'c71585',
|
|
midnightblue: '191970',
|
|
mintcream: 'f5fffa',
|
|
mistyrose: 'ffe4e1',
|
|
moccasin: 'ffe4b5',
|
|
navajowhite: 'ffdead',
|
|
navy: '000080',
|
|
oldlace: 'fdf5e6',
|
|
olive: '808000',
|
|
olivedrab: '6b8e23',
|
|
orange: 'ffa500',
|
|
orangered: 'ff4500',
|
|
orchid: 'da70d6',
|
|
palegoldenrod: 'eee8aa',
|
|
palegreen: '98fb98',
|
|
paleturquoise: 'afeeee',
|
|
palevioletred: 'd87093',
|
|
papayawhip: 'ffefd5',
|
|
peachpuff: 'ffdab9',
|
|
peru: 'cd853f',
|
|
pink: 'ffc0cb',
|
|
plum: 'dda0dd',
|
|
powderblue: 'b0e0e6',
|
|
purple: '800080',
|
|
red: 'ff0000',
|
|
rosybrown: 'bc8f8f',
|
|
royalblue: '4169e1',
|
|
saddlebrown: '8b4513',
|
|
salmon: 'fa8072',
|
|
sandybrown: 'f4a460',
|
|
seagreen: '2e8b57',
|
|
seashell: 'fff5ee',
|
|
sienna: 'a0522d',
|
|
silver: 'c0c0c0',
|
|
skyblue: '87ceeb',
|
|
slateblue: '6a5acd',
|
|
slategray: '708090',
|
|
snow: 'fffafa',
|
|
springgreen: '00ff7f',
|
|
steelblue: '4682b4',
|
|
tan: 'd2b48c',
|
|
teal: '008080',
|
|
thistle: 'd8bfd8',
|
|
tomato: 'ff6347',
|
|
turquoise: '40e0d0',
|
|
violet: 'ee82ee',
|
|
violetred: 'd02090',
|
|
wheat: 'f5deb3',
|
|
white: 'ffffff',
|
|
whitesmoke: 'f5f5f5',
|
|
yellow: 'ffff00',
|
|
yellowgreen: '9acd32'
|
|
};
|
|
var standardColorTypes = [{
|
|
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
|
|
process: function(colorString) {
|
|
return [parseInt(colorString[1], 10), parseInt(colorString[2], 10), parseInt(colorString[3], 10)]
|
|
}
|
|
}, {
|
|
re: /^#(\w{2})(\w{2})(\w{2})$/,
|
|
process: function(colorString) {
|
|
return [parseInt(colorString[1], 16), parseInt(colorString[2], 16), parseInt(colorString[3], 16)]
|
|
}
|
|
}, {
|
|
re: /^#(\w{1})(\w{1})(\w{1})$/,
|
|
process: function(colorString) {
|
|
return [parseInt(colorString[1] + colorString[1], 16), parseInt(colorString[2] + colorString[2], 16), parseInt(colorString[3] + colorString[3], 16)]
|
|
}
|
|
}];
|
|
function Color(value) {
|
|
this.baseColor = value;
|
|
var color;
|
|
if (value) {
|
|
color = String(value).toLowerCase().replace(/ /g, '');
|
|
color = standardColorNames[color] ? '#' + standardColorNames[color] : color;
|
|
color = parseColor(color)
|
|
}
|
|
color = color || {};
|
|
this.r = normalize(color[0]);
|
|
this.g = normalize(color[1]);
|
|
this.b = normalize(color[2])
|
|
}
|
|
function parseColor(color) {
|
|
var result,
|
|
i = 0,
|
|
ii = standardColorTypes.length,
|
|
str;
|
|
for (; i < ii; ++i) {
|
|
str = standardColorTypes[i].re.exec(color);
|
|
if (str)
|
|
return standardColorTypes[i].process(str)
|
|
}
|
|
return null
|
|
}
|
|
function normalize(colorComponent) {
|
|
return colorComponent < 0 || isNaN(colorComponent) ? 0 : colorComponent > 255 ? 255 : colorComponent
|
|
}
|
|
function toHexFromRgb(r, g, b) {
|
|
return '#' + (0X01000000 | r << 16 | g << 8 | b).toString(16).slice(1)
|
|
}
|
|
var _round = Math.round;
|
|
Color.prototype = {
|
|
constructor: Color,
|
|
highlight: function(step) {
|
|
step = step || 10;
|
|
return this.alter(step).toHex()
|
|
},
|
|
darken: function(step) {
|
|
step = step || 10;
|
|
return this.alter(-step).toHex()
|
|
},
|
|
alter: function(step) {
|
|
var result = new Color;
|
|
result.r = normalize(this.r + step);
|
|
result.g = normalize(this.g + step);
|
|
result.b = normalize(this.b + step);
|
|
return result
|
|
},
|
|
blend: function(blendColor, opacity) {
|
|
var other = blendColor instanceof Color ? blendColor : new Color(blendColor),
|
|
result = new Color;
|
|
result.r = normalize(_round(this.r * (1 - opacity) + other.r * opacity));
|
|
result.g = normalize(_round(this.g * (1 - opacity) + other.g * opacity));
|
|
result.b = normalize(_round(this.b * (1 - opacity) + other.b * opacity));
|
|
return result
|
|
},
|
|
toHex: function() {
|
|
return toHexFromRgb(this.r, this.g, this.b)
|
|
}
|
|
};
|
|
DX.Color = Color
|
|
})(DevExpress);
|
|
/*! Module core, file localization.js */
|
|
(function($, DX, undefined) {
|
|
var localization = function() {
|
|
var newMessages = {};
|
|
return {
|
|
setup: function(localizablePrefix) {
|
|
this.localizeString = function(text) {
|
|
var regex = new RegExp("(^|[^a-zA-Z_0-9" + localizablePrefix + "-]+)(" + localizablePrefix + "{1,2})([a-zA-Z_0-9-]+)", "g"),
|
|
escapeString = localizablePrefix + localizablePrefix;
|
|
return text.replace(regex, function(str, prefix, escape, localizationKey) {
|
|
var result = prefix + localizablePrefix + localizationKey;
|
|
if (escape !== escapeString)
|
|
if (Globalize.cultures["default"].messages[localizationKey])
|
|
result = prefix + Globalize.localize(localizationKey);
|
|
else
|
|
newMessages[localizationKey] = DX.inflector.humanize(localizationKey);
|
|
return result
|
|
})
|
|
}
|
|
},
|
|
localizeNode: function(node) {
|
|
var self = this;
|
|
$(node).each(function(index, nodeItem) {
|
|
if (!nodeItem.nodeType)
|
|
return;
|
|
if (nodeItem.nodeType === 3)
|
|
nodeItem.nodeValue = self.localizeString(nodeItem.nodeValue);
|
|
else {
|
|
$.each(nodeItem.attributes || [], function(index, attr) {
|
|
if (typeof attr.value === "string")
|
|
attr.value = self.localizeString(attr.value)
|
|
});
|
|
$(nodeItem).contents().each(function(index, node) {
|
|
self.localizeNode(node)
|
|
})
|
|
}
|
|
})
|
|
},
|
|
getDictionary: function(onlyNew) {
|
|
if (onlyNew)
|
|
return newMessages;
|
|
return $.extend({}, newMessages, Globalize.cultures["default"].messages)
|
|
}
|
|
}
|
|
}();
|
|
localization.setup("@");
|
|
DX.localization = localization
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file localization.en.js */
|
|
Globalize.addCultureInfo("default", {messages: {
|
|
Yes: "Yes",
|
|
No: "No",
|
|
Cancel: "Cancel",
|
|
Clear: "Clear",
|
|
Done: "Done",
|
|
Loading: "Loading...",
|
|
Select: "Select...",
|
|
Search: "Search",
|
|
Back: "Back",
|
|
"dxLookup-searchPlaceholder": "Minimum character number: {0}",
|
|
"dxCollectionContainerWidget-noDataText": "No data to display",
|
|
"dxList-pullingDownText": "Pull down to refresh...",
|
|
"dxList-pulledDownText": "Release to refresh...",
|
|
"dxList-refreshingText": "Refreshing...",
|
|
"dxList-pageLoadingText": "Loading...",
|
|
"dxListEditDecorator-delete": "Delete",
|
|
"dxScrollView-pullingDownText": "Pull down to refresh...",
|
|
"dxScrollView-pulledDownText": "Release to refresh...",
|
|
"dxScrollView-refreshingText": "Refreshing...",
|
|
"dxScrollView-reachBottomText": "Loading...",
|
|
"dxSwitch-onText": "ON",
|
|
"dxSwitch-offText": "OFF"
|
|
}});
|
|
/*! Module core, file data.js */
|
|
(function($, DX, undefined) {
|
|
var HAS_KO = DX.support.hasKo;
|
|
var bracketsToDots = function(expr) {
|
|
return expr.replace(/\[/g, ".").replace(/\]/g, "")
|
|
};
|
|
var unwrapObservable = function(value) {
|
|
if (HAS_KO)
|
|
return ko.utils.unwrapObservable(value);
|
|
return value
|
|
};
|
|
var isObservable = function(value) {
|
|
return HAS_KO && ko.isObservable(value)
|
|
};
|
|
var readPropValue = function(obj, propName) {
|
|
if (propName === "this")
|
|
return obj;
|
|
return obj[propName]
|
|
};
|
|
var assignPropValue = function(obj, propName, value) {
|
|
if (propName === "this")
|
|
throw Error("Cannot assign to self");
|
|
var propValue = obj[propName];
|
|
if (isObservable(propValue))
|
|
propValue(value);
|
|
else
|
|
obj[propName] = value
|
|
};
|
|
var compileGetter = function(expr) {
|
|
if (arguments.length > 1)
|
|
expr = $.makeArray(arguments);
|
|
if (!expr || expr === "this")
|
|
return function(obj) {
|
|
return obj
|
|
};
|
|
if ($.isFunction(expr))
|
|
return expr;
|
|
if ($.isArray(expr))
|
|
return combineGetters(expr);
|
|
expr = bracketsToDots(expr);
|
|
var path = expr.split(".");
|
|
return function(obj, options) {
|
|
options = options || {};
|
|
var current = unwrapObservable(obj);
|
|
$.each(path, function() {
|
|
if (!current)
|
|
return false;
|
|
var next = unwrapObservable(current[this]);
|
|
if ($.isFunction(next) && !options.functionsAsIs)
|
|
next = next.call(current);
|
|
current = next
|
|
});
|
|
return current
|
|
}
|
|
};
|
|
var combineGetters = function(getters) {
|
|
var compiledGetters = {};
|
|
$.each(getters, function() {
|
|
compiledGetters[this] = compileGetter(this)
|
|
});
|
|
return function(obj, options) {
|
|
var result = {};
|
|
$.each(compiledGetters, function(name) {
|
|
var value = this(obj, options),
|
|
current,
|
|
path,
|
|
last,
|
|
i;
|
|
if (value === undefined)
|
|
return;
|
|
current = result;
|
|
path = name.split(".");
|
|
last = path.length - 1;
|
|
for (i = 0; i < last; i++)
|
|
current = current[path[i]] = {};
|
|
current[path[i]] = value
|
|
});
|
|
return result
|
|
}
|
|
};
|
|
var compileSetter = function(expr) {
|
|
expr = expr || "this";
|
|
expr = bracketsToDots(expr);
|
|
var pos = expr.lastIndexOf("."),
|
|
targetGetter = compileGetter(expr.substr(0, pos)),
|
|
targetPropName = expr.substr(1 + pos);
|
|
return function(obj, value, options) {
|
|
options = options || {};
|
|
var target = targetGetter(obj, {functionsAsIs: options.functionsAsIs}),
|
|
prevTargetValue = readPropValue(target, targetPropName);
|
|
if (!options.functionsAsIs && $.isFunction(prevTargetValue) && !isObservable(prevTargetValue))
|
|
target[targetPropName](value);
|
|
else {
|
|
prevTargetValue = unwrapObservable(prevTargetValue);
|
|
if (options.merge && $.isPlainObject(value) && (prevTargetValue === undefined || $.isPlainObject(prevTargetValue))) {
|
|
if (!prevTargetValue)
|
|
assignPropValue(target, targetPropName, {});
|
|
DX.utils.deepExtendArraySafe(unwrapObservable(readPropValue(target, targetPropName)), value)
|
|
}
|
|
else
|
|
assignPropValue(target, targetPropName, value)
|
|
}
|
|
}
|
|
};
|
|
var normalizeBinaryCriterion = function(crit) {
|
|
return [crit[0], crit.length < 3 ? "=" : crit[1].toLowerCase(), crit.length < 2 ? true : crit[crit.length - 1]]
|
|
};
|
|
var normalizeSortingInfo = function(info) {
|
|
if (!$.isArray(info))
|
|
info = [info];
|
|
return $.map(info, function(i) {
|
|
return {
|
|
selector: $.isFunction(i) || typeof i === "string" ? i : i.getter || i.field || i.selector,
|
|
desc: !!(i.desc || String(i.dir).charAt(0).toLowerCase() === "d")
|
|
}
|
|
})
|
|
};
|
|
var Guid = DX.Class.inherit({
|
|
ctor: function(value) {
|
|
if (value)
|
|
value = String(value);
|
|
this._value = this._normalize(value || this._generate())
|
|
},
|
|
_normalize: function(value) {
|
|
value = value.replace(/[^a-f0-9]/ig, "").toLowerCase();
|
|
while (value.length < 32)
|
|
value += "0";
|
|
return [value.substr(0, 8), value.substr(8, 4), value.substr(12, 4), value.substr(16, 4), value.substr(20, 12)].join("-")
|
|
},
|
|
_generate: function() {
|
|
var value = "";
|
|
for (var i = 0; i < 32; i++)
|
|
value += Math.round(Math.random() * 15).toString(16);
|
|
return value
|
|
},
|
|
toString: function() {
|
|
return this._value
|
|
},
|
|
valueOf: function() {
|
|
return this._value
|
|
},
|
|
toJSON: function() {
|
|
return this._value
|
|
}
|
|
});
|
|
var toComparable = function(value, caseSensitive) {
|
|
if (value instanceof Date)
|
|
return value.getTime();
|
|
if (value instanceof Guid)
|
|
return value.valueOf();
|
|
if (!caseSensitive && typeof value === "string")
|
|
return value.toLowerCase();
|
|
return value
|
|
};
|
|
var keysEqual = function(keyExpr, key1, key2) {
|
|
if ($.isArray(keyExpr)) {
|
|
var names = $.map(key1, function(v, k) {
|
|
return k
|
|
}),
|
|
name;
|
|
for (var i = 0; i < names.length; i++) {
|
|
name = names[i];
|
|
if (toComparable(key1[name], true) != toComparable(key2[name], true))
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
return toComparable(key1, true) == toComparable(key2, true)
|
|
};
|
|
var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
var base64_encode = function(input) {
|
|
if (!$.isArray(input))
|
|
input = stringToByteArray(String(input));
|
|
var result = "";
|
|
for (var i = 0; i < input.length; i += 3) {
|
|
var octet1 = input[i],
|
|
octet2 = input[i + 1],
|
|
octet3 = input[i + 2];
|
|
result += $.map([octet1 >> 2, (octet1 & 3) << 4 | octet2 >> 4, isNaN(octet2) ? 64 : (octet2 & 15) << 2 | octet3 >> 6, isNaN(octet3) ? 64 : octet3 & 63], function(item) {
|
|
return BASE64_CHARS.charAt(item)
|
|
}).join("")
|
|
}
|
|
return result
|
|
};
|
|
var stringToByteArray = function(str) {
|
|
var bytes = [],
|
|
code,
|
|
i;
|
|
for (i = 0; i < str.length; i++) {
|
|
code = str.charCodeAt(i);
|
|
if (code < 128)
|
|
bytes.push(code);
|
|
else if (code < 2048)
|
|
bytes.push(192 + (code >> 6), 128 + (code & 63));
|
|
else if (code < 65536)
|
|
bytes.push(224 + (code >> 12), 128 + (code >> 6 & 63), 128 + (code & 63));
|
|
else if (code < 2097152)
|
|
bytes.push(240 + (code >> 18), 128 + (code >> 12 & 63), 128 + (code >> 6 & 63), 128 + (code & 63))
|
|
}
|
|
return bytes
|
|
};
|
|
var errorMessageFromXhr = function() {
|
|
var textStatusMessages = {
|
|
timeout: "Network connection timeout",
|
|
error: "Unspecified network error",
|
|
parsererror: "Unexpected server response"
|
|
};
|
|
var textStatusDetails = {
|
|
timeout: "possible causes: the remote host is not accessible, overloaded or is not included into the domain white-list when being run in the native container",
|
|
error: "if the remote host is located on another domain, make sure it properly supports cross-origin resource sharing (CORS), or use the JSONP approach instead",
|
|
parsererror: "the remote host did not respond with valid JSON data"
|
|
};
|
|
var explainTextStatus = function(textStatus) {
|
|
var result = textStatusMessages[textStatus];
|
|
if (!result)
|
|
return textStatus;
|
|
result += " (" + textStatusDetails[textStatus] + ")";
|
|
return result
|
|
};
|
|
return function(xhr, textStatus) {
|
|
if (xhr.status < 400)
|
|
return explainTextStatus(textStatus);
|
|
return xhr.statusText
|
|
}
|
|
}();
|
|
var data = DX.data = {
|
|
utils: {
|
|
compileGetter: compileGetter,
|
|
compileSetter: compileSetter,
|
|
normalizeBinaryCriterion: normalizeBinaryCriterion,
|
|
normalizeSortingInfo: normalizeSortingInfo,
|
|
toComparable: toComparable,
|
|
keysEqual: keysEqual,
|
|
errorMessageFromXhr: errorMessageFromXhr
|
|
},
|
|
Guid: Guid,
|
|
base64_encode: base64_encode,
|
|
queryImpl: {},
|
|
queryAdapters: {},
|
|
query: function() {
|
|
var impl = $.isArray(arguments[0]) ? "array" : "remote";
|
|
return data.queryImpl[impl].apply(this, arguments)
|
|
},
|
|
errorHandler: null,
|
|
_handleError: function(error) {
|
|
if (window.console)
|
|
console.warn("[DevExpress.data]: " + error);
|
|
if (data.errorHandler)
|
|
data.errorHandler(error)
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.query.array.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
data = DX.data,
|
|
queryImpl = data.queryImpl,
|
|
compileGetter = data.utils.compileGetter,
|
|
toComparable = data.utils.toComparable;
|
|
var Iterator = Class.inherit({
|
|
toArray: function() {
|
|
var result = [];
|
|
this.reset();
|
|
while (this.next())
|
|
result.push(this.current());
|
|
return result
|
|
},
|
|
countable: function() {
|
|
return false
|
|
}
|
|
});
|
|
var ArrayIterator = Iterator.inherit({
|
|
ctor: function(array) {
|
|
this.array = array;
|
|
this.index = -1
|
|
},
|
|
next: function() {
|
|
if (this.index + 1 < this.array.length) {
|
|
this.index++;
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
current: function() {
|
|
return this.array[this.index]
|
|
},
|
|
reset: function() {
|
|
this.index = -1
|
|
},
|
|
toArray: function() {
|
|
return this.array.slice(0)
|
|
},
|
|
countable: function() {
|
|
return true
|
|
},
|
|
count: function() {
|
|
return this.array.length
|
|
}
|
|
});
|
|
var WrappedIterator = Iterator.inherit({
|
|
ctor: function(iter) {
|
|
this.iter = iter
|
|
},
|
|
next: function() {
|
|
return this.iter.next()
|
|
},
|
|
current: function() {
|
|
return this.iter.current()
|
|
},
|
|
reset: function() {
|
|
return this.iter.reset()
|
|
}
|
|
});
|
|
var SortIterator = Iterator.inherit({
|
|
ctor: function(iter, getter, desc) {
|
|
this.iter = iter;
|
|
this.rules = [{
|
|
getter: getter,
|
|
desc: desc
|
|
}]
|
|
},
|
|
thenBy: function(getter, desc) {
|
|
var result = new SortIterator(this.sortedIter || this.iter, getter, desc);
|
|
if (!this.sortedIter)
|
|
result.rules = this.rules.concat(result.rules);
|
|
return result
|
|
},
|
|
next: function() {
|
|
this._ensureSorted();
|
|
return this.sortedIter.next()
|
|
},
|
|
current: function() {
|
|
this._ensureSorted();
|
|
return this.sortedIter.current()
|
|
},
|
|
reset: function() {
|
|
delete this.sortedIter
|
|
},
|
|
countable: function() {
|
|
return this.sortedIter || this.iter.countable()
|
|
},
|
|
count: function() {
|
|
if (this.sortedIter)
|
|
return this.sortedIter.count();
|
|
return this.iter.count()
|
|
},
|
|
_ensureSorted: function() {
|
|
if (this.sortedIter)
|
|
return;
|
|
$.each(this.rules, function() {
|
|
this.getter = compileGetter(this.getter)
|
|
});
|
|
this.sortedIter = new ArrayIterator(this.iter.toArray().sort($.proxy(this._compare, this)))
|
|
},
|
|
_compare: function(x, y) {
|
|
if (x === y)
|
|
return 0;
|
|
for (var i = 0, rulesCount = this.rules.length; i < rulesCount; i++) {
|
|
var rule = this.rules[i],
|
|
xValue = toComparable(rule.getter(x)),
|
|
yValue = toComparable(rule.getter(y)),
|
|
factor = rule.desc ? -1 : 1;
|
|
if (xValue < yValue)
|
|
return -factor;
|
|
if (xValue > yValue)
|
|
return factor;
|
|
if (xValue !== yValue)
|
|
return !xValue ? -factor : factor
|
|
}
|
|
return 0
|
|
}
|
|
});
|
|
var compileCriteria = function() {
|
|
var compileGroup = function(crit) {
|
|
var operands = [],
|
|
bag = ["return function(d) { return "],
|
|
index = 0,
|
|
pushAnd = false;
|
|
$.each(crit, function() {
|
|
if ($.isArray(this) || $.isFunction(this)) {
|
|
if (pushAnd)
|
|
bag.push(" && ");
|
|
operands.push(compileCriteria(this));
|
|
bag.push("op[", index, "](d)");
|
|
index++;
|
|
pushAnd = true
|
|
}
|
|
else {
|
|
bag.push(/and|&/i.test(this) ? " && " : " || ");
|
|
pushAnd = false
|
|
}
|
|
});
|
|
bag.push(" }");
|
|
return new Function("op", bag.join(""))(operands)
|
|
};
|
|
var toString = function(value) {
|
|
return DX.utils.isDefined(value) ? value.toString() : ''
|
|
};
|
|
var compileBinary = function(crit) {
|
|
crit = data.utils.normalizeBinaryCriterion(crit);
|
|
var getter = compileGetter(crit[0]),
|
|
op = crit[1],
|
|
value = crit[2];
|
|
value = toComparable(value);
|
|
switch (op.toLowerCase()) {
|
|
case"=":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) == value
|
|
};
|
|
case"<>":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) != value
|
|
};
|
|
case">":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) > value
|
|
};
|
|
case"<":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) < value
|
|
};
|
|
case">=":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) >= value
|
|
};
|
|
case"<=":
|
|
return function(obj) {
|
|
return toComparable(getter(obj)) <= value
|
|
};
|
|
case"startswith":
|
|
return function(obj) {
|
|
return toComparable(toString(getter(obj))).indexOf(value) === 0
|
|
};
|
|
case"endswith":
|
|
return function(obj) {
|
|
var getterValue = toComparable(toString(getter(obj)));
|
|
return getterValue.lastIndexOf(value) === getterValue.length - toString(value).length
|
|
};
|
|
case"contains":
|
|
return function(obj) {
|
|
return toComparable(toString(getter(obj))).indexOf(value) > -1
|
|
};
|
|
case"notcontains":
|
|
return function(obj) {
|
|
return toComparable(toString(getter(obj))).indexOf(value) === -1
|
|
}
|
|
}
|
|
throw Error("Unknown filter operation: " + op);
|
|
};
|
|
return function(crit) {
|
|
if ($.isFunction(crit))
|
|
return crit;
|
|
if ($.isArray(crit[0]))
|
|
return compileGroup(crit);
|
|
return compileBinary(crit)
|
|
}
|
|
}();
|
|
var FilterIterator = WrappedIterator.inherit({
|
|
ctor: function(iter, criteria) {
|
|
this.callBase(iter);
|
|
this.criteria = compileCriteria(criteria)
|
|
},
|
|
next: function() {
|
|
while (this.iter.next())
|
|
if (this.criteria(this.current()))
|
|
return true;
|
|
return false
|
|
}
|
|
});
|
|
var GroupIterator = Iterator.inherit({
|
|
ctor: function(iter, getter) {
|
|
this.iter = iter;
|
|
this.getter = getter
|
|
},
|
|
next: function() {
|
|
this._ensureGrouped();
|
|
return this.groupedIter.next()
|
|
},
|
|
current: function() {
|
|
this._ensureGrouped();
|
|
return this.groupedIter.current()
|
|
},
|
|
reset: function() {
|
|
delete this.groupedIter
|
|
},
|
|
countable: function() {
|
|
return !!this.groupedIter
|
|
},
|
|
count: function() {
|
|
return this.groupedIter.count()
|
|
},
|
|
_ensureGrouped: function() {
|
|
if (this.groupedIter)
|
|
return;
|
|
var hash = {},
|
|
keys = [],
|
|
iter = this.iter,
|
|
getter = compileGetter(this.getter);
|
|
iter.reset();
|
|
while (iter.next()) {
|
|
var current = iter.current(),
|
|
key = getter(current);
|
|
if (key in hash)
|
|
hash[key].push(current);
|
|
else {
|
|
hash[key] = [current];
|
|
keys.push(key)
|
|
}
|
|
}
|
|
this.groupedIter = new ArrayIterator($.map(keys, function(key) {
|
|
return {
|
|
key: key,
|
|
items: hash[key]
|
|
}
|
|
}))
|
|
}
|
|
});
|
|
var SelectIterator = WrappedIterator.inherit({
|
|
ctor: function(iter, getter) {
|
|
this.callBase(iter);
|
|
this.getter = compileGetter(getter)
|
|
},
|
|
current: function() {
|
|
return this.getter(this.callBase())
|
|
},
|
|
countable: function() {
|
|
return this.iter.countable()
|
|
},
|
|
count: function() {
|
|
return this.iter.count()
|
|
}
|
|
});
|
|
var SliceIterator = WrappedIterator.inherit({
|
|
ctor: function(iter, skip, take) {
|
|
this.callBase(iter);
|
|
this.skip = Math.max(0, skip);
|
|
this.take = Math.max(0, take);
|
|
this.pos = 0
|
|
},
|
|
next: function() {
|
|
if (this.pos >= this.skip + this.take)
|
|
return false;
|
|
while (this.pos < this.skip && this.iter.next())
|
|
this.pos++;
|
|
this.pos++;
|
|
return this.iter.next()
|
|
},
|
|
reset: function() {
|
|
this.callBase();
|
|
this.pos = 0
|
|
},
|
|
countable: function() {
|
|
return this.iter.countable()
|
|
},
|
|
count: function() {
|
|
return Math.min(this.iter.count() - this.skip, this.take)
|
|
}
|
|
});
|
|
queryImpl.array = function(iter, queryOptions) {
|
|
queryOptions = queryOptions || {};
|
|
if (!(iter instanceof Iterator))
|
|
iter = new ArrayIterator(iter);
|
|
var handleError = function(error) {
|
|
var handler = queryOptions.errorHandler;
|
|
if (handler)
|
|
handler(error);
|
|
data._handleError(error)
|
|
};
|
|
var aggregate = function(seed, step, finalize) {
|
|
var d = $.Deferred().fail(handleError);
|
|
try {
|
|
iter.reset();
|
|
if (arguments.length < 2) {
|
|
step = arguments[0];
|
|
seed = iter.next() ? iter.current() : undefined
|
|
}
|
|
var accumulator = seed;
|
|
while (iter.next())
|
|
accumulator = step(accumulator, iter.current());
|
|
d.resolve(finalize ? finalize(accumulator) : accumulator)
|
|
}
|
|
catch(x) {
|
|
d.reject(x)
|
|
}
|
|
return d.promise()
|
|
};
|
|
var select = function(getter) {
|
|
if (!$.isFunction(getter) && !$.isArray(getter))
|
|
getter = $.makeArray(arguments);
|
|
return chainQuery(new SelectIterator(iter, getter))
|
|
};
|
|
var selectProp = function(name) {
|
|
return select(compileGetter(name))
|
|
};
|
|
var chainQuery = function(iter) {
|
|
return queryImpl.array(iter, queryOptions)
|
|
};
|
|
return {
|
|
toArray: function() {
|
|
return iter.toArray()
|
|
},
|
|
enumerate: function() {
|
|
var d = $.Deferred().fail(handleError);
|
|
try {
|
|
d.resolve(iter.toArray())
|
|
}
|
|
catch(x) {
|
|
d.reject(x)
|
|
}
|
|
return d.promise()
|
|
},
|
|
sortBy: function(getter, desc) {
|
|
return chainQuery(new SortIterator(iter, getter, desc))
|
|
},
|
|
thenBy: function(getter, desc) {
|
|
if (iter instanceof SortIterator)
|
|
return chainQuery(iter.thenBy(getter, desc));
|
|
throw Error();
|
|
},
|
|
filter: function(criteria) {
|
|
if (!$.isArray(criteria))
|
|
criteria = $.makeArray(arguments);
|
|
return chainQuery(new FilterIterator(iter, criteria))
|
|
},
|
|
slice: function(skip, take) {
|
|
if (take === undefined)
|
|
take = Number.MAX_VALUE;
|
|
return chainQuery(new SliceIterator(iter, skip, take))
|
|
},
|
|
select: select,
|
|
groupBy: function(getter) {
|
|
return chainQuery(new GroupIterator(iter, getter))
|
|
},
|
|
aggregate: aggregate,
|
|
count: function() {
|
|
if (iter.countable()) {
|
|
var d = $.Deferred().fail(handleError);
|
|
try {
|
|
d.resolve(iter.count())
|
|
}
|
|
catch(x) {
|
|
d.reject(x)
|
|
}
|
|
return d.promise()
|
|
}
|
|
return aggregate(0, function(count) {
|
|
return 1 + count
|
|
})
|
|
},
|
|
sum: function(getter) {
|
|
if (getter)
|
|
return selectProp(getter).sum();
|
|
return aggregate(0, function(sum, item) {
|
|
return sum + item
|
|
})
|
|
},
|
|
min: function(getter) {
|
|
if (getter)
|
|
return selectProp(getter).min();
|
|
return aggregate(function(min, item) {
|
|
return item < min ? item : min
|
|
})
|
|
},
|
|
max: function(getter) {
|
|
if (getter)
|
|
return selectProp(getter).max();
|
|
return aggregate(function(max, item) {
|
|
return item > max ? item : max
|
|
})
|
|
},
|
|
avg: function(getter) {
|
|
if (getter)
|
|
return selectProp(getter).avg();
|
|
var count = 0;
|
|
return aggregate(0, function(sum, item) {
|
|
count++;
|
|
return sum + item
|
|
}, function(sum) {
|
|
return count ? sum / count : undefined
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.query.remote.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data,
|
|
queryImpl = data.queryImpl;
|
|
queryImpl.remote = function(url, queryOptions, tasks) {
|
|
tasks = tasks || [];
|
|
queryOptions = queryOptions || {};
|
|
var createTask = function(name, args) {
|
|
return {
|
|
name: name,
|
|
args: args
|
|
}
|
|
};
|
|
var exec = function(executorTask) {
|
|
var d = $.Deferred(),
|
|
adapterFactory,
|
|
adapter,
|
|
taskQueue,
|
|
currentTask;
|
|
var rejectWithNotify = function(error) {
|
|
var handler = queryOptions.errorHandler;
|
|
if (handler)
|
|
handler(error);
|
|
data._handleError(error);
|
|
d.reject(error)
|
|
};
|
|
try {
|
|
adapterFactory = queryOptions.adapter || "odata";
|
|
if (!$.isFunction(adapterFactory))
|
|
adapterFactory = data.queryAdapters[adapterFactory];
|
|
adapter = adapterFactory(queryOptions);
|
|
taskQueue = [].concat(tasks).concat(executorTask);
|
|
while (taskQueue.length) {
|
|
currentTask = taskQueue[0];
|
|
if (String(currentTask.name) !== "enumerate")
|
|
if (!adapter[currentTask.name] || adapter[currentTask.name].apply(adapter, currentTask.args) === false)
|
|
break;
|
|
taskQueue.shift()
|
|
}
|
|
adapter.exec(url).done(function(result, extra) {
|
|
if (!taskQueue.length)
|
|
d.resolve(result, extra);
|
|
else {
|
|
var clientChain = queryImpl.array(result, {errorHandler: queryOptions.errorHandler});
|
|
$.each(taskQueue, function() {
|
|
clientChain = clientChain[this.name].apply(clientChain, this.args)
|
|
});
|
|
clientChain.done($.proxy(d.resolve, d)).fail($.proxy(d.reject, d))
|
|
}
|
|
}).fail(rejectWithNotify)
|
|
}
|
|
catch(x) {
|
|
rejectWithNotify(x)
|
|
}
|
|
return d.promise()
|
|
};
|
|
var query = {};
|
|
$.each(["sortBy", "thenBy", "filter", "slice", "select", "groupBy"], function() {
|
|
var name = this;
|
|
query[name] = function() {
|
|
return queryImpl.remote(url, queryOptions, tasks.concat(createTask(name, arguments)))
|
|
}
|
|
});
|
|
$.each(["count", "min", "max", "sum", "avg", "aggregate", "enumerate"], function() {
|
|
var name = this;
|
|
query[name] = function() {
|
|
return exec.call(this, createTask(name, arguments))
|
|
}
|
|
});
|
|
return query
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.odata.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data,
|
|
Guid = data.Guid;
|
|
var JSON_VERBOSE_MIME_TYPE = "application/json;odata=verbose";
|
|
var ajaxOptionsForRequest = function(request, requestOptions) {
|
|
request = $.extend({
|
|
method: "get",
|
|
url: "",
|
|
params: {},
|
|
payload: null,
|
|
headers: {}
|
|
}, request);
|
|
requestOptions = requestOptions || {};
|
|
var beforeSend = requestOptions.beforeSend;
|
|
if (beforeSend)
|
|
beforeSend(request);
|
|
var method = (request.method || "get").toLowerCase(),
|
|
isGet = method === "get",
|
|
useJsonp = isGet && requestOptions.jsonp,
|
|
params = $.extend({}, request.params),
|
|
ajaxData = isGet ? params : JSON.stringify(request.payload),
|
|
qs = !isGet && $.param(params),
|
|
url = request.url,
|
|
contentType = !isGet && JSON_VERBOSE_MIME_TYPE;
|
|
if (qs)
|
|
url += (url.indexOf("?") > -1 ? "&" : "?") + qs;
|
|
if (useJsonp)
|
|
ajaxData["$format"] = "json";
|
|
return {
|
|
url: url,
|
|
data: ajaxData,
|
|
dataType: useJsonp ? "jsonp" : "json",
|
|
jsonp: useJsonp && "$callback",
|
|
type: method,
|
|
timeout: 30000,
|
|
headers: request.headers,
|
|
contentType: contentType,
|
|
accepts: {json: [JSON_VERBOSE_MIME_TYPE, "text/plain"].join()},
|
|
xhrFields: {withCredentials: requestOptions.withCredentials}
|
|
}
|
|
};
|
|
var sendRequest = function(request, requestOptions) {
|
|
var d = $.Deferred();
|
|
$.ajax(ajaxOptionsForRequest(request, requestOptions)).always(function(obj, textStatus) {
|
|
var tuplet = interpretVerboseJsonFormat(obj, textStatus),
|
|
error = tuplet.error,
|
|
data = tuplet.data,
|
|
nextUrl = tuplet.nextUrl,
|
|
extra;
|
|
if (error)
|
|
d.reject(error);
|
|
else if (requestOptions.countOnly)
|
|
d.resolve(tuplet.count);
|
|
else if (nextUrl)
|
|
sendRequest({url: nextUrl}, requestOptions).fail($.proxy(d.reject, d)).done(function(nextData) {
|
|
d.resolve(data.concat(nextData))
|
|
});
|
|
else {
|
|
if (isFinite(tuplet.count))
|
|
extra = {totalCount: tuplet.count};
|
|
d.resolve(data, extra)
|
|
}
|
|
});
|
|
return d.promise()
|
|
};
|
|
var formatDotNetError = function(errorObj) {
|
|
var message,
|
|
currentError = errorObj;
|
|
if ("message" in errorObj)
|
|
if (errorObj.message.value)
|
|
message = errorObj.message.value;
|
|
else
|
|
message = errorObj.message;
|
|
while (currentError = currentError.innererror || currentError.internalexception) {
|
|
message = currentError.message;
|
|
if (currentError.internalexception && message.indexOf("inner exception") === -1)
|
|
break
|
|
}
|
|
return message
|
|
};
|
|
var errorFromResponse = function(obj, textStatus) {
|
|
if (textStatus === "nocontent")
|
|
return null;
|
|
var httpStatus = 200,
|
|
message = "Unknown error",
|
|
response = obj;
|
|
if (textStatus !== "success") {
|
|
httpStatus = obj.status;
|
|
message = data.utils.errorMessageFromXhr(obj, textStatus);
|
|
try {
|
|
response = $.parseJSON(obj.responseText)
|
|
}
|
|
catch(x) {}
|
|
}
|
|
var errorObj = response && response.error;
|
|
if (errorObj) {
|
|
message = formatDotNetError(errorObj) || message;
|
|
if (httpStatus === 200)
|
|
httpStatus = 500;
|
|
if (response.error.code)
|
|
httpStatus = Number(response.error.code);
|
|
return $.extend(Error(message), {
|
|
httpStatus: httpStatus,
|
|
errorDetails: errorObj
|
|
})
|
|
}
|
|
else if (httpStatus !== 200)
|
|
return $.extend(Error(message), {httpStatus: httpStatus})
|
|
};
|
|
var interpretVerboseJsonFormat = function(obj, textStatus) {
|
|
var error = errorFromResponse(obj, textStatus);
|
|
if (error)
|
|
return {error: error};
|
|
if (!$.isPlainObject(obj))
|
|
return {data: obj};
|
|
var data = obj.d;
|
|
if (!data)
|
|
return {error: Error("Malformed or unsupported JSON response received")};
|
|
data = data.results || data;
|
|
recognizeDates(data);
|
|
return {
|
|
data: data,
|
|
nextUrl: obj.d.__next,
|
|
count: obj.d.__count
|
|
}
|
|
};
|
|
var EdmLiteral = DX.Class.inherit({
|
|
ctor: function(value) {
|
|
this._value = value
|
|
},
|
|
valueOf: function() {
|
|
return this._value
|
|
}
|
|
});
|
|
var serializeDate = function() {
|
|
var pad = function(part) {
|
|
part = String(part);
|
|
if (part.length < 2)
|
|
part = "0" + part;
|
|
return part
|
|
};
|
|
return function(date) {
|
|
var result = ["datetime'", date.getUTCFullYear(), "-", pad(date.getUTCMonth() + 1), "-", pad(date.getUTCDate())];
|
|
if (date.getUTCHours() || date.getUTCMinutes() || date.getUTCSeconds() || date.getUTCMilliseconds()) {
|
|
result.push("T", pad(date.getUTCHours()), ":", pad(date.getUTCMinutes()), ":", pad(date.getUTCSeconds()));
|
|
if (date.getUTCMilliseconds())
|
|
result.push(".", date.getUTCMilliseconds())
|
|
}
|
|
result.push("'");
|
|
return result.join("")
|
|
}
|
|
}();
|
|
var serializePropName = function(propName) {
|
|
if (propName instanceof EdmLiteral)
|
|
return propName.valueOf();
|
|
return propName.replace(/\./g, "/")
|
|
};
|
|
var serializeValue = function(value) {
|
|
if (value instanceof Date)
|
|
return serializeDate(value);
|
|
if (value instanceof Guid)
|
|
return "guid'" + value + "'";
|
|
if (value instanceof EdmLiteral)
|
|
return value.valueOf();
|
|
if (typeof value === "string")
|
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
return String(value)
|
|
};
|
|
var serializeKey = function(key) {
|
|
if ($.isPlainObject(key)) {
|
|
var parts = [];
|
|
$.each(key, function(k, v) {
|
|
parts.push(serializePropName(k) + "=" + serializeValue(v))
|
|
});
|
|
return parts.join()
|
|
}
|
|
return serializeValue(key)
|
|
};
|
|
var recognizeDates = function(list) {
|
|
$.each(list, function(i, val) {
|
|
if (val !== null && typeof val === "object")
|
|
recognizeDates(val);
|
|
else if (typeof val === "string") {
|
|
var matches = val.match(/^\/Date\((-?\d+)((\+|-)?(\d+)?)\)\/$/);
|
|
if (matches)
|
|
list[i] = new Date(Number(matches[1]) + matches[2] * 60000)
|
|
}
|
|
})
|
|
};
|
|
var keyConverters = {
|
|
String: function(value) {
|
|
return value + ""
|
|
},
|
|
Int32: function(value) {
|
|
return ~~value
|
|
},
|
|
Int64: function(value) {
|
|
if (value instanceof EdmLiteral)
|
|
return value;
|
|
return new EdmLiteral(value + "L")
|
|
},
|
|
Guid: function(value) {
|
|
if (value instanceof Guid)
|
|
return value;
|
|
return new Guid(value)
|
|
}
|
|
};
|
|
var compileCriteria = function() {
|
|
var createBinaryOperationFormatter = function(op) {
|
|
return function(prop, val, bag) {
|
|
bag.push(prop, " ", op, " ", val)
|
|
}
|
|
};
|
|
var createStringFuncFormatter = function(op, reverse) {
|
|
return function(prop, val, bag) {
|
|
if (reverse)
|
|
bag.push(op, "(", val, ",", prop, ")");
|
|
else
|
|
bag.push(op, "(", prop, ",", val, ")")
|
|
}
|
|
};
|
|
var formatters = {
|
|
"=": createBinaryOperationFormatter("eq"),
|
|
"<>": createBinaryOperationFormatter("ne"),
|
|
">": createBinaryOperationFormatter("gt"),
|
|
">=": createBinaryOperationFormatter("ge"),
|
|
"<": createBinaryOperationFormatter("lt"),
|
|
"<=": createBinaryOperationFormatter("le"),
|
|
startswith: createStringFuncFormatter("startswith"),
|
|
endswith: createStringFuncFormatter("endswith"),
|
|
contains: createStringFuncFormatter("substringof", true),
|
|
notcontains: createStringFuncFormatter("not substringof", true)
|
|
};
|
|
var compileBinary = function(criteria, bag) {
|
|
criteria = data.utils.normalizeBinaryCriterion(criteria);
|
|
var op = criteria[1],
|
|
formatter = formatters[op.toLowerCase()];
|
|
if (!formatter)
|
|
throw Error("Unknown filter operation: " + op);
|
|
formatter(serializePropName(criteria[0]), serializeValue(criteria[2]), bag)
|
|
};
|
|
var compileGroup = function(criteria, bag) {
|
|
var pushAnd = false;
|
|
$.each(criteria, function() {
|
|
if ($.isArray(this)) {
|
|
if (pushAnd)
|
|
bag.push(" and ");
|
|
bag.push("(");
|
|
compileCore(this, bag);
|
|
bag.push(")");
|
|
pushAnd = true
|
|
}
|
|
else {
|
|
bag.push(/and|&/i.test(this) ? " and " : " or ");
|
|
pushAnd = false
|
|
}
|
|
})
|
|
};
|
|
var compileCore = function(criteria, bag) {
|
|
if ($.isArray(criteria[0]))
|
|
compileGroup(criteria, bag);
|
|
else
|
|
compileBinary(criteria, bag)
|
|
};
|
|
return function(criteria) {
|
|
var bag = [];
|
|
compileCore(criteria, bag);
|
|
return bag.join("")
|
|
}
|
|
}();
|
|
var createODataQueryAdapter = function(queryOptions) {
|
|
var sorting = [],
|
|
criteria = [],
|
|
select,
|
|
skip,
|
|
take,
|
|
countQuery;
|
|
var hasSlice = function() {
|
|
return skip || take !== undefined
|
|
};
|
|
var sortCore = function(getter, desc, reset) {
|
|
if (hasSlice() || typeof getter !== "string")
|
|
return false;
|
|
if (reset)
|
|
sorting = [];
|
|
var rule = serializePropName(getter);
|
|
if (desc)
|
|
rule += " desc";
|
|
sorting.push(rule)
|
|
};
|
|
var generateExpand = function() {
|
|
var hash = {};
|
|
if (queryOptions.expand)
|
|
$.each($.makeArray(queryOptions.expand), function() {
|
|
hash[serializePropName(this)] = 1
|
|
});
|
|
if (select)
|
|
$.each(select, function() {
|
|
var path = this.split(".");
|
|
if (path.length < 2)
|
|
return;
|
|
path.pop();
|
|
hash[serializePropName(path.join("."))] = 1
|
|
});
|
|
return $.map(hash, function(k, v) {
|
|
return v
|
|
}).join() || undefined
|
|
};
|
|
var requestData = function() {
|
|
var result = {};
|
|
if (!countQuery) {
|
|
if (sorting.length)
|
|
result["$orderby"] = sorting.join(",");
|
|
if (skip)
|
|
result["$skip"] = skip;
|
|
if (take !== undefined)
|
|
result["$top"] = take;
|
|
if (select)
|
|
result["$select"] = serializePropName(select.join());
|
|
result["$expand"] = generateExpand()
|
|
}
|
|
if (criteria.length)
|
|
result["$filter"] = compileCriteria(criteria.length < 2 ? criteria[0] : criteria);
|
|
if (countQuery)
|
|
result["$top"] = 0;
|
|
if (queryOptions.requireTotalCount || countQuery)
|
|
result["$inlinecount"] = "allpages";
|
|
return result
|
|
};
|
|
return {
|
|
exec: function(url) {
|
|
return sendRequest({
|
|
url: url,
|
|
params: $.extend(requestData(), queryOptions && queryOptions.params)
|
|
}, {
|
|
beforeSend: queryOptions.beforeSend,
|
|
jsonp: queryOptions.jsonp,
|
|
withCredentials: queryOptions.withCredentials,
|
|
countOnly: countQuery
|
|
})
|
|
},
|
|
sortBy: function(getter, desc) {
|
|
return sortCore(getter, desc, true)
|
|
},
|
|
thenBy: function(getter, desc) {
|
|
return sortCore(getter, desc, false)
|
|
},
|
|
slice: function(skipCount, takeCount) {
|
|
if (hasSlice())
|
|
return false;
|
|
skip = skipCount;
|
|
take = takeCount
|
|
},
|
|
filter: function(criterion) {
|
|
if (hasSlice() || $.isFunction(criterion))
|
|
return false;
|
|
if (!$.isArray(criterion))
|
|
criterion = $.makeArray(arguments);
|
|
if (criteria.length)
|
|
criteria.push("and");
|
|
criteria.push(criterion)
|
|
},
|
|
select: function(expr) {
|
|
if (select || $.isFunction(expr))
|
|
return false;
|
|
if (!$.isArray(expr))
|
|
expr = $.makeArray(arguments);
|
|
select = expr
|
|
},
|
|
count: function() {
|
|
countQuery = true
|
|
}
|
|
}
|
|
};
|
|
$.extend(true, data, {
|
|
EdmLiteral: EdmLiteral,
|
|
utils: {odata: {
|
|
sendRequest: sendRequest,
|
|
serializePropName: serializePropName,
|
|
serializeValue: serializeValue,
|
|
serializeKey: serializeKey,
|
|
keyConverters: keyConverters
|
|
}},
|
|
queryAdapters: {odata: createODataQueryAdapter}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.abstract.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
abstract = DX.abstract,
|
|
data = DX.data,
|
|
normalizeSortingInfo = data.utils.normalizeSortingInfo;
|
|
var STORE_CALLBACK_NAMES = ["loading", "loaded", "modifying", "modified", "inserting", "inserted", "updating", "updated", "removing", "removed"];
|
|
function multiLevelGroup(query, groupInfo) {
|
|
query = query.groupBy(groupInfo[0].selector);
|
|
if (groupInfo.length > 1)
|
|
query = query.select(function(g) {
|
|
return $.extend({}, g, {items: multiLevelGroup(data.query(g.items), groupInfo.slice(1)).toArray()})
|
|
});
|
|
return query
|
|
}
|
|
data.Store = Class.inherit({
|
|
ctor: function(options) {
|
|
var self = this;
|
|
options = options || {};
|
|
$.each(STORE_CALLBACK_NAMES, function() {
|
|
var callbacks = self[this] = $.Callbacks();
|
|
if (this in options)
|
|
callbacks.add(options[this])
|
|
});
|
|
this._key = options.key;
|
|
this._errorHandler = options.errorHandler;
|
|
this._useDefaultSearch = true
|
|
},
|
|
_customLoadOptions: function() {
|
|
return null
|
|
},
|
|
key: function() {
|
|
return this._key
|
|
},
|
|
keyOf: function(obj) {
|
|
if (!this._keyGetter)
|
|
this._keyGetter = data.utils.compileGetter(this.key());
|
|
return this._keyGetter(obj)
|
|
},
|
|
_requireKey: function() {
|
|
if (!this.key())
|
|
throw Error("Key expression is required for this operation");
|
|
},
|
|
load: function(options) {
|
|
var self = this;
|
|
options = options || {};
|
|
this.loading.fire(options);
|
|
return this._loadImpl(options).done(function(result, extra) {
|
|
self.loaded.fire(result, extra)
|
|
})
|
|
},
|
|
_loadImpl: function(options) {
|
|
var filter = options.filter,
|
|
sort = options.sort,
|
|
select = options.select,
|
|
group = options.group,
|
|
skip = options.skip,
|
|
take = options.take,
|
|
q = this.createQuery(options);
|
|
if (filter)
|
|
q = q.filter(filter);
|
|
if (group)
|
|
group = normalizeSortingInfo(group);
|
|
if (sort || group) {
|
|
sort = normalizeSortingInfo(sort || []);
|
|
if (group)
|
|
sort = group.concat(sort);
|
|
$.each(sort, function(index) {
|
|
q = q[index ? "thenBy" : "sortBy"](this.selector, this.desc)
|
|
})
|
|
}
|
|
if (select)
|
|
q = q.select(select);
|
|
if (group)
|
|
q = multiLevelGroup(q, group);
|
|
if (take || skip)
|
|
q = q.slice(skip || 0, take);
|
|
return q.enumerate()
|
|
},
|
|
createQuery: abstract,
|
|
totalCount: function(options) {
|
|
return this._addFailHandlers(this._totalCountImpl(options))
|
|
},
|
|
_totalCountImpl: function(options) {
|
|
options = options || {};
|
|
var q = this.createQuery(),
|
|
group = options.group,
|
|
filter = options.filter;
|
|
if (filter)
|
|
q = q.filter(filter);
|
|
if (group) {
|
|
group = normalizeSortingInfo(group);
|
|
q = multiLevelGroup(q, group)
|
|
}
|
|
return q.count()
|
|
},
|
|
byKey: function(key, extraOptions) {
|
|
return this._addFailHandlers(this._byKeyImpl(key, extraOptions))
|
|
},
|
|
_byKeyImpl: abstract,
|
|
insert: function(values) {
|
|
var self = this;
|
|
self.modifying.fire();
|
|
self.inserting.fire(values);
|
|
return self._addFailHandlers(self._insertImpl(values).done(function(callbackValues, callbackKey) {
|
|
self.inserted.fire(callbackValues, callbackKey);
|
|
self.modified.fire()
|
|
}))
|
|
},
|
|
_insertImpl: abstract,
|
|
update: function(key, values) {
|
|
var self = this;
|
|
self.modifying.fire();
|
|
self.updating.fire(key, values);
|
|
return self._addFailHandlers(self._updateImpl(key, values).done(function(callbackKey, callbackValues) {
|
|
self.updated.fire(callbackKey, callbackValues);
|
|
self.modified.fire()
|
|
}))
|
|
},
|
|
_updateImpl: abstract,
|
|
remove: function(key) {
|
|
var self = this;
|
|
self.modifying.fire();
|
|
self.removing.fire(key);
|
|
return self._addFailHandlers(self._removeImpl(key).done(function(callbackKey) {
|
|
self.removed.fire(callbackKey);
|
|
self.modified.fire()
|
|
}))
|
|
},
|
|
_removeImpl: abstract,
|
|
_addFailHandlers: function(deferred) {
|
|
return deferred.fail(this._errorHandler, data._handleError)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.array.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data,
|
|
Guid = data.Guid;
|
|
var trivialPromise = function(_) {
|
|
var d = $.Deferred();
|
|
return d.resolve.apply(d, arguments).promise()
|
|
};
|
|
var rejectedPromise = function(_) {
|
|
var d = $.Deferred();
|
|
return d.reject.apply(d, arguments).promise()
|
|
};
|
|
data.ArrayStore = data.Store.inherit({
|
|
ctor: function(options) {
|
|
if ($.isArray(options))
|
|
options = {data: options};
|
|
else
|
|
options = options || {};
|
|
this.callBase(options);
|
|
this._array = options.data || []
|
|
},
|
|
createQuery: function() {
|
|
return data.query(this._array, {errorHandler: this._errorHandler})
|
|
},
|
|
_byKeyImpl: function(key) {
|
|
return trivialPromise(this._array[this._indexByKey(key)])
|
|
},
|
|
_insertImpl: function(values) {
|
|
var keyExpr = this.key(),
|
|
keyValue,
|
|
obj = {};
|
|
$.extend(obj, values);
|
|
if (keyExpr) {
|
|
keyValue = this.keyOf(obj);
|
|
if (keyValue === undefined || typeof keyValue === "object" && $.isEmptyObject(keyValue)) {
|
|
if ($.isArray(keyExpr))
|
|
throw Error("Compound keys cannot be auto-generated");
|
|
keyValue = obj[keyExpr] = String(new Guid)
|
|
}
|
|
else if (this._array[this._indexByKey(keyValue)] !== undefined)
|
|
return rejectedPromise(Error("Attempt to insert an item with the duplicate key"))
|
|
}
|
|
else
|
|
keyValue = obj;
|
|
this._array.push(obj);
|
|
return trivialPromise(values, keyValue)
|
|
},
|
|
_updateImpl: function(key, values) {
|
|
var target;
|
|
if (this.key()) {
|
|
var index = this._indexByKey(key);
|
|
if (index < 0)
|
|
return rejectedPromise(Error("Data item not found"));
|
|
target = this._array[index]
|
|
}
|
|
else
|
|
target = key;
|
|
DX.utils.deepExtendArraySafe(target, values);
|
|
return trivialPromise(key, values)
|
|
},
|
|
_removeImpl: function(key) {
|
|
var index = this._indexByKey(key);
|
|
if (index > -1)
|
|
this._array.splice(index, 1);
|
|
return trivialPromise(key)
|
|
},
|
|
_indexByKey: function(key) {
|
|
for (var i = 0, arrayLength = this._array.length; i < arrayLength; i++)
|
|
if (data.utils.keysEqual(this.key(), this.keyOf(this._array[i]), key))
|
|
return i;
|
|
return -1
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.local.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
abstract = DX.abstract,
|
|
data = DX.data;
|
|
var LocalStoreBackend = Class.inherit({
|
|
ctor: function(store, storeOptions) {
|
|
this._store = store;
|
|
this._dirty = false;
|
|
var immediate = this._immediate = storeOptions.immediate;
|
|
var flushInterval = Math.max(100, storeOptions.flushInterval || 10 * 1000);
|
|
if (!immediate) {
|
|
var saveProxy = $.proxy(this.save, this);
|
|
setInterval(saveProxy, flushInterval);
|
|
$(window).on("beforeunload", saveProxy);
|
|
if (window.cordova)
|
|
document.addEventListener("pause", saveProxy, false)
|
|
}
|
|
},
|
|
notifyChanged: function() {
|
|
this._dirty = true;
|
|
if (this._immediate)
|
|
this.save()
|
|
},
|
|
load: function() {
|
|
this._store._array = this._loadImpl();
|
|
this._dirty = false
|
|
},
|
|
save: function() {
|
|
if (!this._dirty)
|
|
return;
|
|
this._saveImpl(this._store._array);
|
|
this._dirty = false
|
|
},
|
|
_loadImpl: abstract,
|
|
_saveImpl: abstract
|
|
});
|
|
var DomLocalStoreBackend = LocalStoreBackend.inherit({
|
|
ctor: function(store, storeOptions) {
|
|
this.callBase(store, storeOptions);
|
|
var name = storeOptions.name;
|
|
if (!name)
|
|
throw Error("Name is required");
|
|
this._key = "dx-data-localStore-" + name
|
|
},
|
|
_loadImpl: function() {
|
|
var raw = localStorage.getItem(this._key);
|
|
if (raw)
|
|
return JSON.parse(raw);
|
|
return []
|
|
},
|
|
_saveImpl: function(array) {
|
|
if (!array.length)
|
|
localStorage.removeItem(this._key);
|
|
else
|
|
localStorage.setItem(this._key, JSON.stringify(array))
|
|
}
|
|
});
|
|
var localStoreBackends = {dom: DomLocalStoreBackend};
|
|
data.LocalStore = data.ArrayStore.inherit({
|
|
ctor: function(options) {
|
|
if (typeof options === "string")
|
|
options = {name: options};
|
|
else
|
|
options = options || {};
|
|
this.callBase(options);
|
|
this._backend = new localStoreBackends[options.backend || "dom"](this, options);
|
|
this._backend.load()
|
|
},
|
|
clear: function() {
|
|
this._array = [];
|
|
this._backend.notifyChanged()
|
|
},
|
|
_insertImpl: function(values) {
|
|
var b = this._backend;
|
|
return this.callBase(values).done($.proxy(b.notifyChanged, b))
|
|
},
|
|
_updateImpl: function(key, values) {
|
|
var b = this._backend;
|
|
return this.callBase(key, values).done($.proxy(b.notifyChanged, b))
|
|
},
|
|
_removeImpl: function(key) {
|
|
var b = this._backend;
|
|
return this.callBase(key).done($.proxy(b.notifyChanged, b))
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.odata.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
data = DX.data,
|
|
odataUtils = data.utils.odata;
|
|
var escapeServiceOperationParams = function(params) {
|
|
if (!params)
|
|
return params;
|
|
var result = {};
|
|
$.each(params, function(k, v) {
|
|
result[k] = odataUtils.serializeValue(v)
|
|
});
|
|
return result
|
|
};
|
|
var convertSimpleKey = function(keyType, keyValue) {
|
|
var converter = odataUtils.keyConverters[keyType];
|
|
if (!converter)
|
|
throw Error("Unknown key type: " + keyType);
|
|
return converter(keyValue)
|
|
};
|
|
var SharedMethods = {
|
|
_extractServiceOptions: function(options) {
|
|
options = options || {};
|
|
this._url = String(options.url).replace(/\/+$/, "");
|
|
this._beforeSend = options.beforeSend;
|
|
this._jsonp = options.jsonp;
|
|
this._withCredentials = options.withCredentials
|
|
},
|
|
_sendRequest: function(url, method, params, payload) {
|
|
return odataUtils.sendRequest({
|
|
url: url,
|
|
method: method,
|
|
params: params || {},
|
|
payload: payload
|
|
}, {
|
|
beforeSend: this._beforeSend,
|
|
jsonp: this._jsonp,
|
|
withCredentials: this._withCredentials
|
|
})
|
|
}
|
|
};
|
|
var ODataStore = data.Store.inherit({
|
|
ctor: function(options) {
|
|
this.callBase(options);
|
|
this._extractServiceOptions(options);
|
|
this._keyType = options.keyType
|
|
},
|
|
_customLoadOptions: function() {
|
|
return ["expand", "customQueryParams"]
|
|
},
|
|
_byKeyImpl: function(key, extraOptions) {
|
|
var params = {};
|
|
if (extraOptions)
|
|
if (extraOptions.expand)
|
|
params["$expand"] = $.map($.makeArray(extraOptions.expand), odataUtils.serializePropName).join();
|
|
return this._sendRequest(this._byKeyUrl(key), "GET", params)
|
|
},
|
|
createQuery: function(loadOptions) {
|
|
loadOptions = loadOptions || {};
|
|
return data.query(this._url, {
|
|
beforeSend: this._beforeSend,
|
|
errorHandler: this._errorHandler,
|
|
jsonp: this._jsonp,
|
|
withCredentials: this._withCredentials,
|
|
params: escapeServiceOperationParams(loadOptions.customQueryParams),
|
|
expand: loadOptions.expand,
|
|
requireTotalCount: loadOptions.requireTotalCount
|
|
})
|
|
},
|
|
_insertImpl: function(values) {
|
|
this._requireKey();
|
|
var self = this,
|
|
d = $.Deferred();
|
|
$.when(this._sendRequest(this._url, "POST", null, values)).done(function(serverResponse) {
|
|
d.resolve(values, self.keyOf(serverResponse))
|
|
}).fail($.proxy(d.reject, d));
|
|
return d.promise()
|
|
},
|
|
_updateImpl: function(key, values) {
|
|
var d = $.Deferred();
|
|
$.when(this._sendRequest(this._byKeyUrl(key), "MERGE", null, values)).done(function() {
|
|
d.resolve(key, values)
|
|
}).fail($.proxy(d.reject, d));
|
|
return d.promise()
|
|
},
|
|
_removeImpl: function(key) {
|
|
var d = $.Deferred();
|
|
$.when(this._sendRequest(this._byKeyUrl(key), "DELETE")).done(function() {
|
|
d.resolve(key)
|
|
}).fail($.proxy(d.reject, d));
|
|
return d.promise()
|
|
},
|
|
_byKeyUrl: function(key) {
|
|
var keyType = this._keyType;
|
|
if ($.isPlainObject(keyType))
|
|
$.each(keyType, function(subKeyName, subKeyType) {
|
|
key[subKeyName] = convertSimpleKey(subKeyType, key[subKeyName])
|
|
});
|
|
else if (keyType)
|
|
key = convertSimpleKey(keyType, key);
|
|
return this._url + "(" + encodeURIComponent(odataUtils.serializeKey(key)) + ")"
|
|
}
|
|
}).include(SharedMethods);
|
|
var ODataContext = Class.inherit({
|
|
ctor: function(options) {
|
|
var self = this;
|
|
self._extractServiceOptions(options);
|
|
self._errorHandler = options.errorHandler;
|
|
$.each(options.entities || [], function(entityAlias, entityOptions) {
|
|
self[entityAlias] = new ODataStore($.extend({}, options, {url: self._url + "/" + encodeURIComponent(entityOptions.name || entityAlias)}, entityOptions))
|
|
})
|
|
},
|
|
get: function(operationName, params) {
|
|
return this.invoke(operationName, params, "GET")
|
|
},
|
|
invoke: function(operationName, params, httpMethod) {
|
|
httpMethod = httpMethod || "POST";
|
|
var d = $.Deferred();
|
|
$.when(this._sendRequest(this._url + "/" + encodeURIComponent(operationName), httpMethod, escapeServiceOperationParams(params))).done(function(r) {
|
|
if (r && operationName in r)
|
|
r = r[operationName];
|
|
d.resolve(r)
|
|
}).fail([this._errorHandler, data._handleError, $.proxy(d.reject, d)]);
|
|
return d.promise()
|
|
},
|
|
objectLink: function(entityAlias, key) {
|
|
var store = this[entityAlias];
|
|
if (!store)
|
|
throw Error("Unknown entity name or alias: " + entityAlias);
|
|
return {__metadata: {uri: store._byKeyUrl(key)}}
|
|
}
|
|
}).include(SharedMethods);
|
|
$.extend(data, {
|
|
ODataStore: ODataStore,
|
|
ODataContext: ODataContext
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.rest.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data;
|
|
function createAjaxFailureHandler(deferred) {
|
|
return function(xhr, textStatus) {
|
|
if (!xhr || !xhr.getResponseHeader)
|
|
deferred.reject.apply(deferred, arguments);
|
|
else
|
|
deferred.reject(Error(data.utils.errorMessageFromXhr(xhr, textStatus)))
|
|
}
|
|
}
|
|
function operationCustomizerPropName(operationName) {
|
|
return "_customize" + DX.inflector.camelize(operationName, true)
|
|
}
|
|
function pathPropName(operationName) {
|
|
return "_" + operationName + "Path"
|
|
}
|
|
data.RestStore = data.Store.inherit({
|
|
ctor: function(options) {
|
|
DX.utils.logger.warn("RestStore is deprecated, use CustomStore instead");
|
|
var self = this;
|
|
self.callBase(options);
|
|
options = options || {};
|
|
self._url = String(options.url).replace(/\/+$/, "");
|
|
self._jsonp = options.jsonp;
|
|
self._withCredentials = options.withCredentials;
|
|
$.each(["Load", "Insert", "Update", "Remove", "ByKey", "Operation"], function() {
|
|
var value = options["customize" + this];
|
|
if (value)
|
|
self[operationCustomizerPropName(this)] = value
|
|
});
|
|
$.each(["load", "insert", "update", "remove", "byKey"], function() {
|
|
var value = options[this + "Path"];
|
|
if (value)
|
|
self[pathPropName(this)] = value
|
|
})
|
|
},
|
|
_loadImpl: function(options) {
|
|
var d = $.Deferred(),
|
|
ajaxOptions = {
|
|
url: this._formatUrlNoKey("load"),
|
|
type: "GET"
|
|
};
|
|
$.when(this._createAjax(ajaxOptions, "load", options)).done($.proxy(d.resolve, d)).fail(createAjaxFailureHandler(d));
|
|
return this._addFailHandlers(d.promise())
|
|
},
|
|
createQuery: function() {
|
|
throw Error("Not supported");
|
|
},
|
|
_insertImpl: function(values) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
ajaxOptions = {
|
|
url: this._formatUrlNoKey("insert"),
|
|
type: "POST",
|
|
contentType: "application/json",
|
|
data: JSON.stringify(values)
|
|
};
|
|
$.when(this._createAjax(ajaxOptions, "insert")).done(function(serverResponse) {
|
|
d.resolve(values, self.key() && self.keyOf(serverResponse))
|
|
}).fail(createAjaxFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_updateImpl: function(key, values) {
|
|
var d = $.Deferred(),
|
|
ajaxOptions = {
|
|
url: this._formatUrlWithKey("update", key),
|
|
type: "PUT",
|
|
contentType: "application/json",
|
|
data: JSON.stringify(values)
|
|
};
|
|
$.when(this._createAjax(ajaxOptions, "update")).done(function() {
|
|
d.resolve(key, values)
|
|
}).fail(createAjaxFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_removeImpl: function(key) {
|
|
var d = $.Deferred(),
|
|
ajaxOptions = {
|
|
url: this._formatUrlWithKey("remove", key),
|
|
type: "DELETE"
|
|
};
|
|
$.when(this._createAjax(ajaxOptions, "remove")).done(function() {
|
|
d.resolve(key)
|
|
}).fail(createAjaxFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_byKeyImpl: function(key) {
|
|
var d = $.Deferred(),
|
|
ajaxOptions = {
|
|
url: this._formatUrlWithKey("byKey", key),
|
|
type: "GET"
|
|
};
|
|
$.when(this._createAjax(ajaxOptions, "byKey")).done(function(data) {
|
|
d.resolve(data)
|
|
}).fail(createAjaxFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_createAjax: function(ajaxOptions, operationName, extra) {
|
|
var customizationFunc,
|
|
customizationResult;
|
|
function isDeferred(obj) {
|
|
return "done" in obj && "fail" in obj
|
|
}
|
|
if (this._jsonp && ajaxOptions.type === "GET")
|
|
ajaxOptions.dataType = "jsonp";
|
|
else
|
|
$.extend(true, ajaxOptions, {xhrFields: {withCredentials: this._withCredentials}});
|
|
customizationFunc = this[operationCustomizerPropName("operation")];
|
|
if (customizationFunc) {
|
|
customizationResult = customizationFunc(ajaxOptions, operationName, extra);
|
|
if (customizationResult) {
|
|
if (isDeferred(customizationResult))
|
|
return customizationResult;
|
|
ajaxOptions = customizationResult
|
|
}
|
|
}
|
|
customizationFunc = this[operationCustomizerPropName(operationName)];
|
|
if (customizationFunc) {
|
|
customizationResult = customizationFunc(ajaxOptions, extra);
|
|
if (customizationResult) {
|
|
if (isDeferred(customizationResult))
|
|
return customizationResult;
|
|
ajaxOptions = customizationResult
|
|
}
|
|
}
|
|
return $.ajax(ajaxOptions)
|
|
},
|
|
_formatUrlNoKey: function(operationName) {
|
|
var url = this._url,
|
|
path = this[pathPropName(operationName)];
|
|
if (!path)
|
|
return url;
|
|
if ($.isFunction(path))
|
|
return path(url);
|
|
return url + "/" + path
|
|
},
|
|
_formatUrlWithKey: function(operationName, key) {
|
|
var url = this._url,
|
|
path = this[pathPropName(operationName)];
|
|
if (!path)
|
|
return url + "/" + encodeURIComponent(key);
|
|
if ($.isFunction(path))
|
|
return path(url, key);
|
|
return url + "/" + path + "/" + encodeURIComponent(key)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.store.custom.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data;
|
|
var ERROR_QUERY_NOT_SUPPORTED = "CustomStore does not support creating queries",
|
|
ERROR_MISSING_USER_FUNC = "Required option is not specified or is not a function: ",
|
|
ERROR_INVALID_RETURN = "Invalid return value: ";
|
|
var TOTAL_COUNT = "totalCount",
|
|
LOAD = "load",
|
|
BY_KEY = "byKey",
|
|
INSERT = "insert",
|
|
UPDATE = "update",
|
|
REMOVE = "remove";
|
|
function isPromise(obj) {
|
|
return obj && $.isFunction(obj.done) && $.isFunction(obj.fail) && $.isFunction(obj.promise)
|
|
}
|
|
function trivialPromise(value) {
|
|
return $.Deferred().resolve(value).promise()
|
|
}
|
|
function ensureRequiredFuncOption(name, obj) {
|
|
if (!$.isFunction(obj))
|
|
throw Error(ERROR_MISSING_USER_FUNC + name);
|
|
}
|
|
function throwInvalidUserFuncResult(name) {
|
|
throw Error(ERROR_INVALID_RETURN + name);
|
|
}
|
|
function createUserFuncFailureHandler(pendingDeferred) {
|
|
function errorMessageFromXhr(promiseArguments) {
|
|
var xhr = promiseArguments[0],
|
|
textStatus = promiseArguments[1];
|
|
if (!xhr || !xhr.getResponseHeader)
|
|
return null;
|
|
return data.utils.errorMessageFromXhr(xhr, textStatus)
|
|
}
|
|
return function(arg) {
|
|
var error;
|
|
if (arg instanceof Error)
|
|
error = arg;
|
|
else
|
|
error = Error(errorMessageFromXhr(arguments) || arg && String(arg) || "Unknown error");
|
|
pendingDeferred.reject(error)
|
|
}
|
|
}
|
|
data.CustomStore = data.Store.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.callBase(options);
|
|
this._useDefaultSearch = false;
|
|
this._loadFunc = options[LOAD];
|
|
this._totalCountFunc = options[TOTAL_COUNT];
|
|
this._byKeyFunc = options[BY_KEY] || options.lookup;
|
|
this._insertFunc = options[INSERT];
|
|
this._updateFunc = options[UPDATE];
|
|
this._removeFunc = options[REMOVE]
|
|
},
|
|
createQuery: function() {
|
|
throw Error(ERROR_QUERY_NOT_SUPPORTED);
|
|
},
|
|
_totalCountImpl: function(options) {
|
|
var userFunc = this._totalCountFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(TOTAL_COUNT, userFunc);
|
|
userResult = userFunc(options);
|
|
if (!isPromise(userResult)) {
|
|
userResult = Number(userResult);
|
|
if (!isFinite(userResult))
|
|
throwInvalidUserFuncResult(TOTAL_COUNT);
|
|
userResult = trivialPromise(userResult)
|
|
}
|
|
userResult.done(function(count) {
|
|
d.resolve(Number(count))
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_loadImpl: function(options) {
|
|
var userFunc = this._loadFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(LOAD, userFunc);
|
|
userResult = userFunc(options);
|
|
if ($.isArray(userResult))
|
|
userResult = trivialPromise(userResult);
|
|
else if (userResult === null || userResult === undefined)
|
|
userResult = trivialPromise([]);
|
|
else if (!isPromise(userResult))
|
|
throwInvalidUserFuncResult(LOAD);
|
|
userResult.done(function(data, extra) {
|
|
d.resolve(data, extra)
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return this._addFailHandlers(d.promise())
|
|
},
|
|
_byKeyImpl: function(key) {
|
|
var userFunc = this._byKeyFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(BY_KEY, userFunc);
|
|
userResult = userFunc(key);
|
|
if (!isPromise(userResult))
|
|
userResult = trivialPromise(userResult);
|
|
userResult.done(function(obj) {
|
|
d.resolve(obj)
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_insertImpl: function(values) {
|
|
var userFunc = this._insertFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(INSERT, userFunc);
|
|
userResult = userFunc(values);
|
|
if (!isPromise(userResult))
|
|
userResult = trivialPromise(userResult);
|
|
userResult.done(function(newKey) {
|
|
d.resolve(values, newKey)
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_updateImpl: function(key, values) {
|
|
var userFunc = this._updateFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(UPDATE, userFunc);
|
|
userResult = userFunc(key, values);
|
|
if (!isPromise(userResult))
|
|
userResult = trivialPromise();
|
|
userResult.done(function() {
|
|
d.resolve(key, values)
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return d.promise()
|
|
},
|
|
_removeImpl: function(key) {
|
|
var userFunc = this._removeFunc,
|
|
userResult,
|
|
d = $.Deferred();
|
|
ensureRequiredFuncOption(REMOVE, userFunc);
|
|
userResult = userFunc(key);
|
|
if (!isPromise(userResult))
|
|
userResult = trivialPromise();
|
|
userResult.done(function() {
|
|
d.resolve(key)
|
|
}).fail(createUserFuncFailureHandler(d));
|
|
return d.promise()
|
|
}
|
|
});
|
|
data.CustomStore_internals = {ERRORS: {
|
|
QUERY_NOT_SUPPORTED: ERROR_QUERY_NOT_SUPPORTED,
|
|
MISSING_USER_FUNC: ERROR_MISSING_USER_FUNC,
|
|
INVALID_RETURN: ERROR_INVALID_RETURN
|
|
}}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file data.dataSource.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data,
|
|
CustomStore = data.CustomStore,
|
|
Class = DX.Class;
|
|
var storeTypeRegistry = {
|
|
jaydata: "JayDataStore",
|
|
breeze: "BreezeStore",
|
|
odata: "ODataStore",
|
|
local: "LocalStore",
|
|
array: "ArrayStore"
|
|
};
|
|
function normalizeDataSourceOptions(options) {
|
|
var store;
|
|
function createCustomStoreFromLoadFunc() {
|
|
var storeConfig = {};
|
|
$.each(["load", "byKey", "lookup", "totalCount", "insert", "update", "remove"], function() {
|
|
storeConfig[this] = options[this];
|
|
delete options[this]
|
|
});
|
|
return new CustomStore(storeConfig)
|
|
}
|
|
function createStoreFromConfig(storeConfig) {
|
|
var storeCtor = data[storeTypeRegistry[storeConfig.type]];
|
|
delete storeConfig.type;
|
|
return new storeCtor(storeConfig)
|
|
}
|
|
function createCustomStoreFromUrl(url) {
|
|
return new CustomStore({load: function() {
|
|
return $.getJSON(url)
|
|
}})
|
|
}
|
|
if (typeof options === "string")
|
|
options = createCustomStoreFromUrl(options);
|
|
if (options === undefined)
|
|
options = [];
|
|
if ($.isArray(options) || options instanceof data.Store)
|
|
options = {store: options};
|
|
else
|
|
options = $.extend({}, options);
|
|
store = options.store;
|
|
if ("load" in options)
|
|
store = createCustomStoreFromLoadFunc();
|
|
else if ($.isArray(store))
|
|
store = new data.ArrayStore(store);
|
|
else if ($.isPlainObject(store))
|
|
store = createStoreFromConfig($.extend({}, store));
|
|
options.store = store;
|
|
return options
|
|
}
|
|
function normalizeStoreLoadOptionAccessorArguments(originalArguments) {
|
|
switch (originalArguments.length) {
|
|
case 0:
|
|
return undefined;
|
|
case 1:
|
|
return originalArguments[0]
|
|
}
|
|
return $.makeArray(originalArguments)
|
|
}
|
|
function generateStoreLoadOptionAccessor(optionName) {
|
|
return function() {
|
|
var args = normalizeStoreLoadOptionAccessorArguments(arguments);
|
|
if (args !== undefined)
|
|
this._storeLoadOptions[optionName] = args;
|
|
return this._storeLoadOptions[optionName]
|
|
}
|
|
}
|
|
function addOldUserDataSourceBackwardCompatibilityOptions(dataSource, storeLoadOptions) {
|
|
storeLoadOptions.refresh = !dataSource._paginate || dataSource._pageIndex === 0;
|
|
if (storeLoadOptions.searchValue !== null)
|
|
storeLoadOptions.searchString = storeLoadOptions.searchValue
|
|
}
|
|
var DataSource = Class.inherit({
|
|
ctor: function(options) {
|
|
options = normalizeDataSourceOptions(options);
|
|
this._store = options.store;
|
|
this._storeLoadOptions = this._extractLoadOptions(options);
|
|
this._mapFunc = options.map;
|
|
this._postProcessFunc = options.postProcess;
|
|
this._pageIndex = 0;
|
|
this._pageSize = options.pageSize !== undefined ? options.pageSize : 20;
|
|
this._items = [];
|
|
this._totalCount = -1;
|
|
this._isLoaded = false;
|
|
this._loadingCount = 0;
|
|
this._preferSync = options._preferSync;
|
|
this._loadQueue = this._createLoadQueue();
|
|
this._searchValue = "searchValue" in options ? options.searchValue : null;
|
|
this._searchOperation = options.searchOperation || "contains";
|
|
this._searchExpr = options.searchExpr;
|
|
this._paginate = options.paginate;
|
|
if (this._paginate === undefined)
|
|
this._paginate = !this.group();
|
|
this._isLastPage = !this._paginate;
|
|
this._userData = {};
|
|
this.changed = $.Callbacks();
|
|
this.loadError = $.Callbacks();
|
|
this.loadingChanged = $.Callbacks()
|
|
},
|
|
dispose: function() {
|
|
this.changed.empty();
|
|
this.loadError.empty();
|
|
this.loadingChanged.empty();
|
|
delete this._store;
|
|
this._disposed = true
|
|
},
|
|
_extractLoadOptions: function(options) {
|
|
var result = {},
|
|
names = ["sort", "filter", "select", "group", "requireTotalCount"],
|
|
customNames = this._store._customLoadOptions();
|
|
if (customNames)
|
|
names = names.concat(customNames);
|
|
$.each(names, function() {
|
|
result[this] = options[this]
|
|
});
|
|
return result
|
|
},
|
|
loadOptions: function() {
|
|
return this._storeLoadOptions
|
|
},
|
|
items: function() {
|
|
return this._items
|
|
},
|
|
pageIndex: function(newIndex) {
|
|
if (newIndex !== undefined) {
|
|
this._pageIndex = newIndex;
|
|
this._isLastPage = !this._paginate
|
|
}
|
|
return this._pageIndex
|
|
},
|
|
isLastPage: function() {
|
|
return this._isLastPage
|
|
},
|
|
sort: generateStoreLoadOptionAccessor("sort"),
|
|
filter: function() {
|
|
var newFilter = normalizeStoreLoadOptionAccessorArguments(arguments);
|
|
if (newFilter !== undefined) {
|
|
this._storeLoadOptions.filter = newFilter;
|
|
this.pageIndex(0)
|
|
}
|
|
return this._storeLoadOptions.filter
|
|
},
|
|
group: generateStoreLoadOptionAccessor("group"),
|
|
select: generateStoreLoadOptionAccessor("select"),
|
|
searchValue: function(value) {
|
|
if (value !== undefined)
|
|
this._searchValue = value;
|
|
return this._searchValue
|
|
},
|
|
searchOperation: function(op) {
|
|
if (op !== undefined)
|
|
this._searchOperation = op;
|
|
return this._searchOperation
|
|
},
|
|
searchExpr: function(expr) {
|
|
var argc = arguments.length;
|
|
if (argc) {
|
|
if (argc > 1)
|
|
expr = $.makeArray(arguments);
|
|
this._searchExpr = expr
|
|
}
|
|
return this._searchExpr
|
|
},
|
|
store: function() {
|
|
return this._store
|
|
},
|
|
key: function() {
|
|
return this._store && this._store.key()
|
|
},
|
|
totalCount: function() {
|
|
return this._totalCount
|
|
},
|
|
isLoaded: function() {
|
|
return this._isLoaded
|
|
},
|
|
isLoading: function() {
|
|
return this._loadingCount > 0
|
|
},
|
|
_createLoadQueue: function() {
|
|
return DX.createQueue()
|
|
},
|
|
_changeLoadingCount: function(increment) {
|
|
var oldLoading = this.isLoading(),
|
|
newLoading;
|
|
this._loadingCount += increment;
|
|
newLoading = this.isLoading();
|
|
if (oldLoading ^ newLoading)
|
|
this.loadingChanged.fire(newLoading)
|
|
},
|
|
_scheduleLoadCallbacks: function(deferred) {
|
|
var thisSource = this;
|
|
thisSource._changeLoadingCount(1);
|
|
deferred.always(function() {
|
|
thisSource._changeLoadingCount(-1)
|
|
})
|
|
},
|
|
_scheduleChangedCallbacks: function(deferred) {
|
|
var self = this;
|
|
deferred.done(function() {
|
|
self.changed.fire()
|
|
})
|
|
},
|
|
load: function() {
|
|
var thisSource = this,
|
|
d = $.Deferred(),
|
|
errorCallback = this.loadError,
|
|
storeLoadOptions;
|
|
this._scheduleLoadCallbacks(d);
|
|
this._scheduleChangedCallbacks(d);
|
|
storeLoadOptions = this._createStoreLoadOptions();
|
|
function loadTask() {
|
|
if (thisSource._disposed)
|
|
return undefined;
|
|
return thisSource._loadFromStore(storeLoadOptions, d)
|
|
}
|
|
this._loadQueue.add(function() {
|
|
loadTask();
|
|
return d.promise()
|
|
}, function() {
|
|
thisSource._changeLoadingCount(-1)
|
|
});
|
|
return d.promise().fail($.proxy(errorCallback.fire, errorCallback))
|
|
},
|
|
_addSearchOptions: function(storeLoadOptions) {
|
|
if (this._disposed)
|
|
return;
|
|
if (this.store()._useDefaultSearch)
|
|
this._addSearchFilter(storeLoadOptions);
|
|
else {
|
|
storeLoadOptions.searchValue = this._searchValue;
|
|
storeLoadOptions.searchExpr = this._searchExpr
|
|
}
|
|
},
|
|
_createStoreLoadOptions: function() {
|
|
var result = $.extend({}, this._storeLoadOptions);
|
|
this._addSearchOptions(result);
|
|
if (this._paginate) {
|
|
result.pageIndex = this._pageIndex;
|
|
if (this._pageSize) {
|
|
result.skip = this._pageIndex * this._pageSize;
|
|
result.take = this._pageSize
|
|
}
|
|
}
|
|
result.userData = this._userData;
|
|
addOldUserDataSourceBackwardCompatibilityOptions(this, result);
|
|
return result
|
|
},
|
|
_addSearchFilter: function(storeLoadOptions) {
|
|
var value = this._searchValue,
|
|
op = this._searchOperation,
|
|
selector = this._searchExpr,
|
|
searchFilter = [];
|
|
if (!value)
|
|
return;
|
|
if (!selector)
|
|
selector = "this";
|
|
if (!$.isArray(selector))
|
|
selector = [selector];
|
|
$.each(selector, function(i, item) {
|
|
if (searchFilter.length)
|
|
searchFilter.push("or");
|
|
searchFilter.push([item, op, value])
|
|
});
|
|
if (storeLoadOptions.filter)
|
|
storeLoadOptions.filter = [searchFilter, storeLoadOptions.filter];
|
|
else
|
|
storeLoadOptions.filter = searchFilter
|
|
},
|
|
_loadFromStore: function(storeLoadOptions, pendingDeferred) {
|
|
var thisSource = this;
|
|
function handleSuccess(data, extra) {
|
|
function processResult() {
|
|
thisSource._processStoreLoadResult(data, extra, storeLoadOptions, pendingDeferred)
|
|
}
|
|
if (thisSource._preferSync)
|
|
processResult();
|
|
else
|
|
DX.utils.executeAsync(processResult)
|
|
}
|
|
return this.store().load(storeLoadOptions).done(handleSuccess).fail($.proxy(pendingDeferred.reject, pendingDeferred))
|
|
},
|
|
_processStoreLoadResult: function(data, extra, storeLoadOptions, pendingDeferred) {
|
|
var thisSource = this;
|
|
function resolvePendingDeferred() {
|
|
thisSource._isLoaded = true;
|
|
thisSource._totalCount = isFinite(extra.totalCount) ? extra.totalCount : -1;
|
|
return pendingDeferred.resolve(data, extra)
|
|
}
|
|
function proceedLoadingTotalCount() {
|
|
thisSource.store().totalCount(storeLoadOptions).done(function(count) {
|
|
extra.totalCount = count;
|
|
resolvePendingDeferred()
|
|
}).fail(function(){})
|
|
}
|
|
if (thisSource._disposed)
|
|
return;
|
|
data = thisSource._transformLoadedData(data);
|
|
if (!$.isPlainObject(extra))
|
|
extra = {};
|
|
thisSource._items = data;
|
|
if (!data.length || !thisSource._paginate || thisSource._pageSize && data.length < thisSource._pageSize)
|
|
thisSource._isLastPage = true;
|
|
if (storeLoadOptions.requireTotalCount && !isFinite(extra.totalCount))
|
|
proceedLoadingTotalCount();
|
|
else
|
|
resolvePendingDeferred()
|
|
},
|
|
_transformLoadedData: function(data) {
|
|
var result = $.makeArray(data);
|
|
if (this._mapFunc)
|
|
result = $.map(result, this._mapFunc);
|
|
if (this._postProcessFunc)
|
|
result = this._postProcessFunc(result);
|
|
return result
|
|
}
|
|
});
|
|
data.Store.redefine({toDataSource: function(options) {
|
|
DX.utils.logger.warn("toDataSource() method is deprecated, use 'new DevExpress.data.DataSource(...)' instead");
|
|
return new DataSource($.extend({store: this}, options))
|
|
}});
|
|
$.extend(true, data, {
|
|
DataSource: DataSource,
|
|
createDataSource: function(options) {
|
|
DX.utils.logger.warn("createDataSource() method is deprecated, use 'new DevExpress.data.DataSource(...)' instead");
|
|
return new DataSource(options)
|
|
},
|
|
utils: {
|
|
storeTypeRegistry: storeTypeRegistry,
|
|
normalizeDataSourceOptions: normalizeDataSourceOptions
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file social.js */
|
|
DevExpress.social = {};
|
|
/*! Module core, file facebook.js */
|
|
(function($, DX, undefined) {
|
|
function notifyDeprecated() {
|
|
DX.utils.logger.warn("DevExpress.social API is deprecated. Use official Facebook library instead")
|
|
}
|
|
var social = DX.social;
|
|
var location = window.location,
|
|
navigator = window.navigator,
|
|
encodeURIComponent = window.encodeURIComponent,
|
|
decodeURIComponent = window.decodeURIComponent,
|
|
iosStandaloneMode = navigator.standalone,
|
|
cordovaMode = false;
|
|
if (window.cordova)
|
|
$(document).on("deviceready", function() {
|
|
cordovaMode = true
|
|
});
|
|
var ACCESS_TOKEN_KEY = "dx-facebook-access-token",
|
|
IOS_STANDALONE_STEP1_KEY = "dx-facebook-step1",
|
|
IOS_STANDALONE_STEP2_KEY = "dx-facebook-step2";
|
|
var accessToken = null,
|
|
expires = null,
|
|
connectionChanged = $.Callbacks();
|
|
var pendingLoginRedirectUrl;
|
|
var isConnected = function() {
|
|
return !!accessToken
|
|
};
|
|
var getAccessTokenObject = function() {
|
|
return {
|
|
accessToken: accessToken,
|
|
expiresIn: accessToken ? expires : 0
|
|
}
|
|
};
|
|
var FB = social.Facebook = {
|
|
loginRedirectUrl: "FacebookLoginCallback.html",
|
|
connectionChanged: connectionChanged,
|
|
isConnected: isConnected,
|
|
getAccessTokenObject: getAccessTokenObject,
|
|
jsonp: false
|
|
};
|
|
var login = function(appId, options) {
|
|
notifyDeprecated();
|
|
options = options || {};
|
|
if (cordovaMode)
|
|
pendingLoginRedirectUrl = "https://www.facebook.com/connect/login_success.html";
|
|
else
|
|
pendingLoginRedirectUrl = formatLoginRedirectUrl();
|
|
var scope = (options.permissions || []).join(),
|
|
url = "https://www.facebook.com/dialog/oauth?display=popup&client_id=" + appId + "&redirect_uri=" + encodeURIComponent(pendingLoginRedirectUrl) + "&scope=" + encodeURIComponent(scope) + "&response_type=token";
|
|
if (iosStandaloneMode)
|
|
putData(IOS_STANDALONE_STEP1_KEY, location.href);
|
|
if (cordovaMode)
|
|
startLogin_cordova(url);
|
|
else
|
|
startLogin_browser(url)
|
|
};
|
|
var formatLoginRedirectUrl = function() {
|
|
var pathSegments = location.pathname.split(/\//g);
|
|
pathSegments.pop();
|
|
pathSegments.push(FB.loginRedirectUrl);
|
|
return location.protocol + "//" + location.host + pathSegments.join("/")
|
|
};
|
|
var startLogin_browser = function(loginUrl) {
|
|
var width = 512,
|
|
height = 320,
|
|
left = (screen.width - width) / 2,
|
|
top = (screen.height - height) / 2;
|
|
window.open(loginUrl, null, "width=" + width + ",height=" + height + ",toolbar=0,scrollbars=0,status=0,resizable=0,menuBar=0,left=" + left + ",top=" + top)
|
|
};
|
|
var startLogin_cordova = function(loginUrl) {
|
|
var ref = window.open(loginUrl, "_blank");
|
|
ref.addEventListener('exit', function(event) {
|
|
pendingLoginRedirectUrl = null
|
|
});
|
|
ref.addEventListener('loadstop', function(event) {
|
|
var url = unescape(event.url);
|
|
if (url.indexOf(pendingLoginRedirectUrl) === 0) {
|
|
ref.close();
|
|
_processLoginRedirectUrl(url)
|
|
}
|
|
})
|
|
};
|
|
var handleLoginRedirect = function() {
|
|
var opener = window.opener;
|
|
if (iosStandaloneMode) {
|
|
putData(IOS_STANDALONE_STEP2_KEY, location.href);
|
|
location.href = getData(IOS_STANDALONE_STEP1_KEY)
|
|
}
|
|
else if (opener && opener.DevExpress) {
|
|
opener.DevExpress.social.Facebook._processLoginRedirectUrl(location.href);
|
|
window.close()
|
|
}
|
|
};
|
|
var _processLoginRedirectUrl = function(url) {
|
|
var params = parseUrlFragment(url);
|
|
expires = params.expires_in;
|
|
changeToken(params.access_token);
|
|
pendingLoginRedirectUrl = null
|
|
};
|
|
var parseUrlFragment = function(url) {
|
|
var hash = url.split("#")[1];
|
|
if (!hash)
|
|
return {};
|
|
var pairs = hash.split(/&/g),
|
|
result = {};
|
|
$.each(pairs, function(i) {
|
|
var splitPair = this.split("=");
|
|
result[splitPair[0]] = decodeURIComponent(splitPair[1])
|
|
});
|
|
return result
|
|
};
|
|
var logout = function() {
|
|
notifyDeprecated();
|
|
changeToken(null)
|
|
};
|
|
var changeToken = function(value) {
|
|
if (value === accessToken)
|
|
return;
|
|
accessToken = value;
|
|
putData(ACCESS_TOKEN_KEY, value);
|
|
connectionChanged.fire(!!value)
|
|
};
|
|
var api = function(resource, method, params) {
|
|
notifyDeprecated();
|
|
if (!isConnected())
|
|
throw Error("Not connected");
|
|
if (typeof method !== "string") {
|
|
params = method;
|
|
method = undefined
|
|
}
|
|
method = (method || "get").toLowerCase();
|
|
var d = $.Deferred();
|
|
var args = arguments;
|
|
$.ajax({
|
|
url: "https://graph.facebook.com/" + resource,
|
|
type: method,
|
|
data: $.extend({access_token: accessToken}, params),
|
|
dataType: FB.jsonp && method === "get" ? "jsonp" : "json"
|
|
}).done(function(response) {
|
|
response = response || simulateErrorResponse();
|
|
if (response.error)
|
|
d.reject(response.error);
|
|
else
|
|
d.resolve(response)
|
|
}).fail(function(xhr) {
|
|
var response;
|
|
try {
|
|
response = $.parseJSON(xhr.responseText);
|
|
var tries = args[3] || 0;
|
|
if (tries++ < 3 && response.error.code == 190 && response.error.error_subcode == 466) {
|
|
setTimeout(function() {
|
|
api(resource, method, params, tries).done(function(result) {
|
|
d.resolve(result)
|
|
}).fail(function(error) {
|
|
d.reject(error)
|
|
})
|
|
}, 500);
|
|
return
|
|
}
|
|
}
|
|
catch(x) {
|
|
response = simulateErrorResponse()
|
|
}
|
|
d.reject(response.error)
|
|
});
|
|
return d.promise()
|
|
};
|
|
var simulateErrorResponse = function() {
|
|
return {error: {message: "Unknown error"}}
|
|
};
|
|
var ensureStorageBackend = function() {
|
|
if (!hasStorageBackend())
|
|
throw Error("HTML5 sessionStorage or jQuery.cookie plugin is required");
|
|
};
|
|
var hasStorageBackend = function() {
|
|
return !!($.cookie || window.sessionStorage)
|
|
};
|
|
var putData = function(key, data) {
|
|
ensureStorageBackend();
|
|
data = JSON.stringify(data);
|
|
if (window.sessionStorage)
|
|
if (data === null)
|
|
sess.removeItem(key);
|
|
else
|
|
sessionStorage.setItem(key, data);
|
|
else
|
|
$.cookie(key, data)
|
|
};
|
|
var getData = function(key) {
|
|
ensureStorageBackend();
|
|
try {
|
|
return JSON.parse(window.sessionStorage ? sessionStorage.getItem(key) : $.cookie(key))
|
|
}
|
|
catch(x) {
|
|
return null
|
|
}
|
|
};
|
|
if (hasStorageBackend())
|
|
accessToken = getData(ACCESS_TOKEN_KEY);
|
|
if (iosStandaloneMode) {
|
|
var url = getData(IOS_STANDALONE_STEP2_KEY);
|
|
if (url) {
|
|
_processLoginRedirectUrl(url);
|
|
putData(IOS_STANDALONE_STEP1_KEY, null);
|
|
putData(IOS_STANDALONE_STEP2_KEY, null)
|
|
}
|
|
}
|
|
$.extend(FB, {
|
|
login: login,
|
|
logout: logout,
|
|
handleLoginRedirect: handleLoginRedirect,
|
|
_processLoginRedirectUrl: _processLoginRedirectUrl,
|
|
api: api
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui = {};
|
|
var IOS7_APP_BAR_HEIGHT = "20px";
|
|
var initViewport = function(options) {
|
|
options = $.extend({}, options);
|
|
var device = DX.devices.current();
|
|
var allowZoom = options.allowZoom,
|
|
allowPan = options.allowPan,
|
|
allowSelection = "allowSelection" in options ? options.allowSelection : device.platform == "desktop";
|
|
DX.overlayTargetContainer(".dx-viewport");
|
|
var metaSelector = "meta[name=viewport]";
|
|
if (!$(metaSelector).length)
|
|
$("<meta />").attr("name", "viewport").appendTo("head");
|
|
var metaVerbs = ["width=device-width"],
|
|
msTouchVerbs = [];
|
|
if (allowZoom)
|
|
msTouchVerbs.push("pinch-zoom");
|
|
else
|
|
metaVerbs.push("initial-scale=1.0", "maximum-scale=1.0, user-scalable=no");
|
|
if (allowPan)
|
|
msTouchVerbs.push("pan-x", "pan-y");
|
|
if (!allowPan && !allowZoom)
|
|
$("html, body").css("overflow", "hidden");
|
|
else
|
|
$("html").css("-ms-overflow-style", "-ms-autohiding-scrollbar");
|
|
if (!allowSelection) {
|
|
if (DX.devices.real.ios)
|
|
$(document).on("selectstart", function() {
|
|
return false
|
|
});
|
|
$(".dx-viewport").css("user-select", "none")
|
|
}
|
|
$(metaSelector).attr("content", metaVerbs.join());
|
|
$("html").css("-ms-touch-action", msTouchVerbs.join(" ") || "none");
|
|
if (DX.support.touch)
|
|
$(document).off(".dxInitViewport").on("touchmove.dxInitViewport", function(e) {
|
|
var count = e.originalEvent.touches.length,
|
|
zoomDisabled = !allowZoom && count > 1,
|
|
panDisabled = !allowPan && count === 1 && !e.isScrollingEvent;
|
|
if (zoomDisabled || panDisabled)
|
|
e.preventDefault()
|
|
});
|
|
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
|
|
$(document.head).append($("<style/>").text("@-ms-viewport{ width: auto!important; user-zoom: fixed; max-zoom: 1; min-zoom: 1; }"));
|
|
$(window).bind("load resize", function(e) {
|
|
var TOP_BAR_W = 44,
|
|
TOP_BAR_H = 21,
|
|
ADDRESS_BAR_H = 72;
|
|
var isStandalone = 'Notify' in window.external;
|
|
var barWidth = isStandalone ? TOP_BAR_W : 0,
|
|
barHeight = isStandalone ? TOP_BAR_H : ADDRESS_BAR_H;
|
|
var actualHeight = $(window).width() < $(window).height() ? Math.round(screen.availHeight * (document.body.clientWidth / screen.availWidth)) - barHeight : Math.round(screen.availWidth * (document.body.clientHeight / screen.availHeight)) - barWidth;
|
|
document.body.style.setProperty("min-height", actualHeight + "px", "important")
|
|
})
|
|
}
|
|
if (DX.devices.real.ios && DX.devices.real.version[0] > 6) {
|
|
var isPhoneGap = document.location.protocol == "file:";
|
|
if (isPhoneGap) {
|
|
$(".dx-viewport").css("position", "relative");
|
|
$("body").css({
|
|
"box-sizing": "border-box",
|
|
"padding-top": IOS7_APP_BAR_HEIGHT
|
|
});
|
|
var setDeviceHeight = function() {
|
|
var deviceHeight = "height=device-" + (Math.abs(window.orientation) === 90 ? "width" : "height");
|
|
$(metaSelector).attr("content", metaVerbs.join() + "," + deviceHeight)
|
|
};
|
|
$(window).on("orientationchange", setDeviceHeight);
|
|
setDeviceHeight()
|
|
}
|
|
}
|
|
};
|
|
var TemplateProvider = DX.Class.inherit({
|
|
getTemplateClass: function() {
|
|
return Template
|
|
},
|
|
supportDefaultTemplate: function() {
|
|
return false
|
|
},
|
|
getDefaultTemplate: function() {
|
|
return null
|
|
}
|
|
});
|
|
var Template = DX.Class.inherit({
|
|
ctor: function(element) {
|
|
this._template = this._element = $(element).detach()
|
|
},
|
|
render: function(container) {
|
|
var renderedTemplate = this._template.clone();
|
|
container.append(renderedTemplate);
|
|
return renderedTemplate
|
|
},
|
|
dispose: $.noop
|
|
});
|
|
DX.registerActionExecutor({
|
|
designMode: {validate: function(e) {
|
|
if (DX.designMode)
|
|
e.canceled = true
|
|
}},
|
|
gesture: {validate: function(e) {
|
|
if (!e.args.length)
|
|
return;
|
|
var args = e.args[0],
|
|
element = args.itemElement || args.element;
|
|
while (element && element.length) {
|
|
if (element.data("dxGesture")) {
|
|
e.canceled = true;
|
|
break
|
|
}
|
|
element = element.parent()
|
|
}
|
|
}},
|
|
disabled: {validate: function(e) {
|
|
if (!e.args.length)
|
|
return;
|
|
var args = e.args[0],
|
|
element = args.itemElement || args.element;
|
|
if (element && element.is(".dx-state-disabled, .dx-state-disabled *"))
|
|
e.canceled = true
|
|
}}
|
|
});
|
|
$.extend(ui, {
|
|
TemplateProvider: TemplateProvider,
|
|
Template: Template,
|
|
initViewport: initViewport
|
|
});
|
|
ui.__internals = {Template: Template}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
eventNS = $.event,
|
|
specialNS = eventNS.special,
|
|
EVENT_SOURCES_REGEX = {
|
|
mouse: /^mouse/i,
|
|
touch: /^touch/i,
|
|
keyboard: /^key/i,
|
|
pointer: /pointer/i
|
|
};
|
|
var eventSource = function(e) {
|
|
var result = "other";
|
|
$.each(EVENT_SOURCES_REGEX, function(key) {
|
|
if (this.test(e.type)) {
|
|
result = key;
|
|
return false
|
|
}
|
|
});
|
|
return result
|
|
};
|
|
var isPointerEvent = function(e) {
|
|
return eventSource(e) === "pointer"
|
|
};
|
|
var isMouseEvent = function(e) {
|
|
return eventSource(e) === "mouse" || isPointerEvent(e) && e.pointerType === "mouse"
|
|
};
|
|
var isTouchEvent = function(e) {
|
|
return eventSource(e) === "touch" || isPointerEvent(e) && e.pointerType === "touch"
|
|
};
|
|
var isKeyboardEvent = function(e) {
|
|
return eventSource(e) === "keyboard"
|
|
};
|
|
var addNamespace = function(eventNames, namespace) {
|
|
if (!namespace)
|
|
throw Error("Namespace is not defined");
|
|
if (typeof eventNames === "string")
|
|
return addNamespace(eventNames.split(/\s+/g), namespace);
|
|
$.each(eventNames, function(index, eventName) {
|
|
eventNames[index] = eventName + "." + namespace
|
|
});
|
|
return eventNames.join(" ")
|
|
};
|
|
var eventData = function(e) {
|
|
if (isPointerEvent(e) && isTouchEvent(e)) {
|
|
var touch = (e.originalEvent.originalEvent || e.originalEvent).changedTouches[0];
|
|
return {
|
|
x: touch.pageX,
|
|
y: touch.pageY,
|
|
time: e.timeStamp
|
|
}
|
|
}
|
|
if (isMouseEvent(e))
|
|
return {
|
|
x: e.pageX,
|
|
y: e.pageY,
|
|
time: e.timeStamp
|
|
};
|
|
if (isTouchEvent(e)) {
|
|
var touch = (e.changedTouches || e.originalEvent.changedTouches)[0];
|
|
return {
|
|
x: touch.pageX,
|
|
y: touch.pageY,
|
|
time: e.timeStamp
|
|
}
|
|
}
|
|
};
|
|
var eventDelta = function(from, to) {
|
|
return {
|
|
x: to.x - from.x,
|
|
y: to.y - from.y,
|
|
time: to.time - from.time || 1
|
|
}
|
|
};
|
|
var hasTouches = function(e) {
|
|
if (isMouseEvent(e) || isPointerEvent(e))
|
|
return 0;
|
|
if (isTouchEvent(e))
|
|
return e.originalEvent.touches.length
|
|
};
|
|
var needSkipEvent = function(e) {
|
|
if (isMouseEvent(e))
|
|
return $(e.target).is("input, textarea, select") || e.which > 1;
|
|
if (isTouchEvent(e))
|
|
return (e.originalEvent.changedTouches || e.originalEvent.originalEvent.changedTouches).length !== 1
|
|
};
|
|
var createEvent = function(sourceEvent, props) {
|
|
var event = $.Event(sourceEvent, props),
|
|
originalEvent = event.originalEvent,
|
|
propNames = $.event.props.slice();
|
|
if (isMouseEvent(sourceEvent) || isTouchEvent(sourceEvent))
|
|
$.merge(propNames, $.event.mouseHooks.props);
|
|
if (isKeyboardEvent(sourceEvent))
|
|
$.merge(propNames, $.event.keyHooks.props);
|
|
if (originalEvent)
|
|
$.each(propNames, function() {
|
|
event[this] = originalEvent[this]
|
|
});
|
|
return event
|
|
};
|
|
var fireEvent = function(props) {
|
|
var event = createEvent(props.originalEvent, props);
|
|
$.event.trigger(event, null, props.target || event.target);
|
|
return event
|
|
};
|
|
var handleGestureEvent = function(e, type) {
|
|
var gestureEvent = $(e.target).data("dxGestureEvent");
|
|
if (!gestureEvent || gestureEvent === type) {
|
|
$(e.target).data("dxGestureEvent", type);
|
|
return true
|
|
}
|
|
return false
|
|
};
|
|
var registerEvent = function(eventName, eventObject) {
|
|
specialNS[eventName] = eventObject
|
|
};
|
|
ui.events = {
|
|
eventSource: eventSource,
|
|
isPointerEvent: isPointerEvent,
|
|
isMouseEvent: isMouseEvent,
|
|
isTouchEvent: isTouchEvent,
|
|
isKeyboardEvent: isKeyboardEvent,
|
|
addNamespace: addNamespace,
|
|
hasTouches: hasTouches,
|
|
eventData: eventData,
|
|
eventDelta: eventDelta,
|
|
needSkipEvent: needSkipEvent,
|
|
createEvent: createEvent,
|
|
fireEvent: fireEvent,
|
|
handleGestureEvent: handleGestureEvent,
|
|
registerEvent: registerEvent
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.component.js */
|
|
(function($, DX, undefined) {
|
|
var COMPONENT_NAMES_DATA_KEY = "dxComponents",
|
|
ui = DX.ui,
|
|
dataUtils = DX.data.utils;
|
|
var Component = DX.Class.inherit({
|
|
NAME: null,
|
|
_defaultOptions: function() {
|
|
return {disabled: false}
|
|
},
|
|
_optionsByReference: function() {
|
|
return {}
|
|
},
|
|
ctor: function(element, options) {
|
|
if (!this.NAME)
|
|
throw Error("NAME is not specified");
|
|
this._$element = $(element);
|
|
this._element().data(this.NAME, this);
|
|
if (!this._element().data(COMPONENT_NAMES_DATA_KEY))
|
|
this._element().data(COMPONENT_NAMES_DATA_KEY, []);
|
|
this._element().data(COMPONENT_NAMES_DATA_KEY).push(this.NAME);
|
|
this._options = {};
|
|
this._updateLockCount = 0;
|
|
this._requireRefresh = false;
|
|
this.optionChanged = $.Callbacks();
|
|
this.disposing = $.Callbacks();
|
|
this.beginUpdate();
|
|
try {
|
|
var device = DX.devices.current(),
|
|
optionsByDevice = ui.optionsByDevice(device, this.NAME) || {};
|
|
this.option(this._defaultOptions());
|
|
this.option(optionsByDevice);
|
|
this._initOptions(options || {})
|
|
}
|
|
finally {
|
|
this.endUpdate()
|
|
}
|
|
},
|
|
_initOptions: function(options) {
|
|
this.option(options)
|
|
},
|
|
_optionValuesEqual: function(name, oldValue, newValue) {
|
|
oldValue = dataUtils.toComparable(oldValue, true);
|
|
newValue = dataUtils.toComparable(newValue, true);
|
|
if (oldValue === null || typeof oldValue !== "object")
|
|
return oldValue === newValue;
|
|
return false
|
|
},
|
|
_init: $.noop,
|
|
_render: $.noop,
|
|
_clean: $.noop,
|
|
_modelByElement: $.noop,
|
|
_invalidate: function() {
|
|
if (!this._updateLockCount)
|
|
throw Error("Invalidate called outside update transaction");
|
|
this._requireRefresh = true
|
|
},
|
|
_refresh: function() {
|
|
this._clean();
|
|
this._render()
|
|
},
|
|
_dispose: function() {
|
|
this._clean();
|
|
this.optionChanged.empty();
|
|
this.disposing.fireWith(this).empty()
|
|
},
|
|
_createAction: function(actionSource, config) {
|
|
var self = this;
|
|
config = $.extend({}, config);
|
|
var element = config.element || self._element(),
|
|
model = self._modelByElement(element);
|
|
config.context = model || self;
|
|
config.component = self;
|
|
var action = new DX.Action(actionSource, config);
|
|
return function(e) {
|
|
if (!arguments.length)
|
|
e = {};
|
|
if (e instanceof $.Event)
|
|
throw Error("Action must be executed with jQuery.Event like action({ jQueryEvent: event })");
|
|
if (!$.isPlainObject(e))
|
|
e = {actionValue: e};
|
|
return action.execute.call(action, $.extend(e, {
|
|
component: self,
|
|
element: element,
|
|
model: model
|
|
}))
|
|
}
|
|
},
|
|
_createActionByOption: function(optionName, config) {
|
|
if (typeof optionName !== "string")
|
|
throw Error("Option name type is unexpected");
|
|
return this._createAction(this.option(optionName), config)
|
|
},
|
|
_optionChanged: function(name, value, prevValue){},
|
|
_element: function() {
|
|
return this._$element
|
|
},
|
|
instance: function() {
|
|
return this
|
|
},
|
|
beginUpdate: function() {
|
|
this._updateLockCount++
|
|
},
|
|
endUpdate: function() {
|
|
this._updateLockCount--;
|
|
if (!this._updateLockCount)
|
|
if (!this._initializing && !this._initialized) {
|
|
this._initializing = true;
|
|
try {
|
|
this._init()
|
|
}
|
|
finally {
|
|
this._initializing = false;
|
|
this._initialized = true
|
|
}
|
|
this._render()
|
|
}
|
|
else if (this._requireRefresh) {
|
|
this._requireRefresh = false;
|
|
this._refresh()
|
|
}
|
|
},
|
|
option: function(options) {
|
|
var self = this,
|
|
name = options,
|
|
value = arguments[1];
|
|
if (arguments.length < 2 && $.type(name) !== "object")
|
|
return dataUtils.compileGetter(name)(self._options, {functionsAsIs: true});
|
|
if (typeof name === "string") {
|
|
options = {};
|
|
options[name] = value
|
|
}
|
|
self.beginUpdate();
|
|
try {
|
|
$.each(options, function(name, value) {
|
|
var prevValue = dataUtils.compileGetter(name)(self._options, {functionsAsIs: true}),
|
|
topLevelName;
|
|
if (self._optionValuesEqual(name, prevValue, value))
|
|
return;
|
|
dataUtils.compileSetter(name)(self._options, value, {
|
|
functionsAsIs: true,
|
|
merge: !self._optionsByReference()[name]
|
|
});
|
|
topLevelName = name.split(/[.\[]/)[0];
|
|
if (self._initialized) {
|
|
self.optionChanged.fireWith(self, [topLevelName, value, prevValue]);
|
|
self._optionChanged(topLevelName, value, prevValue)
|
|
}
|
|
})
|
|
}
|
|
finally {
|
|
self.endUpdate()
|
|
}
|
|
}
|
|
});
|
|
var registerComponent = function(name, componentClass) {
|
|
ui[name] = componentClass;
|
|
componentClass.prototype.NAME = name;
|
|
$.fn[name] = function(options) {
|
|
var isMemberInvoke = typeof options === "string",
|
|
result = this;
|
|
if (isMemberInvoke) {
|
|
var memberName = options,
|
|
memberArgs = $.makeArray(arguments).slice(1);
|
|
this.each(function() {
|
|
var instance = $(this).data(name);
|
|
if (!instance)
|
|
throw Error(DX.utils.stringFormat("Component {0} has not been initialized on this element", name));
|
|
var member = instance[memberName],
|
|
memberValue = member.apply(instance, memberArgs);
|
|
if (memberValue !== undefined) {
|
|
result = memberValue;
|
|
return false
|
|
}
|
|
})
|
|
}
|
|
else
|
|
this.each(function() {
|
|
var instance = $(this).data(name);
|
|
if (instance)
|
|
instance.option(options);
|
|
else
|
|
new componentClass(this, options)
|
|
});
|
|
return result
|
|
}
|
|
};
|
|
var getComponents = function(element) {
|
|
element = $(element);
|
|
var names = element.data(COMPONENT_NAMES_DATA_KEY);
|
|
if (!names)
|
|
return [];
|
|
return $.map(names, function(name) {
|
|
return element.data(name)
|
|
})
|
|
};
|
|
var disposeComponents = function() {
|
|
$.each(getComponents(this), function() {
|
|
this._dispose()
|
|
})
|
|
};
|
|
var originalCleanData = $.cleanData;
|
|
$.cleanData = function(element) {
|
|
$.each(element, disposeComponents);
|
|
return originalCleanData.apply(this, arguments)
|
|
};
|
|
$.extend(ui, {
|
|
Component: Component,
|
|
registerComponent: registerComponent
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.knockoutIntegration.js */
|
|
(function($, DX, undefined) {
|
|
var ko = window.ko;
|
|
if (!DX.support.hasKo)
|
|
return;
|
|
(function checkKnockoutVersion(version) {
|
|
version = version.split(".");
|
|
if (version[0] < 2 || version[0] == 2 && version[1] < 3)
|
|
throw Error("Your version of KnockoutJS is too old. Please upgrade KnockoutJS to 2.3.0 or later.");
|
|
})(ko.version);
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
LOCKS_DATA_KEY = "dxKoLocks",
|
|
CREATED_WITH_KO_DATA_KEY = "dxKoCreation";
|
|
var Locks = function() {
|
|
var info = {};
|
|
var currentCount = function(lockName) {
|
|
return info[lockName] || 0
|
|
};
|
|
return {
|
|
obtain: function(lockName) {
|
|
info[lockName] = currentCount(lockName) + 1
|
|
},
|
|
release: function(lockName) {
|
|
var count = currentCount(lockName);
|
|
if (count < 1)
|
|
throw Error("Not locked");
|
|
if (count === 1)
|
|
delete info[lockName];
|
|
else
|
|
info[lockName] = count - 1
|
|
},
|
|
locked: function(lockName) {
|
|
return currentCount(lockName) > 0
|
|
}
|
|
}
|
|
};
|
|
var registerComponentKoBinding = function(componentName) {
|
|
ko.bindingHandlers[componentName] = {init: function(domNode, valueAccessor) {
|
|
var element = $(domNode),
|
|
ctorOptions = {},
|
|
optionNameToModelMap = {};
|
|
var applyModelValueToOption = function(optionName, modelValue) {
|
|
var component = element.data(componentName),
|
|
locks = element.data(LOCKS_DATA_KEY),
|
|
optionValue = ko.utils.unwrapObservable(modelValue);
|
|
if (!component) {
|
|
ctorOptions[optionName] = optionValue;
|
|
if (ko.isWriteableObservable(modelValue))
|
|
optionNameToModelMap[optionName] = modelValue
|
|
}
|
|
else {
|
|
if (locks.locked(optionName))
|
|
return;
|
|
locks.obtain(optionName);
|
|
try {
|
|
component.option(optionName, optionValue)
|
|
}
|
|
finally {
|
|
locks.release(optionName)
|
|
}
|
|
}
|
|
};
|
|
var handleOptionChanged = function(optionName, optionValue) {
|
|
if (!(optionName in optionNameToModelMap))
|
|
return;
|
|
var element = this._$element,
|
|
locks = element.data(LOCKS_DATA_KEY);
|
|
if (locks.locked(optionName))
|
|
return;
|
|
locks.obtain(optionName);
|
|
try {
|
|
optionNameToModelMap[optionName](optionValue)
|
|
}
|
|
finally {
|
|
locks.release(optionName)
|
|
}
|
|
};
|
|
ko.computed(function() {
|
|
var cmp = element.data(componentName);
|
|
if (cmp)
|
|
cmp.beginUpdate();
|
|
$.each(ko.unwrap(valueAccessor()), function(modelName, modelValueExpr) {
|
|
ko.computed(function() {
|
|
applyModelValueToOption(modelName, modelValueExpr)
|
|
}, null, {disposeWhenNodeIsRemoved: domNode})
|
|
});
|
|
if (cmp)
|
|
cmp.endUpdate()
|
|
}, null, {disposeWhenNodeIsRemoved: domNode});
|
|
if (ctorOptions) {
|
|
element.data(CREATED_WITH_KO_DATA_KEY, true);
|
|
element[componentName](ctorOptions);
|
|
ctorOptions = null;
|
|
element.data(LOCKS_DATA_KEY, new Locks);
|
|
element.data(componentName).optionChanged.add(handleOptionChanged)
|
|
}
|
|
return {controlsDescendantBindings: ui[componentName].subclassOf(ui.Widget)}
|
|
}}
|
|
};
|
|
var KoComponent = ui.Component.inherit({_modelByElement: function(element) {
|
|
if (element.length)
|
|
return ko.dataFor(element.get(0))
|
|
}});
|
|
var originalRegisterComponent = ui.registerComponent;
|
|
var registerKoComponent = function(name, componentClass) {
|
|
originalRegisterComponent(name, componentClass);
|
|
registerComponentKoBinding(name)
|
|
};
|
|
var KoTemplate = ui.Template.inherit({
|
|
ctor: function(element) {
|
|
this.callBase.apply(this, arguments);
|
|
this._template = $("<div>").append(element);
|
|
this._registerKoTemplate()
|
|
},
|
|
_cleanTemplateElement: function() {
|
|
this._element.each(function() {
|
|
ko.cleanNode(this)
|
|
})
|
|
},
|
|
_registerKoTemplate: function() {
|
|
var template = this._template.get(0);
|
|
new ko.templateSources.anonymousTemplate(template)['nodes'](template)
|
|
},
|
|
render: function(container, data) {
|
|
data = data !== undefined ? data : ko.dataFor(container.get(0)) || {};
|
|
var containerBindingContext = ko.contextFor(container[0]);
|
|
var bindingContext = containerBindingContext ? containerBindingContext.createChildContext(data) : data;
|
|
var renderBag = $("<div />").appendTo(container);
|
|
ko.renderTemplate(this._template.get(0), bindingContext, null, renderBag.get(0));
|
|
var result = renderBag.contents();
|
|
container.append(result);
|
|
renderBag.remove();
|
|
return result
|
|
},
|
|
dispose: function() {
|
|
this._template.remove()
|
|
}
|
|
});
|
|
var KoTemplateProvider = ui.TemplateProvider.inherit({
|
|
getTemplateClass: function() {
|
|
return KoTemplate
|
|
},
|
|
supportDefaultTemplate: function(widget) {
|
|
return this._createdWithKo(widget) ? true : this.callBase(widget)
|
|
},
|
|
getDefaultTemplate: function(widget) {
|
|
if (this._createdWithKo(widget))
|
|
return defaultKoTemplate(widget.NAME)
|
|
},
|
|
_createdWithKo: function(widget) {
|
|
return !!widget._element().data(CREATED_WITH_KO_DATA_KEY)
|
|
}
|
|
});
|
|
ko.bindingHandlers.dxAction = {update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
|
|
var $element = $(element);
|
|
var unwrappedValue = ko.utils.unwrapObservable(valueAccessor()),
|
|
actionSource = unwrappedValue,
|
|
actionOptions = {context: element};
|
|
if (unwrappedValue.execute) {
|
|
actionSource = unwrappedValue.execute;
|
|
$.extend(actionOptions, unwrappedValue)
|
|
}
|
|
var action = new DX.Action(actionSource, actionOptions);
|
|
$element.off(".dxActionBinding").on("dxclick.dxActionBinding", function(e) {
|
|
action.execute({
|
|
element: $element,
|
|
model: viewModel,
|
|
evaluate: function(expression) {
|
|
var context = viewModel;
|
|
if (expression.length > 0 && expression[0] === "$")
|
|
context = ko.contextFor(element);
|
|
var getter = DX.data.utils.compileGetter(expression);
|
|
return getter(context)
|
|
},
|
|
jQueryEvent: e
|
|
});
|
|
if (!actionOptions.bubbling)
|
|
e.stopPropagation()
|
|
})
|
|
}};
|
|
var defaultKoTemplate = function() {
|
|
var cache = {};
|
|
return function(widgetName) {
|
|
if (!DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName])
|
|
widgetName = "base";
|
|
if (!cache[widgetName]) {
|
|
var html = DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName](),
|
|
markup = DX.utils.createMarkupFromString(html);
|
|
cache[widgetName] = new KoTemplate(markup)
|
|
}
|
|
return cache[widgetName]
|
|
}
|
|
}();
|
|
var createElementWithBindAttr = function(tagName, bindings, closeTag, additionalProperties) {
|
|
closeTag = closeTag === undefined ? true : closeTag;
|
|
var bindAttr = $.map(bindings, function(value, key) {
|
|
return key + ":" + value
|
|
}).join(",");
|
|
additionalProperties = additionalProperties || "";
|
|
return "<" + tagName + " data-bind=\"" + bindAttr + "\" " + additionalProperties + ">" + (closeTag ? "</" + tagName + ">" : "")
|
|
};
|
|
var defaultKoTemplateBasicBindings = {css: "{ 'dx-state-disabled': $data.disabled, 'dx-state-invisible': !($data.visible === undefined || ko.unwrap($data.visible)) }"};
|
|
var DEFAULT_ITEM_TEMPLATE_GENERATORS = {base: function() {
|
|
var template = [createElementWithBindAttr("div", defaultKoTemplateBasicBindings, false)],
|
|
htmlBinding = createElementWithBindAttr("div", {html: "html"}),
|
|
textBinding = createElementWithBindAttr("div", {text: "text"}),
|
|
primitiveBinding = createElementWithBindAttr("div", {text: "String($data)"});
|
|
template.push("<!-- ko if: $data.html && !$data.text -->", htmlBinding, "<!-- /ko -->", "<!-- ko if: !$data.html && $data.text -->", textBinding, "<!-- /ko -->", "<!-- ko ifnot: $.isPlainObject($data) -->", primitiveBinding, "<!-- /ko -->", "</div>");
|
|
return template.join("")
|
|
}};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxPivotTabs = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
|
|
titleBinding = createElementWithBindAttr("span", {text: "title"});
|
|
var divInnerStart = template.indexOf(">") + 1,
|
|
divInnerFinish = template.length - 6;
|
|
template = [template.substring(0, divInnerStart), titleBinding, template.substring(divInnerFinish, template.length)];
|
|
return template.join("")
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxPanorama = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
|
|
headerBinding = createElementWithBindAttr("div", {text: "header"}, true, 'class="dx-panorama-item-header"');
|
|
var divInnerStart = template.indexOf(">") + 1;
|
|
template = [template.substring(0, divInnerStart), "<!-- ko if: $data.header -->", headerBinding, "<!-- /ko -->", template.substring(divInnerStart, template.length)];
|
|
return template.join("")
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxList = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
|
|
keyBinding = createElementWithBindAttr("div", {text: "key"});
|
|
template = [template.substring(0, template.length - 6), "<!-- ko if: $data.key -->" + keyBinding + "<!-- /ko -->", "</div>"];
|
|
return template.join("")
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxToolbar = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base();
|
|
template = [template.substring(0, template.length - 6), "<!-- ko if: $data.widget -->"];
|
|
$.each(["button", "tabs", "dropDownMenu"], function() {
|
|
var bindingName = DX.inflector.camelize(["dx", "-", this].join("")),
|
|
bindingObj = {};
|
|
bindingObj[bindingName] = "$data.options";
|
|
template.push("<!-- ko if: $data.widget === '", this, "' -->", createElementWithBindAttr("div", bindingObj), "<!-- /ko -->")
|
|
});
|
|
template.push("<!-- /ko -->");
|
|
return template.join("")
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxGallery = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
|
|
primitiveBinding = createElementWithBindAttr("div", {text: "String($data)"}),
|
|
imgBinding = createElementWithBindAttr("img", {attr: "{ src: String($data) }"}, false);
|
|
template = template.replace(primitiveBinding, imgBinding);
|
|
return template
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base(),
|
|
baseTextBinding = createElementWithBindAttr("div", {text: "text"}),
|
|
iconBinding = createElementWithBindAttr("span", {
|
|
attr: "{ 'class': 'dx-icon-' + $data.icon }",
|
|
css: "{ 'dx-icon': true }"
|
|
}),
|
|
iconSrcBinding = createElementWithBindAttr("img", {
|
|
attr: "{ src: $data.iconSrc }",
|
|
css: "{ 'dx-icon': true }"
|
|
}, false),
|
|
textBinding = "<!-- ko if: $data.icon -->" + iconBinding + "<!-- /ko -->" + "<!-- ko if: !$data.icon && $data.iconSrc -->" + iconSrcBinding + "<!-- /ko -->" + "<span class=\"dx-tab-text\" data-bind=\"text: $data.text\"></span>";
|
|
template = template.replace("<!-- ko if: !$data.html && $data.text -->", "<!-- ko if: !$data.html && ($data.text || $data.icon || $data.iconSrc) -->").replace(baseTextBinding, textBinding);
|
|
return template
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxActionSheet = function() {
|
|
return createElementWithBindAttr("div", {dxButton: "{ text: $data.text, clickAction: $data.clickAction, type: $data.type, disabled: !!ko.unwrap($data.disabled) }"})
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxNavBar = DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs;
|
|
var cleanKoData = function(element, andSelf) {
|
|
var cleanNode = function() {
|
|
ko.cleanNode(this)
|
|
};
|
|
if (andSelf)
|
|
element.each(cleanNode);
|
|
else
|
|
element.find("*").each(cleanNode)
|
|
};
|
|
var originalEmpty = $.fn.empty;
|
|
$.fn.empty = function() {
|
|
cleanKoData(this, false);
|
|
return originalEmpty.apply(this, arguments)
|
|
};
|
|
var originalRemove = $.fn.remove;
|
|
$.fn.remove = function(selector, keepData) {
|
|
if (!keepData) {
|
|
var subject = this;
|
|
if (selector)
|
|
subject = subject.filter(selector);
|
|
cleanKoData(subject, true)
|
|
}
|
|
return originalRemove.call(this, selector, keepData)
|
|
};
|
|
var originalHtml = $.fn.html;
|
|
$.fn.html = function(value) {
|
|
if (typeof value === "string")
|
|
cleanKoData(this, false);
|
|
return originalHtml.apply(this, arguments)
|
|
};
|
|
$.extend(ui, {
|
|
Component: KoComponent,
|
|
registerComponent: registerKoComponent,
|
|
TemplateProvider: KoTemplateProvider,
|
|
Template: KoTemplate,
|
|
defaultTemplate: defaultKoTemplate
|
|
});
|
|
var originalRegisterEvent = events.registerEvent;
|
|
var registerKoEvent = function(eventName, eventObject) {
|
|
originalRegisterEvent(eventName, eventObject);
|
|
var koBindingEventName = events.addNamespace(eventName, eventName + "Binding");
|
|
ko.bindingHandlers[eventName] = {update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
|
|
var $element = $(element),
|
|
unwrappedValue = ko.utils.unwrapObservable(valueAccessor()),
|
|
eventSource = unwrappedValue.execute ? unwrappedValue.execute : unwrappedValue;
|
|
$element.off(koBindingEventName).on(koBindingEventName, function(e) {
|
|
eventSource(viewModel, e)
|
|
})
|
|
}}
|
|
};
|
|
$.extend(events, {registerEvent: registerKoEvent})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.angularIntegration.js */
|
|
(function($, DX, undefined) {
|
|
if (!DX.support.hasNg)
|
|
return;
|
|
var angular = window.angular,
|
|
ui = DX.ui,
|
|
events = ui.events,
|
|
compileSetter = DX.data.utils.compileSetter,
|
|
compileGetter = DX.data.utils.compileGetter;
|
|
var CREATED_WITH_NG_DATA_KEY = "dxNgCreation",
|
|
TEMPLATES_DATA_KEY = "dxTemplates",
|
|
COMPILER_DATA_KEY = "dxNgCompiler",
|
|
DEFAULT_COMPILER_DATA_KEY = "dxDefaultCompilerGetter",
|
|
ANONYMOUS_TEMPLATE_NAME = "template";
|
|
var phoneJsModule = angular.module("dx", []);
|
|
var ComponentBuilder = DX.Class.inherit({
|
|
ctor: function(options) {
|
|
this._componentName = options.componentName;
|
|
this._compile = options.compile;
|
|
this._$element = options.$element;
|
|
this._componentDisposing = $.Callbacks();
|
|
this._$templates = this._extractTemplates()
|
|
},
|
|
init: function(options) {
|
|
this._scope = options.scope;
|
|
this._$element = options.$element;
|
|
this._ngOptions = options.ngOptions;
|
|
this._$element.data(CREATED_WITH_NG_DATA_KEY, true);
|
|
if (options.ngOptions.data)
|
|
this._initDataScope(options.ngOptions.data)
|
|
},
|
|
initDefaultCompilerGetter: function() {
|
|
var self = this;
|
|
self._$element.data(DEFAULT_COMPILER_DATA_KEY, function($template) {
|
|
return self._compilerByTemplate($template)
|
|
})
|
|
},
|
|
initTemplateCompilers: function() {
|
|
var self = this;
|
|
if (this._$templates)
|
|
this._$templates.each(function(i, template) {
|
|
$(template).data(COMPILER_DATA_KEY, self._compilerByTemplate(template))
|
|
})
|
|
},
|
|
initComponentWithBindings: function() {
|
|
this._initComponent(this._scope);
|
|
this._initComponentBindings()
|
|
},
|
|
_initDataScope: function(data) {
|
|
if (typeof data === "string") {
|
|
var dataStr = data,
|
|
rootScope = this._scope;
|
|
data = rootScope.$eval(data);
|
|
this._scope = rootScope.$new();
|
|
this._synchronizeDataScopes(rootScope, this._scope, data, dataStr)
|
|
}
|
|
$.extend(this._scope, data)
|
|
},
|
|
_synchronizeDataScopes: function(parentScope, childScope, data, parentPrefix) {
|
|
var self = this;
|
|
$.each(data, function(fieldPath) {
|
|
self._synchronizeScopeField({
|
|
parentScope: parentScope,
|
|
childScope: childScope,
|
|
fieldPath: fieldPath,
|
|
parentPrefix: parentPrefix
|
|
})
|
|
})
|
|
},
|
|
_initComponent: function(scope) {
|
|
this._component = this._$element[this._componentName](this._evalOptions(scope)).data(this._componentName)
|
|
},
|
|
_initComponentBindings: function() {
|
|
var self = this,
|
|
optionDependencies = {};
|
|
if (self._ngOptions.bindingOptions)
|
|
$.each(self._ngOptions.bindingOptions, function(optionPath, valuePath) {
|
|
var separatorIndex = optionPath.search(/\[|\./),
|
|
optionForSubscribe = separatorIndex > -1 ? optionPath.substring(0, separatorIndex) : optionPath;
|
|
if (!optionDependencies[optionForSubscribe])
|
|
optionDependencies[optionForSubscribe] = {};
|
|
optionDependencies[optionForSubscribe][optionPath] = valuePath;
|
|
var clearWatcher = self._scope.$watch(valuePath, function(newValue, oldValue) {
|
|
if (newValue !== oldValue)
|
|
self._component.option(optionPath, newValue)
|
|
}, true);
|
|
self._component.disposing.add(function() {
|
|
clearWatcher();
|
|
self._componentDisposing.fire()
|
|
})
|
|
});
|
|
self._component.optionChanged.add(function(optionName, optionValue) {
|
|
if (self._scope.$root.$$phase || !optionDependencies || !optionDependencies[optionName])
|
|
return;
|
|
self._scope.$apply(function() {
|
|
$.each(optionDependencies[optionName], function(optionPath, valuePath) {
|
|
var setter = compileSetter(valuePath),
|
|
getter = compileGetter(optionPath);
|
|
var tmpData = {};
|
|
tmpData[optionName] = optionValue;
|
|
setter(self._scope, getter(tmpData))
|
|
})
|
|
})
|
|
})
|
|
},
|
|
_extractTemplates: function() {
|
|
var $templates;
|
|
if (ui[this._componentName].subclassOf(ui.Widget) && $.trim(this._$element.html())) {
|
|
var isAnonymousTemplate = !this._$element.children().first().attr("data-options");
|
|
if (isAnonymousTemplate)
|
|
$templates = $("<div/>").attr("data-options", "dxTemplate: { name: '" + ANONYMOUS_TEMPLATE_NAME + "' }").append(this._$element.contents());
|
|
else
|
|
$templates = this._$element.children().detach();
|
|
this._$element.data(TEMPLATES_DATA_KEY, $templates)
|
|
}
|
|
return $templates
|
|
},
|
|
_compilerByTemplate: function(template) {
|
|
var self = this,
|
|
scopeItemsPath = this._getScopeItemsPath();
|
|
return function(data, index) {
|
|
var $resultMarkup = $(template).clone(),
|
|
templateScope;
|
|
if (data !== undefined) {
|
|
var dataIsScope = data.$id,
|
|
templateScope = dataIsScope ? data : self._createScopeWithData(data);
|
|
$resultMarkup.on("$destroy", function() {
|
|
var destroyAlreadyCalled = !templateScope.$parent;
|
|
if (destroyAlreadyCalled)
|
|
return;
|
|
templateScope.$destroy()
|
|
})
|
|
}
|
|
else
|
|
templateScope = self._scope;
|
|
if (scopeItemsPath)
|
|
self._synchronizeScopes(templateScope, scopeItemsPath, index);
|
|
safeApply(self._compile($resultMarkup), templateScope);
|
|
return $resultMarkup
|
|
}
|
|
},
|
|
_getScopeItemsPath: function() {
|
|
if (ui[this._componentName].subclassOf(ui.CollectionContainerWidget) && this._ngOptions.bindingOptions)
|
|
return this._ngOptions.bindingOptions.items
|
|
},
|
|
_createScopeWithData: function(data) {
|
|
var newScope = this._scope.$new();
|
|
if (typeof data === "object")
|
|
$.extend(newScope, data);
|
|
else
|
|
newScope.scopeValue = data;
|
|
return newScope
|
|
},
|
|
_synchronizeScopes: function(itemScope, parentPrefix, itemIndex) {
|
|
var self = this,
|
|
item = compileGetter(parentPrefix + "[" + itemIndex + "]")(this._scope);
|
|
if (!$.isPlainObject(item))
|
|
item = {scopeValue: item};
|
|
$.each(item, function(itemPath) {
|
|
self._synchronizeScopeField({
|
|
parentScope: self._scope,
|
|
childScope: itemScope,
|
|
fieldPath: itemPath,
|
|
parentPrefix: parentPrefix,
|
|
itemIndex: itemIndex
|
|
})
|
|
})
|
|
},
|
|
_synchronizeScopeField: function(args) {
|
|
var parentScope = args.parentScope,
|
|
childScope = args.childScope,
|
|
fieldPath = args.fieldPath,
|
|
parentPrefix = args.parentPrefix,
|
|
itemIndex = args.itemIndex;
|
|
var innerPathSuffix = fieldPath === "scopeValue" ? "" : "." + fieldPath,
|
|
collectionField = itemIndex !== undefined,
|
|
optionOuterBag = [parentPrefix],
|
|
optionOuterPath;
|
|
if (collectionField)
|
|
optionOuterBag.push("[", itemIndex, "]");
|
|
optionOuterBag.push(innerPathSuffix);
|
|
optionOuterPath = optionOuterBag.join("");
|
|
var clearParentWatcher = parentScope.$watch(optionOuterPath, function(newValue, oldValue) {
|
|
if (newValue !== oldValue)
|
|
compileSetter(fieldPath)(childScope, newValue)
|
|
});
|
|
var clearItemWatcher = childScope.$watch(fieldPath, function(newValue, oldValue) {
|
|
if (newValue !== oldValue) {
|
|
if (collectionField && !compileGetter(parentPrefix)(parentScope)[itemIndex]) {
|
|
clearItemWatcher();
|
|
return
|
|
}
|
|
compileSetter(optionOuterPath)(parentScope, newValue)
|
|
}
|
|
});
|
|
this._componentDisposing.add([clearParentWatcher, clearItemWatcher])
|
|
},
|
|
_evalOptions: function(scope) {
|
|
var result = $.extend({}, this._ngOptions);
|
|
delete result.data;
|
|
delete result.bindingOptions;
|
|
if (this._ngOptions.bindingOptions)
|
|
$.each(this._ngOptions.bindingOptions, function(key, value) {
|
|
result[key] = scope.$eval(value)
|
|
});
|
|
return result
|
|
}
|
|
});
|
|
var safeApply = function(func, scope) {
|
|
if (scope.$root.$$phase)
|
|
func(scope);
|
|
else
|
|
scope.$apply(function() {
|
|
func(scope)
|
|
})
|
|
};
|
|
var NgComponent = ui.Component.inherit({
|
|
_modelByElement: function(element) {
|
|
if (element.length)
|
|
return element.scope()
|
|
},
|
|
_createActionByOption: function() {
|
|
var action = this.callBase.apply(this, arguments);
|
|
var component = this,
|
|
wrappedAction = function() {
|
|
var self = this,
|
|
scope = component._modelByElement(component._element()),
|
|
args = arguments;
|
|
if (!scope || scope.$root.$$phase)
|
|
return action.apply(self, args);
|
|
return scope.$apply(function() {
|
|
return action.apply(self, args)
|
|
})
|
|
};
|
|
return wrappedAction
|
|
}
|
|
});
|
|
var originalRegisterComponent = ui.registerComponent;
|
|
var registerNgComponent = function(componentName, componentClass) {
|
|
originalRegisterComponent(componentName, componentClass);
|
|
phoneJsModule.directive(componentName, ["$compile", function(compile) {
|
|
return {
|
|
restrict: "A",
|
|
compile: function($element) {
|
|
var componentBuilder = new ComponentBuilder({
|
|
componentName: componentName,
|
|
compile: compile,
|
|
$element: $element
|
|
});
|
|
return function(scope, $element, attrs) {
|
|
componentBuilder.init({
|
|
scope: scope,
|
|
$element: $element,
|
|
ngOptions: attrs[componentName] ? scope.$eval(attrs[componentName]) : {}
|
|
});
|
|
componentBuilder.initTemplateCompilers();
|
|
componentBuilder.initDefaultCompilerGetter();
|
|
componentBuilder.initComponentWithBindings()
|
|
}
|
|
}
|
|
}
|
|
}])
|
|
};
|
|
var NgTemplate = ui.Template.inherit({
|
|
ctor: function() {
|
|
this.callBase.apply(this, arguments);
|
|
this._compiler = this._template.data(COMPILER_DATA_KEY)
|
|
},
|
|
render: function(container, data, index) {
|
|
var compiler = this._compiler,
|
|
result = $.isFunction(compiler) ? compiler(data, index) : compiler;
|
|
container.append(result);
|
|
return result
|
|
},
|
|
setCompiler: function(compilerGetter) {
|
|
this._compiler = compilerGetter(this._element)
|
|
}
|
|
});
|
|
var NgTemplateProvider = ui.TemplateProvider.inherit({
|
|
getTemplateClass: function(widget) {
|
|
if (this._createdWithNg(widget))
|
|
return NgTemplate;
|
|
return this.callBase(widget)
|
|
},
|
|
supportDefaultTemplate: function(widget) {
|
|
return this._createdWithNg(widget) ? true : this.callBase(widget)
|
|
},
|
|
getDefaultTemplate: function(widget) {
|
|
if (this._createdWithNg(widget)) {
|
|
var compilerGetter = widget._element().data(DEFAULT_COMPILER_DATA_KEY),
|
|
template = defaultNgTemplate(widget.NAME);
|
|
template.setCompiler(compilerGetter);
|
|
return template
|
|
}
|
|
},
|
|
_createdWithNg: function(widget) {
|
|
return !!widget._element().data(CREATED_WITH_NG_DATA_KEY)
|
|
}
|
|
});
|
|
var defaultNgTemplate = function() {
|
|
var cache = {};
|
|
return function(widgetName) {
|
|
if (!DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName])
|
|
widgetName = "base";
|
|
if (!cache[widgetName])
|
|
cache[widgetName] = DEFAULT_ITEM_TEMPLATE_GENERATORS[widgetName]();
|
|
return new NgTemplate(cache[widgetName])
|
|
}
|
|
}();
|
|
var baseElements = {
|
|
container: function() {
|
|
return $("<div/>").attr("ng-class", "{ 'dx-state-invisible': !visible && visible != undefined, 'dx-state-disabled': !!disabled }").attr("ng-switch", "").attr("on", "html && 'html' || text && 'text' || scopeValue && 'scopeValue'")
|
|
},
|
|
html: function() {
|
|
return $("<div/>").attr("ng-switch-when", "html").attr("ng-bind-html-unsafe", "html")
|
|
},
|
|
text: function() {
|
|
return $("<div/>").attr("ng-switch-when", "text").attr("ng-bind", "text")
|
|
},
|
|
primitive: function() {
|
|
return $("<div/>").attr("ng-switch-when", "scopeValue").attr("ng-bind-html-unsafe", "'' + scopeValue")
|
|
}
|
|
};
|
|
var DEFAULT_ITEM_TEMPLATE_GENERATORS = {base: function() {
|
|
return baseElements.container().append(baseElements.html()).append(baseElements.text()).append(baseElements.primitive())
|
|
}};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxList = function() {
|
|
return DEFAULT_ITEM_TEMPLATE_GENERATORS.base().attr("on", "html && 'html' || text && 'text' || scopeValue && 'scopeValue' || key && 'key'").append($("<div/>").attr("ng-switch-when", "key").attr("ng-bind", "key"))
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxToolbar = function() {
|
|
var template = DEFAULT_ITEM_TEMPLATE_GENERATORS.base().attr("on", "html && 'html' || text && 'text' || scopeValue && 'scopeValue' || widget");
|
|
$.each(["button", "tabs", "dropDownMenu"], function(i, widgetName) {
|
|
var bindingName = "dx-" + DX.inflector.dasherize(this);
|
|
$("<div/>").attr("ng-switch-when", widgetName).attr(bindingName, "options").appendTo(template)
|
|
});
|
|
return template
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxGallery = function() {
|
|
return baseElements.container().append(baseElements.html()).append(baseElements.text()).append($("<img/>").attr("ng-switch-when", "scopeValue").attr("ng-src", "{{'' + scopeValue}}"))
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs = function() {
|
|
var container = baseElements.container().attr("on", "html && 'html' || icon && 'icon' || iconSrc && 'iconSrc' || text && 'text' || scopeValue && 'scopeValue'");
|
|
var text = $("<span/>").addClass("dx-tab-text").attr("ng-bind", "text"),
|
|
icon = $("<span/>").attr("ng-switch-when", "icon").addClass("dx-icon").attr("ng-class", "'dx-icon-' + icon").add(text.attr("ng-switch-when", "icon")),
|
|
iconSrc = $("<img/>").attr("ng-switch-when", "iconSrc").addClass("dx-icon").attr("ng-src", "{{iconSrc}}").add(text.attr("ng-switch-when", "iconSrc"));
|
|
return container.append(baseElements.html()).append(icon).append(iconSrc).append(text.attr("ng-switch-when", "text")).append(baseElements.primitive())
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxActionSheet = function() {
|
|
return $("<div/>").attr("dx-button", "{ bindingOptions: { text: 'text', clickAction: 'clickAction', type: 'type', disabled: 'disabled' } }")
|
|
};
|
|
DEFAULT_ITEM_TEMPLATE_GENERATORS.dxNavBar = DEFAULT_ITEM_TEMPLATE_GENERATORS.dxTabs;
|
|
$.extend(ui, {
|
|
Component: NgComponent,
|
|
registerComponent: registerNgComponent,
|
|
Template: NgTemplate,
|
|
TemplateProvider: NgTemplateProvider
|
|
});
|
|
var originalRegisterEvent = events.registerEvent;
|
|
var registerNgEvent = function(eventName, eventObject) {
|
|
originalRegisterEvent(eventName, eventObject);
|
|
var ngEventName = eventName.slice(0, 2) + eventName.charAt(2).toUpperCase() + eventName.slice(3);
|
|
phoneJsModule.directive(ngEventName, ['$parse', function($parse) {
|
|
return {
|
|
restrict: "A",
|
|
compile: function(_, attr) {
|
|
var handler = $parse(attr[ngEventName]);
|
|
return function(scope, $element) {
|
|
$element.on(eventName, function(e) {
|
|
scope.$apply(function() {
|
|
handler(scope, {$event: e})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}])
|
|
};
|
|
$.extend(events, {registerEvent: registerNgEvent})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.dialog.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var DEFAULT_BUTTON = {
|
|
text: "Ok",
|
|
clickAction: function() {
|
|
return true
|
|
}
|
|
};
|
|
var DX_DIALOG_CLASSNAME = "dx-dialog",
|
|
DX_DIALOG_WRAPPER_CLASSNAME = DX_DIALOG_CLASSNAME + "-wrapper",
|
|
DX_DIALOG_ROOT_CLASSNAME = DX_DIALOG_CLASSNAME + "-root",
|
|
DX_DIALOG_CONTENT_CLASSNAME = DX_DIALOG_CLASSNAME + "-content",
|
|
DX_DIALOG_MESSAGE_CLASSNAME = DX_DIALOG_CLASSNAME + "-message",
|
|
DX_DIALOG_BUTTONS_CLASSNAME = DX_DIALOG_CLASSNAME + "-buttons",
|
|
DX_DIALOG_BUTTON_CLASSNAME = DX_DIALOG_CLASSNAME + "-button";
|
|
var dialog = function(options) {
|
|
var self = this,
|
|
result;
|
|
if (!ui.dxPopup)
|
|
throw new Error("DevExpress.ui.dxPopup required");
|
|
var deferred = $.Deferred();
|
|
options = $.extend(ui.optionsByDevice(DX.devices.current(), "dxDialog"), options);
|
|
var $holder = $(".dx-viewport");
|
|
var $element = $("<div/>").addClass(DX_DIALOG_CLASSNAME).appendTo($holder);
|
|
var $message = $("<div/>").addClass(DX_DIALOG_MESSAGE_CLASSNAME).html(String(options.message));
|
|
var $buttons = $("<div/>").addClass(DX_DIALOG_BUTTONS_CLASSNAME);
|
|
var popupInstance = $element.dxPopup({
|
|
title: options.title || self.title,
|
|
height: "auto",
|
|
width: function() {
|
|
var isPortrait = $(window).height() > $(window).width(),
|
|
key = (isPortrait ? "p" : "l") + "Width";
|
|
return options.hasOwnProperty(key) ? options[key] : options["width"]
|
|
},
|
|
contentReadyAction: function() {
|
|
popupInstance.content().addClass(DX_DIALOG_CONTENT_CLASSNAME).append($message).append($buttons)
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "pop",
|
|
duration: 400
|
|
},
|
|
hide: {
|
|
type: "pop",
|
|
duration: 400,
|
|
to: {
|
|
opacity: 0,
|
|
scale: 0
|
|
},
|
|
from: {
|
|
opacity: 1,
|
|
scale: 1
|
|
}
|
|
}
|
|
}
|
|
}).data("dxPopup");
|
|
popupInstance._wrapper().addClass(DX_DIALOG_WRAPPER_CLASSNAME);
|
|
if (options.position)
|
|
popupInstance.option("position", options.position);
|
|
$.each(options.buttons || [DEFAULT_BUTTON], function() {
|
|
var button = $("<div/>").addClass(DX_DIALOG_BUTTON_CLASSNAME).appendTo($buttons);
|
|
var action = new DX.Action(this.clickAction, {context: popupInstance});
|
|
button.dxButton($.extend(this, {clickAction: function() {
|
|
result = action.execute(arguments);
|
|
hide()
|
|
}}))
|
|
});
|
|
popupInstance._wrapper().addClass(DX_DIALOG_ROOT_CLASSNAME);
|
|
function show() {
|
|
popupInstance.show();
|
|
return deferred.promise()
|
|
}
|
|
function hide(value) {
|
|
popupInstance.hide().done(function() {
|
|
popupInstance._element().remove()
|
|
});
|
|
deferred.resolve(result || value)
|
|
}
|
|
return {
|
|
show: show,
|
|
hide: hide
|
|
}
|
|
};
|
|
var alert = function(message, title) {
|
|
var dialogInstance,
|
|
options = $.isPlainObject(message) ? message : {
|
|
title: title,
|
|
message: message
|
|
};
|
|
dialogInstance = ui.dialog.custom(options);
|
|
return dialogInstance.show()
|
|
};
|
|
var confirm = function(message, title) {
|
|
var dialogInstance,
|
|
options = $.isPlainObject(message) ? message : {
|
|
title: title,
|
|
message: message,
|
|
buttons: [{
|
|
text: Globalize.localize("Yes"),
|
|
clickAction: function() {
|
|
return true
|
|
}
|
|
}, {
|
|
text: Globalize.localize("No"),
|
|
clickAction: function() {
|
|
return false
|
|
}
|
|
}]
|
|
};
|
|
dialogInstance = ui.dialog.custom(options);
|
|
return dialogInstance.show()
|
|
};
|
|
var notify = function(message, type, displayTime) {
|
|
var options,
|
|
instance;
|
|
options = $.isPlainObject(message) ? message : {message: message};
|
|
if (!ui.dxToast) {
|
|
alert(options.message);
|
|
return
|
|
}
|
|
if (type)
|
|
options.type = type;
|
|
if (displayTime)
|
|
options.displayTime = displayTime;
|
|
instance = $("<div/>").appendTo(".dx-viewport").addClass("dx-static").dxToast(options).data("dxToast");
|
|
instance.option("hiddenAction", function(args) {
|
|
args.element.remove();
|
|
new DX.Action(options.hiddenAction, {context: args.model}).execute(arguments)
|
|
});
|
|
instance.show()
|
|
};
|
|
$.extend(ui, {
|
|
notify: notify,
|
|
dialog: {
|
|
custom: dialog,
|
|
alert: alert,
|
|
confirm: confirm
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.dataHelper.js */
|
|
(function($, DX, undefined) {
|
|
var data = DX.data;
|
|
var DATA_SOURCE_OPTIONS_METHOD = "_dataSourceOptions",
|
|
DATA_SOURCE_CHANGED_METHOD = "_handleDataSourceChanged",
|
|
DATA_SOURCE_LOAD_ERROR_METHOD = "_handleDataSourceLoadError",
|
|
DATA_SOURCE_LOADING_CHANGED_METHOD = "_handleDataSourceLoadingChanged";
|
|
DX.ui.DataHelperMixin = {
|
|
ctor: function() {
|
|
this.disposing.add(function() {
|
|
this._disposeDataSource()
|
|
})
|
|
},
|
|
_refreshDataSource: function() {
|
|
this._initDataSource();
|
|
this._loadDataSource()
|
|
},
|
|
_initDataSource: function() {
|
|
var dataSourceOptions = this.option("dataSource"),
|
|
widgetDataSourceOptions,
|
|
dataSourceType;
|
|
this._disposeDataSource();
|
|
if (dataSourceOptions) {
|
|
if (dataSourceOptions instanceof data.DataSource) {
|
|
this._isSharedDataSource = true;
|
|
this._dataSource = dataSourceOptions
|
|
}
|
|
else {
|
|
widgetDataSourceOptions = DATA_SOURCE_OPTIONS_METHOD in this ? this[DATA_SOURCE_OPTIONS_METHOD]() : {};
|
|
dataSourceType = this._dataSourceType ? this._dataSourceType() : data.DataSource;
|
|
this._dataSource = new dataSourceType($.extend(true, {}, widgetDataSourceOptions, data.utils.normalizeDataSourceOptions(dataSourceOptions)))
|
|
}
|
|
this._addDataSourceHandlers()
|
|
}
|
|
},
|
|
_addDataSourceHandlers: function() {
|
|
if (DATA_SOURCE_CHANGED_METHOD in this)
|
|
this._addDataSourceChangeHandler();
|
|
if (DATA_SOURCE_LOAD_ERROR_METHOD in this)
|
|
this._addDataSourceLoadErrorHandler();
|
|
if (DATA_SOURCE_LOADING_CHANGED_METHOD in this)
|
|
this._addDataSourceLoadingChangedHandler()
|
|
},
|
|
_addDataSourceChangeHandler: function() {
|
|
var self = this,
|
|
dataSource = this._dataSource;
|
|
this._dataSourceChangedHandler = function() {
|
|
self[DATA_SOURCE_CHANGED_METHOD](dataSource.items())
|
|
};
|
|
dataSource.changed.add(this._dataSourceChangedHandler)
|
|
},
|
|
_addDataSourceLoadErrorHandler: function() {
|
|
this._dataSourceLoadErrorHandler = $.proxy(this[DATA_SOURCE_LOAD_ERROR_METHOD], this);
|
|
this._dataSource.loadError.add(this._dataSourceLoadErrorHandler)
|
|
},
|
|
_addDataSourceLoadingChangedHandler: function() {
|
|
this._dataSourceLoadingChangedHandler = $.proxy(this[DATA_SOURCE_LOADING_CHANGED_METHOD], this);
|
|
this._dataSource.loadingChanged.add(this._dataSourceLoadingChangedHandler)
|
|
},
|
|
_loadDataSource: function() {
|
|
if (this._dataSource) {
|
|
var dataSource = this._dataSource;
|
|
if (dataSource.isLoaded())
|
|
this._dataSourceChangedHandler();
|
|
else
|
|
dataSource.load()
|
|
}
|
|
},
|
|
_disposeDataSource: function() {
|
|
if (this._dataSource) {
|
|
if (this._isSharedDataSource) {
|
|
delete this._isSharedDataSource;
|
|
this._dataSource.changed.remove(this._dataSourceChangedHandler);
|
|
this._dataSource.loadError.remove(this._dataSourceLoadErrorHandler);
|
|
this._dataSource.loadingChanged.remove(this._dataSourceLoadingChangedHandler)
|
|
}
|
|
else
|
|
this._dataSource.dispose();
|
|
delete this._dataSource;
|
|
delete this._dataSourceChangedHandler;
|
|
delete this._dataSourceLoadErrorHandler;
|
|
delete this._dataSourceLoadingChangedHandler
|
|
}
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.mspointer.js */
|
|
(function($, DX, undefined) {
|
|
var POINTER_TYPE_MAP = {
|
|
2: "touch",
|
|
3: "pen",
|
|
4: "mouse"
|
|
};
|
|
var pointerEventHook = {
|
|
filter: function(event, originalEvent) {
|
|
var pointerType = originalEvent.pointerType;
|
|
if ($.isNumeric(pointerType))
|
|
event.pointerType = POINTER_TYPE_MAP[pointerType];
|
|
return event
|
|
},
|
|
props: $.event.mouseHooks.props.concat(["pointerId", "originalTarget", "namespace", "width", "height", "pressure", "result", "tiltX", "charCode", "tiltY", "detail", "isPrimary", "prevValue"])
|
|
};
|
|
$.each(["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerCancel", "MSPointerOver", "MSPointerOut", "MSPointerEnter", "MSPointerLeave", "pointerdown", "pointermove", "pointerup", "pointercancel", "pointerover", "pointerout", "pointerenter", "pointerleave"], function() {
|
|
$.event.fixHooks[this] = pointerEventHook
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.touch.js */
|
|
(function($, DX, undefined) {
|
|
var touchEventHook = {
|
|
filter: function(event, originalEvent) {
|
|
if (originalEvent.changedTouches.length) {
|
|
event.pageX = originalEvent.changedTouches[0].pageX;
|
|
event.pageY = originalEvent.changedTouches[0].pageY
|
|
}
|
|
return event
|
|
},
|
|
props: $.event.mouseHooks.props.concat(["touches", "changedTouches", "targetTouches", "detail", "result", "namespace", "originalTarget", "charCode", "prevValue"])
|
|
};
|
|
$.each(["touchstart", "touchmove", "touchend", "touchcancel"], function() {
|
|
$.event.fixHooks[this] = touchEventHook
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.pointer.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
support = DX.support,
|
|
device = DX.devices.real,
|
|
events = ui.events,
|
|
MOUSE_EVENT_LOCK_TIMEOUT = 100,
|
|
mouseLocked = false,
|
|
unlockMouseTimer = null;
|
|
var POINTER_EVENTS_NAMESPACE = "dxPointerEvents",
|
|
MouseStrategyEventMap = {
|
|
dxpointerdown: "mousedown",
|
|
dxpointermove: "mousemove",
|
|
dxpointerup: "mouseup",
|
|
dxpointercancel: ""
|
|
},
|
|
TouchStrategyEventMap = {
|
|
dxpointerdown: "touchstart",
|
|
dxpointermove: "touchmove",
|
|
dxpointerup: "touchend",
|
|
dxpointercancel: "touchcancel"
|
|
},
|
|
PointerStrategyEventMap = {
|
|
dxpointerdown: "pointerdown",
|
|
dxpointermove: "pointermove",
|
|
dxpointerup: "pointerup",
|
|
dxpointercancel: "pointercancel"
|
|
},
|
|
MouseAndTouchStrategyEventMap = {
|
|
dxpointerdown: "touchstart mousedown",
|
|
dxpointermove: "touchmove mousemove",
|
|
dxpointerup: "touchend mouseup",
|
|
dxpointercancel: "touchcancel"
|
|
};
|
|
var eventMap = function() {
|
|
if (support.touch && !(device.tablet || device.phone))
|
|
return MouseAndTouchStrategyEventMap;
|
|
if (support.touch)
|
|
return TouchStrategyEventMap;
|
|
return MouseStrategyEventMap
|
|
}();
|
|
$.each(eventMap, function(pointerEvent, originalEvents) {
|
|
var SingleEventStrategy = {
|
|
EVENT_NAMESPACE: [POINTER_EVENTS_NAMESPACE, ".", pointerEvent].join(""),
|
|
_handlerCount: 0,
|
|
_handler: function(e) {
|
|
if (pointerEvent === "dxpointerdown")
|
|
$(e.target).data("dxGestureEvent", null);
|
|
return events.fireEvent({
|
|
type: pointerEvent,
|
|
pointerType: events.eventSource(e),
|
|
originalEvent: e
|
|
})
|
|
},
|
|
setup: function() {
|
|
if (pointerEventNS._handlerCount > 0)
|
|
return;
|
|
$(document).on(events.addNamespace(originalEvents, SingleEventStrategy.EVENT_NAMESPACE), pointerEventNS._handler)
|
|
},
|
|
add: function() {
|
|
pointerEventNS._handlerCount++
|
|
},
|
|
remove: function() {
|
|
pointerEventNS._handlerCount--
|
|
},
|
|
teardown: function() {
|
|
if (pointerEventNS._handlerCount)
|
|
return;
|
|
$(document).off("." + pointerEventNS.EVENT_NAMESPACE)
|
|
}
|
|
};
|
|
var MultiEventStrategy = $.extend({}, SingleEventStrategy, {_handler: function(e) {
|
|
if (events.isTouchEvent(e))
|
|
pointerEventNS._skipNextEvents = true;
|
|
if (events.isMouseEvent(e) && mouseLocked)
|
|
return;
|
|
if (events.isMouseEvent(e) && pointerEventNS._skipNextEvents) {
|
|
pointerEventNS._skipNextEvents = false;
|
|
mouseLocked = true;
|
|
clearTimeout(unlockMouseTimer);
|
|
unlockMouseTimer = setTimeout(function() {
|
|
mouseLocked = false
|
|
}, MOUSE_EVENT_LOCK_TIMEOUT);
|
|
return
|
|
}
|
|
return SingleEventStrategy._handler(e)
|
|
}});
|
|
var pointerEventNS = eventMap === MouseAndTouchStrategyEventMap ? MultiEventStrategy : SingleEventStrategy;
|
|
events.registerEvent(pointerEvent, pointerEventNS)
|
|
});
|
|
DX.ui.events.__internals = DX.ui.events.__internals || {};
|
|
$.extend(DX.ui.events.__internals, {
|
|
mouseLocked: function(value) {
|
|
if (value === undefined)
|
|
return mouseLocked;
|
|
mouseLocked = value
|
|
},
|
|
unlockMouseTimer: function() {
|
|
return unlockMouseTimer
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.click.js */
|
|
(function($, DX, wnd, undefined) {
|
|
var ua = navigator.userAgent,
|
|
screen = wnd.screen,
|
|
ui = DX.ui,
|
|
utils = DX.utils,
|
|
events = ui.events,
|
|
support = DX.support,
|
|
device = DX.devices.real,
|
|
EVENTS_NAME_SPACE = "dxSpecialEvents",
|
|
CLICK_NAME_SPACE = "dxClick" + EVENTS_NAME_SPACE,
|
|
CLICK_EVENT_NAME = "dxclick",
|
|
SCROLLABLE_PARENT_DATA_KEY = "dxClickScrollableParent",
|
|
SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY = "dxClickScrollableParentOffset",
|
|
preferNativeClick = function() {
|
|
var iPhone4SAndElder = device.deviceType === "phone" && screen.height <= 480,
|
|
iPad2AndElder = device.deviceType === "tablet" && wnd.devicePixelRatio < 2,
|
|
IOS7AndNewer = device.platform === "ios" && device.version[0] > 6;
|
|
return IOS7AndNewer && (iPhone4SAndElder || iPad2AndElder)
|
|
}(),
|
|
skipTouchWithSameIdentifier = function() {
|
|
return device.platform === "ios"
|
|
},
|
|
useNativeClick = function() {
|
|
if (!support.touch)
|
|
return true;
|
|
var chromeInfo = ua.match(/Chrome\/([0-9]+)/) || [],
|
|
chrome = !!chromeInfo[0],
|
|
chromeVersion = ~~chromeInfo[1],
|
|
android = device.platform === "android";
|
|
if (chrome)
|
|
if (android) {
|
|
if (chromeVersion > 31 && wnd.innerWidth <= screen.width)
|
|
return true;
|
|
if ($("meta[name=viewport][content*='user-scalable=no']").length)
|
|
return true
|
|
}
|
|
else
|
|
return true;
|
|
return false
|
|
}();
|
|
var SimulatedStrategy = {
|
|
TOUCH_BOUNDARY: 10,
|
|
_startX: 0,
|
|
_startY: 0,
|
|
_handlerCount: 0,
|
|
_target: null,
|
|
_touchWasMoved: function(e) {
|
|
var boundary = SimulatedStrategy.TOUCH_BOUNDARY;
|
|
return Math.abs(e.pageX - SimulatedStrategy._startX) > boundary || Math.abs(e.pageY - SimulatedStrategy._startY) > boundary
|
|
},
|
|
_getClosestScrollable: function($element) {
|
|
var $scrollParent = $();
|
|
if ($element.data(SCROLLABLE_PARENT_DATA_KEY))
|
|
$scrollParent = $element.data(SCROLLABLE_PARENT_DATA_KEY);
|
|
else {
|
|
var $current = $element;
|
|
while ($current.length) {
|
|
if ($current[0].scrollHeight - $current[0].offsetHeight > 1) {
|
|
$scrollParent = $current;
|
|
$element.data(SCROLLABLE_PARENT_DATA_KEY, $scrollParent);
|
|
break
|
|
}
|
|
$current = $current.parent()
|
|
}
|
|
}
|
|
return $scrollParent
|
|
},
|
|
_saveClosestScrollableOffset: function($element) {
|
|
var $scrollable = SimulatedStrategy._getClosestScrollable($element);
|
|
if ($scrollable.length)
|
|
$element.data(SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY, $scrollable.scrollTop())
|
|
},
|
|
_closestScrollableWasMoved: function($element) {
|
|
var $scrollable = $element.data(SCROLLABLE_PARENT_DATA_KEY);
|
|
return $scrollable && $scrollable.scrollTop() !== $element.data(SCROLLABLE_PARENT_SCROLL_OFFSET_DATA_KEY)
|
|
},
|
|
_hasClosestScrollable: function($element) {
|
|
var $scrollable = SimulatedStrategy._getClosestScrollable($element);
|
|
if (!$scrollable.length)
|
|
return false;
|
|
if ($scrollable.is("body"))
|
|
return false;
|
|
if ($scrollable === window)
|
|
return false;
|
|
if ($scrollable.css("overflow") === "hidden")
|
|
return false;
|
|
return true
|
|
},
|
|
_handleStart: function(e) {
|
|
if (events.isMouseEvent(e) && e.which !== 1)
|
|
return;
|
|
if (events.isTouchEvent(e) && skipTouchWithSameIdentifier()) {
|
|
var touchId = e.originalEvent.targetTouches[0].identifier;
|
|
if (SimulatedStrategy._lastTouchId === touchId) {
|
|
ui.feedback.reset();
|
|
return
|
|
}
|
|
SimulatedStrategy._lastTouchId = touchId
|
|
}
|
|
SimulatedStrategy._saveClosestScrollableOffset($(e.target));
|
|
SimulatedStrategy._target = e.target;
|
|
SimulatedStrategy._startX = e.pageX;
|
|
SimulatedStrategy._startY = e.pageY
|
|
},
|
|
_handleEnd: function(e) {
|
|
var $target = $(e.target);
|
|
if (!$target.is(SimulatedStrategy._target) || SimulatedStrategy._touchWasMoved(e) || SimulatedStrategy._closestScrollableWasMoved($target) || preferNativeClick && SimulatedStrategy._hasClosestScrollable($target))
|
|
return;
|
|
if (!$target.is(":focus") && !e.dxPreventBlur)
|
|
utils.resetActiveElement();
|
|
if (events.handleGestureEvent(e, CLICK_EVENT_NAME))
|
|
events.fireEvent({
|
|
type: CLICK_EVENT_NAME,
|
|
originalEvent: e
|
|
});
|
|
SimulatedStrategy._reset()
|
|
},
|
|
_handleCancel: function(e) {
|
|
SimulatedStrategy._reset()
|
|
},
|
|
_reset: function() {
|
|
SimulatedStrategy._target = null
|
|
},
|
|
_handleClick: function(e) {
|
|
var $target = $(e.target);
|
|
if ($target.is(SimulatedStrategy._target) && SimulatedStrategy._hasClosestScrollable($target))
|
|
if (events.handleGestureEvent(e, CLICK_EVENT_NAME))
|
|
events.fireEvent({
|
|
type: CLICK_EVENT_NAME,
|
|
originalEvent: e
|
|
});
|
|
SimulatedStrategy._reset()
|
|
},
|
|
_makeElementClickable: function($element) {
|
|
if (!$element.attr("onclick"))
|
|
$element.attr("onclick", "void(0)")
|
|
},
|
|
setup: function() {
|
|
SimulatedStrategy._makeElementClickable($(this));
|
|
if (SimulatedStrategy._handlerCount > 0)
|
|
return;
|
|
var $doc = $(document).on(events.addNamespace("dxpointerdown", CLICK_NAME_SPACE), $.proxy(SimulatedStrategy._handleStart, this)).on(events.addNamespace("dxpointerup", CLICK_NAME_SPACE), $.proxy(SimulatedStrategy._handleEnd, this)).on(events.addNamespace("dxpointercancel", CLICK_NAME_SPACE), $.proxy(SimulatedStrategy._handleCancel, this));
|
|
if (preferNativeClick)
|
|
$doc.on(events.addNamespace("click", CLICK_NAME_SPACE), $.proxy(SimulatedStrategy._handleClick, this))
|
|
},
|
|
add: function() {
|
|
SimulatedStrategy._handlerCount++
|
|
},
|
|
remove: function() {
|
|
SimulatedStrategy._handlerCount--
|
|
},
|
|
teardown: function() {
|
|
if (SimulatedStrategy._handlerCount)
|
|
return;
|
|
$(document).off("." + CLICK_NAME_SPACE)
|
|
}
|
|
};
|
|
var NativeStrategy = {
|
|
bindType: "click",
|
|
delegateType: "click",
|
|
handle: function(e) {
|
|
if (events.handleGestureEvent(e, CLICK_EVENT_NAME))
|
|
return e.handleObj.handler.apply(this, arguments)
|
|
}
|
|
};
|
|
events.registerEvent(CLICK_EVENT_NAME, useNativeClick ? NativeStrategy : SimulatedStrategy);
|
|
DX.ui.events.__internals = DX.ui.events.__internals || {};
|
|
$.extend(DX.ui.events.__internals, {
|
|
NativeClickStrategy: NativeStrategy,
|
|
SimulatedClickStrategy: SimulatedStrategy,
|
|
device: device
|
|
})
|
|
})(jQuery, DevExpress, window);
|
|
/*! Module core, file ui.events.hold.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
jqSpecialEvent = $.event.special,
|
|
EVENTS_NAME_SPACE = "dxSpecialEvents",
|
|
HOLD_NAME_SPACE = "dxHold",
|
|
HOLD_EVENT_NAME = "dxhold",
|
|
HOLD_TIMER_DATA_KEY = EVENTS_NAME_SPACE + "HoldTimer";
|
|
var hold = {
|
|
HOLD_TIMEOUT: 750,
|
|
TOUCH_BOUNDARY: 5,
|
|
_startX: 0,
|
|
_startY: 0,
|
|
_touchWasMoved: function(e) {
|
|
var boundary = hold.TOUCH_BOUNDARY;
|
|
return Math.abs(e.pageX - hold._startX) > boundary || Math.abs(e.pageY - hold._startY) > boundary
|
|
},
|
|
setup: function(data) {
|
|
var element = this,
|
|
$element = $(element);
|
|
var handleStart = function(e) {
|
|
if ($element.data(HOLD_TIMER_DATA_KEY))
|
|
return;
|
|
hold._startX = e.pageX;
|
|
hold._startY = e.pageY;
|
|
$element.data(HOLD_TIMER_DATA_KEY, setTimeout(function() {
|
|
$element.removeData(HOLD_TIMER_DATA_KEY);
|
|
if (events.handleGestureEvent(e, HOLD_EVENT_NAME))
|
|
events.fireEvent({
|
|
type: HOLD_EVENT_NAME,
|
|
originalEvent: e
|
|
})
|
|
}, data && "timeout" in data ? data.timeout : hold.HOLD_TIMEOUT))
|
|
};
|
|
var handleMove = function(e) {
|
|
if (!hold._touchWasMoved(e))
|
|
return;
|
|
handleEnd()
|
|
};
|
|
var handleEnd = function() {
|
|
clearTimeout($element.data(HOLD_TIMER_DATA_KEY));
|
|
$element.removeData(HOLD_TIMER_DATA_KEY)
|
|
};
|
|
$element.on(events.addNamespace("dxpointerdown", HOLD_NAME_SPACE), handleStart).on(events.addNamespace("dxpointermove", HOLD_NAME_SPACE), handleMove).on(events.addNamespace("dxpointerup", HOLD_NAME_SPACE), handleEnd)
|
|
},
|
|
teardown: function() {
|
|
var $element = $(this);
|
|
clearTimeout($element.data(HOLD_TIMER_DATA_KEY));
|
|
$element.removeData(HOLD_TIMER_DATA_KEY).off("." + HOLD_NAME_SPACE)
|
|
}
|
|
};
|
|
events.registerEvent(HOLD_EVENT_NAME, hold)
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.events.swipe.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils,
|
|
events = ui.events,
|
|
SWIPE_START_EVENT_NAME = "dxswipestart",
|
|
SWIPE_EVENT_NAME = "dxswipe",
|
|
SWIPE_END_EVENT_NAME = "dxswipeend",
|
|
SWIPE_CANCEL_EVENT_NAME = "dxswipecancel",
|
|
SWIPEABLE_DATA_KEY = "dxSwipeEventDataKey",
|
|
GESTURE_LOCK_KEY = "dxGesture";
|
|
var HorizontalStrategy = {
|
|
defaultItemSizeFunc: function() {
|
|
return this._activeSwipeable.width()
|
|
},
|
|
isSwipeAngleAllowed: function(delta) {
|
|
return Math.abs(delta.y) <= Math.abs(delta.x)
|
|
},
|
|
getBounds: function() {
|
|
return [this._maxLeftOffset, this._maxRightOffset]
|
|
},
|
|
calcOffsetRatio: function(e) {
|
|
var endEventData = events.eventData(e);
|
|
return (endEventData.x - (this._startEventData && this._startEventData.x || 0)) / this._itemSizeFunc().call(this, e)
|
|
},
|
|
isFastSwipe: function(e) {
|
|
var endEventData = events.eventData(e);
|
|
return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.x - this._tickData.x) >= endEventData.time - this._tickData.time
|
|
}
|
|
};
|
|
var VerticalStrategy = {
|
|
defaultItemSizeFunc: function() {
|
|
return this._activeSwipeable.height()
|
|
},
|
|
isSwipeAngleAllowed: function(delta) {
|
|
return Math.abs(delta.y) >= Math.abs(delta.x)
|
|
},
|
|
getBounds: function() {
|
|
return [this._maxTopOffset, this._maxBottomOffset]
|
|
},
|
|
calcOffsetRatio: function(e) {
|
|
var endEventData = events.eventData(e);
|
|
return (endEventData.y - (this._startEventData && this._startEventData.y || 0)) / this._itemSizeFunc().call(this, e)
|
|
},
|
|
isFastSwipe: function(e) {
|
|
var endEventData = events.eventData(e);
|
|
return this.FAST_SWIPE_SPEED_LIMIT * Math.abs(endEventData.y - this._tickData.y) >= endEventData.time - this._tickData.time
|
|
}
|
|
};
|
|
var STRATEGIES = {
|
|
horizontal: HorizontalStrategy,
|
|
vertical: VerticalStrategy
|
|
};
|
|
var SwipeDispatcher = DX.Class.inherit({
|
|
STAGE_SLEEP: 0,
|
|
STAGE_TOUCHED: 1,
|
|
STAGE_SWIPING: 2,
|
|
TICK_INTERVAL: 300,
|
|
FAST_SWIPE_SPEED_LIMIT: 5,
|
|
ctor: function() {
|
|
this._attachEvents()
|
|
},
|
|
_getStrategy: function() {
|
|
return STRATEGIES[this._data("direction")]
|
|
},
|
|
_defaultItemSizeFunc: function() {
|
|
return this._getStrategy().defaultItemSizeFunc.call(this)
|
|
},
|
|
_itemSizeFunc: function() {
|
|
return this._data("itemSizeFunc") || this._defaultItemSizeFunc
|
|
},
|
|
_data: function(key, value) {
|
|
var data = this._activeSwipeable.data(SWIPEABLE_DATA_KEY);
|
|
if (arguments.length === 1)
|
|
return data[key];
|
|
else if (arguments.length === 2)
|
|
data[key] = value
|
|
},
|
|
_closestSwipeable: function(e) {
|
|
var current = $(e.target);
|
|
while (current.length) {
|
|
var swipeable = $(current).data(SWIPEABLE_DATA_KEY);
|
|
if (swipeable)
|
|
return $(current);
|
|
current = current.parent()
|
|
}
|
|
},
|
|
_handleStart: function(e) {
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
if (this._swipeStage > this.STAGE_SLEEP)
|
|
return;
|
|
var activeSwipeable = this._activeSwipeable = this._closestSwipeable(e);
|
|
if (!activeSwipeable)
|
|
return;
|
|
this._parentsLength = this._activeSwipeable.parents().length;
|
|
this._startEventData = events.eventData(e);
|
|
this._tickData = {time: 0};
|
|
this._swipeStage = this.STAGE_TOUCHED
|
|
},
|
|
_handleMove: function(e) {
|
|
if (!this._activeSwipeable || this._swipeStage === this.STAGE_SLEEP)
|
|
return;
|
|
if (this._swipeStage === this.STAGE_TOUCHED)
|
|
this._handleFirstMove(e);
|
|
if (this._swipeStage === this.STAGE_SWIPING)
|
|
this._handleNextMoves(e)
|
|
},
|
|
_handleFirstMove: function(e) {
|
|
var delta = events.eventDelta(this._startEventData, events.eventData(e));
|
|
if (!delta.x && !delta.y)
|
|
return;
|
|
if (!events.handleGestureEvent(e, SWIPE_EVENT_NAME))
|
|
return;
|
|
if (!this._getStrategy().isSwipeAngleAllowed.call(this, delta) || events.needSkipEvent(e)) {
|
|
this._fireSwipeCancelEvent(e);
|
|
this._reset();
|
|
return
|
|
}
|
|
ui.feedback.reset();
|
|
if ($(":focus", this._activeSwipeable).length)
|
|
utils.resetActiveElement();
|
|
if (e.originalEvent) {
|
|
var direction = this._data("direction");
|
|
if (e.originalEvent.pointerMoveData[direction] !== this._parentsLength)
|
|
return;
|
|
e.originalEvent.isScrollingEvent = false
|
|
}
|
|
this._prepareGesture();
|
|
e = events.fireEvent({
|
|
type: "dxswipestart",
|
|
originalEvent: e,
|
|
target: this._activeSwipeable.get(0)
|
|
});
|
|
if (e.cancel) {
|
|
this._fireSwipeCancelEvent(e);
|
|
this._reset();
|
|
return
|
|
}
|
|
this._maxLeftOffset = e.maxLeftOffset;
|
|
this._maxRightOffset = e.maxRightOffset;
|
|
this._maxTopOffset = e.maxTopOffset;
|
|
this._maxBottomOffset = e.maxBottomOffset;
|
|
this._swipeStage = this.STAGE_SWIPING
|
|
},
|
|
_fireSwipeCancelEvent: function(e) {
|
|
events.fireEvent({
|
|
type: "dxswipecancel",
|
|
originalEvent: e,
|
|
target: this._activeSwipeable.get(0)
|
|
})
|
|
},
|
|
_handleBodyPointerMove: function(e) {
|
|
if (!this._activeSwipeable || !e.originalEvent)
|
|
return;
|
|
var pointerMoveData = e.originalEvent.pointerMoveData || {},
|
|
direction = this._data("direction"),
|
|
directionValue = pointerMoveData[direction];
|
|
if (directionValue && directionValue > this._parentsLength) {
|
|
this._reset();
|
|
return
|
|
}
|
|
pointerMoveData[direction] = this._parentsLength;
|
|
e.originalEvent.pointerMoveData = pointerMoveData
|
|
},
|
|
_handleNextMoves: function(e) {
|
|
var strategy = this._getStrategy(),
|
|
moveEventData = events.eventData(e),
|
|
offset = strategy.calcOffsetRatio.call(this, e);
|
|
offset = this._fitOffset(offset, this._data("elastic"));
|
|
if (moveEventData.time - this._tickData.time > this.TICK_INTERVAL)
|
|
this._tickData = moveEventData;
|
|
events.fireEvent({
|
|
type: "dxswipe",
|
|
originalEvent: e,
|
|
offset: offset,
|
|
target: this._activeSwipeable.get(0)
|
|
})
|
|
},
|
|
_handleEnd: function(e) {
|
|
if (!DX.devices.isRippleEmulator() && events.hasTouches(e) || !this._activeSwipeable)
|
|
return;
|
|
if (this._swipeStage !== this.STAGE_SWIPING) {
|
|
this._reset();
|
|
return
|
|
}
|
|
var strategy = this._getStrategy(),
|
|
offsetRatio = strategy.calcOffsetRatio.call(this, e),
|
|
fast = strategy.isFastSwipe.call(this, e),
|
|
startOffset = offsetRatio,
|
|
targetOffset = this._calcTargetOffset(offsetRatio, fast);
|
|
startOffset = this._fitOffset(startOffset, this._data("elastic"));
|
|
targetOffset = this._fitOffset(targetOffset, false);
|
|
events.fireEvent({
|
|
type: "dxswipeend",
|
|
offset: startOffset,
|
|
targetOffset: targetOffset,
|
|
target: this._activeSwipeable.get(0),
|
|
originalEvent: e
|
|
});
|
|
this._reset()
|
|
},
|
|
_fitOffset: function(offset, elastic) {
|
|
var strategy = this._getStrategy(),
|
|
bounds = strategy.getBounds.call(this);
|
|
if (offset < -bounds[0])
|
|
return elastic ? (-2 * bounds[0] + offset) / 3 : -bounds[0];
|
|
if (offset > bounds[1])
|
|
return elastic ? (2 * bounds[1] + offset) / 3 : bounds[1];
|
|
return offset
|
|
},
|
|
_calcTargetOffset: function(offsetRatio, fast) {
|
|
var result;
|
|
if (fast) {
|
|
result = Math.ceil(Math.abs(offsetRatio));
|
|
if (offsetRatio < 0)
|
|
result = -result
|
|
}
|
|
else
|
|
result = Math.round(offsetRatio);
|
|
return result
|
|
},
|
|
_prepareGesture: function() {
|
|
clearTimeout(this._gestureEndTimer);
|
|
this._activeSwipeable.data(GESTURE_LOCK_KEY, true)
|
|
},
|
|
_forgetGesture: function() {
|
|
var swipeable = this._activeSwipeable;
|
|
this._gestureEndTimer = setTimeout($.proxy(function() {
|
|
swipeable.data(GESTURE_LOCK_KEY, false)
|
|
}, this), 400)
|
|
},
|
|
_reset: function() {
|
|
this._forgetGesture();
|
|
this._activeSwipeable = null;
|
|
this._swipeStage = this.STAGE_SLEEP
|
|
},
|
|
_attachEvents: function() {
|
|
$("body").on(events.addNamespace("dxpointermove", "dxSwipe"), $.proxy(this._handleBodyPointerMove, this));
|
|
$(document).on(events.addNamespace("dxpointerdown", "dxSwipe"), $.proxy(this._handleStart, this)).on(events.addNamespace("dxpointermove", "dxSwipe"), $.proxy(this._handleMove, this)).on(events.addNamespace("dxpointerup dxpointercancel", "dxSwipe"), $.proxy(this._handleEnd, this))
|
|
},
|
|
isDisposed: function() {
|
|
return this._disposed
|
|
},
|
|
dispose: function() {
|
|
this._disposed = true;
|
|
if (this._activeSwipeable)
|
|
this._reset();
|
|
$(document).off(".dxSwipe")
|
|
}
|
|
});
|
|
var swipeDispatcher = null;
|
|
var handlerCount = 0;
|
|
$.each([SWIPE_START_EVENT_NAME, SWIPE_EVENT_NAME, SWIPE_END_EVENT_NAME, SWIPE_CANCEL_EVENT_NAME], function(_, eventName) {
|
|
events.registerEvent(eventName, {
|
|
noBubble: true,
|
|
setup: function(data) {
|
|
$(this).data(SWIPEABLE_DATA_KEY, $.extend($(this).data(SWIPEABLE_DATA_KEY) || {
|
|
elastic: true,
|
|
direction: "horizontal"
|
|
}, data));
|
|
if (!swipeDispatcher || swipeDispatcher.isDisposed())
|
|
swipeDispatcher = new SwipeDispatcher
|
|
},
|
|
add: function() {
|
|
handlerCount++
|
|
},
|
|
remove: function() {
|
|
handlerCount--
|
|
},
|
|
teardown: function() {
|
|
var element = $(this);
|
|
if (element.data(SWIPEABLE_DATA_KEY))
|
|
element.removeData(SWIPEABLE_DATA_KEY);
|
|
if (handlerCount)
|
|
return;
|
|
if (!swipeDispatcher)
|
|
return;
|
|
swipeDispatcher.dispose();
|
|
swipeDispatcher = null
|
|
}
|
|
})
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.widget.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
UI_FEEDBACK = "UIFeedback",
|
|
UI_FEEDBACK_CLASS = "dx-feedback",
|
|
ACTIVE_STATE_CLASS = "dx-state-active",
|
|
DISABLED_STATE_CLASS = "dx-state-disabled",
|
|
INVISIBLE_STATE_CLASS = "dx-state-invisible",
|
|
HOVERED_STATE_CLASS = "dx-state-hovered",
|
|
FEEDBACK_SHOW_TIMEOUT = 30,
|
|
FEEDBACK_HIDE_TIMEOUT = 400;
|
|
var activeElement,
|
|
events = ui.events;
|
|
ui.feedback = {reset: function() {
|
|
handleEnd(true)
|
|
}};
|
|
ui.Widget = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
visible: true,
|
|
activeStateEnabled: true,
|
|
width: undefined,
|
|
height: undefined,
|
|
clickAction: null,
|
|
hoverStateEnabled: false
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._feedbackShowTimeout = FEEDBACK_SHOW_TIMEOUT;
|
|
this._feedbackHideTimeout = FEEDBACK_HIDE_TIMEOUT
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-widget");
|
|
this._toggleDisabledState(this.option("disabled"));
|
|
this._toggleVisibility(this.option("visible"));
|
|
this._refreshFeedback();
|
|
this._renderDimensions();
|
|
this._renderClick()
|
|
},
|
|
_dispose: function() {
|
|
this._clearTimers();
|
|
if (activeElement && activeElement.closest(this._element()).length)
|
|
activeElement = null;
|
|
this.callBase()
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._element().empty()
|
|
},
|
|
_clearTimers: function() {
|
|
clearTimeout(this._feedbackHideTimer);
|
|
clearTimeout(this._feedbackShowTimer)
|
|
},
|
|
_toggleVisibility: function(visible) {
|
|
this._element().toggleClass(INVISIBLE_STATE_CLASS, !visible)
|
|
},
|
|
_toggleHoverState: function(value) {
|
|
if (this.option("hoverStateEnabled"))
|
|
this._element().toggleClass(HOVERED_STATE_CLASS, value)
|
|
},
|
|
_renderDimensions: function() {
|
|
var width = this.option("width"),
|
|
height = this.option("height");
|
|
this._element().width(width);
|
|
this._element().height(height)
|
|
},
|
|
_refreshFeedback: function() {
|
|
if (this._feedbackDisabled()) {
|
|
this._feedbackOff();
|
|
this._element().removeClass(UI_FEEDBACK_CLASS)
|
|
}
|
|
else
|
|
this._element().addClass(UI_FEEDBACK_CLASS)
|
|
},
|
|
_renderClick: function() {
|
|
var self = this,
|
|
eventName = events.addNamespace("dxclick", this.NAME);
|
|
this._clickAction = this._createActionByOption("clickAction");
|
|
this._clickEventContainer().off(eventName).on(eventName, function(e) {
|
|
self._clickAction({jQueryEvent: e})
|
|
})
|
|
},
|
|
_clickEventContainer: function() {
|
|
return this._element()
|
|
},
|
|
_feedbackDisabled: function() {
|
|
return !this.option("activeStateEnabled") || this.option("disabled")
|
|
},
|
|
_feedbackOn: function(element, immediate) {
|
|
if (this._feedbackDisabled())
|
|
return;
|
|
this._clearTimers();
|
|
if (immediate)
|
|
this._feedbackShow(element);
|
|
else
|
|
this._feedbackShowTimer = window.setTimeout($.proxy(this._feedbackShow, this, element), this._feedbackShowTimeout);
|
|
this._saveActiveElement()
|
|
},
|
|
_feedbackShow: function(element) {
|
|
var activeStateElement = this._element();
|
|
if (this._activeStateUnit)
|
|
activeStateElement = $(element).closest(this._activeStateUnit);
|
|
if (!activeStateElement.hasClass(DISABLED_STATE_CLASS)) {
|
|
activeStateElement.addClass(ACTIVE_STATE_CLASS);
|
|
this._toggleHoverState(false)
|
|
}
|
|
},
|
|
_saveActiveElement: function() {
|
|
activeElement = this._element()
|
|
},
|
|
_feedbackOff: function(immediate) {
|
|
this._clearTimers();
|
|
if (immediate)
|
|
this._feedbackHide();
|
|
else
|
|
this._feedbackHideTimer = window.setTimeout($.proxy(this._feedbackHide, this), this._feedbackHideTimeout)
|
|
},
|
|
_feedbackHide: function() {
|
|
var activeStateElement = this._element();
|
|
if (this._activeStateUnit)
|
|
activeStateElement = activeStateElement.find(this._activeStateUnit);
|
|
activeStateElement.removeClass(ACTIVE_STATE_CLASS);
|
|
this._toggleHoverState(!this.option("disabled"));
|
|
this._clearActiveElement()
|
|
},
|
|
_clearActiveElement: function() {
|
|
var rootDomElement = this._element().get(0),
|
|
activeDomElement = activeElement && activeElement.get(0);
|
|
if (activeDomElement && (activeDomElement === rootDomElement || $.contains(rootDomElement, activeDomElement)))
|
|
activeElement = null
|
|
},
|
|
_toggleDisabledState: function(value) {
|
|
this._element().toggleClass(DISABLED_STATE_CLASS, value);
|
|
this._toggleHoverState(!value)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"disabled":
|
|
this._toggleDisabledState(value);
|
|
this._refreshFeedback();
|
|
break;
|
|
case"activeStateEnabled":
|
|
this._refreshFeedback();
|
|
break;
|
|
case"hoverStateEnabled":
|
|
this._toggleHoverState();
|
|
break;
|
|
case"visible":
|
|
this._toggleVisibility(value);
|
|
break;
|
|
case"width":
|
|
case"height":
|
|
this._renderDimensions();
|
|
break;
|
|
case"clickAction":
|
|
this._renderClick();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
repaint: function() {
|
|
this._refresh()
|
|
}
|
|
});
|
|
var handleStart = function(args, immediate) {
|
|
var e = args.jQueryEvent,
|
|
$target = args.element;
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
if (activeElement)
|
|
getWidget(activeElement)._feedbackOff(true);
|
|
var closestFeedbackElement = $target.closest("." + UI_FEEDBACK_CLASS),
|
|
widget;
|
|
if (closestFeedbackElement.length) {
|
|
widget = getWidget(closestFeedbackElement);
|
|
widget._feedbackOn($target, immediate);
|
|
if (immediate)
|
|
widget._feedbackOff()
|
|
}
|
|
};
|
|
var handleEnd = function(immediate) {
|
|
if (!activeElement)
|
|
return;
|
|
getWidget(activeElement)._feedbackOff(immediate)
|
|
};
|
|
var getWidget = function(widgetElement) {
|
|
var result;
|
|
$.each(widgetElement.data("dxComponents"), function(index, componentName) {
|
|
if (ui[componentName].subclassOf(ui.Widget)) {
|
|
result = widgetElement.data(componentName);
|
|
return false
|
|
}
|
|
});
|
|
return result
|
|
};
|
|
$(function() {
|
|
var startAction = new DX.Action(handleStart);
|
|
$(document).on(events.addNamespace("dxpointerdown", UI_FEEDBACK), function(e) {
|
|
startAction.execute({
|
|
jQueryEvent: e,
|
|
element: $(e.target)
|
|
})
|
|
}).on(events.addNamespace("dxpointerup dxpointercancel", UI_FEEDBACK), function(e) {
|
|
var activeElementClicked = activeElement && $(e.target).closest("." + UI_FEEDBACK_CLASS).get(0) === activeElement.get(0);
|
|
if (activeElementClicked)
|
|
startAction.execute({
|
|
jQueryEvent: e,
|
|
element: $(e.target)
|
|
}, true);
|
|
handleEnd()
|
|
})
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.containerWidget.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
ANONYMOUS_TEMPLATE_NAME = "template",
|
|
TEMPLATE_SELECTOR = "[data-options*='dxTemplate']",
|
|
TEMPLATES_DATA_KEY = "dxTemplates";
|
|
var getTemplateOptions = function(element) {
|
|
var options = $(element).data("options");
|
|
if ($.trim(options).charAt(0) !== "{")
|
|
options = "{" + options + "}";
|
|
return new Function("return " + options)().dxTemplate
|
|
};
|
|
var ContainerWidget = ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {contentReadyAction: $.noop})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._templateProvider = new ui.TemplateProvider;
|
|
this._initTemplates();
|
|
this._initContentReadyAction()
|
|
},
|
|
_clean: $.noop,
|
|
_createTemplate: function(element) {
|
|
return new(this._templateProvider.getTemplateClass(this))(element)
|
|
},
|
|
_initTemplates: function() {
|
|
var self = this,
|
|
templates = {},
|
|
dataTemplateElements = this._element().data(TEMPLATES_DATA_KEY),
|
|
templateElements = dataTemplateElements ? dataTemplateElements : this._element().contents().filter(TEMPLATE_SELECTOR);
|
|
if (templateElements.length)
|
|
templateElements.each(function() {
|
|
var templateOptions = getTemplateOptions(this);
|
|
if (!templateOptions)
|
|
return;
|
|
if (!templateOptions.name)
|
|
throw Error("Template name was not specified");
|
|
templates[templateOptions.name] = self._createTemplate(this)
|
|
});
|
|
else
|
|
templates[ANONYMOUS_TEMPLATE_NAME] = self._createTemplate(self._element().contents());
|
|
this._externalTemplates = {};
|
|
this._templates = templates
|
|
},
|
|
_initContentReadyAction: function() {
|
|
this._contentReadyAction = this._createActionByOption("contentReadyAction", {excludeValidators: ["gesture", "designMode", "disabled"]})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._renderContent()
|
|
},
|
|
_renderContent: function() {
|
|
this._renderContentImpl();
|
|
this._fireContentReadyAction()
|
|
},
|
|
_renderContentImpl: DX.abstract,
|
|
_fireContentReadyAction: function() {
|
|
this._contentReadyAction({excludeValidators: ["disabled", "gesture"]})
|
|
},
|
|
_getTemplate: function(templateName) {
|
|
var result = this._acquireTemplate.apply(this, arguments);
|
|
if (!result && this._templateProvider.supportDefaultTemplate(this)) {
|
|
result = this._templateProvider.getDefaultTemplate(this);
|
|
if (!result)
|
|
throw Error(DX.utils.stringFormat("Template \"{0}\" was not found and no default template specified!", templateName));
|
|
}
|
|
return result
|
|
},
|
|
_acquireTemplate: function(templateSource) {
|
|
if (templateSource == null)
|
|
return templateSource;
|
|
if (templateSource.nodeType || templateSource.jquery) {
|
|
templateSource = $(templateSource);
|
|
if (templateSource.is("script"))
|
|
templateSource = templateSource.html();
|
|
return this._createTemplate(templateSource)
|
|
}
|
|
if (typeof templateSource === "string")
|
|
return this._getTemplates()[templateSource];
|
|
if ($.isFunction(templateSource)) {
|
|
var args = $.makeArray(arguments).slice(1);
|
|
return this._acquireTemplate(templateSource.apply(this, args))
|
|
}
|
|
return this._acquireTemplate(templateSource.toString())
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"contentReadyAction":
|
|
this._initContentReadyAction();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_cleanTemplates: function() {
|
|
$.each(this._templates, function(templateName, template) {
|
|
template.dispose()
|
|
})
|
|
},
|
|
_dispose: function() {
|
|
this._cleanTemplates();
|
|
this._contentReadyAction = null;
|
|
this.callBase()
|
|
},
|
|
addTemplate: function(template) {
|
|
$.extend(this._templates, template)
|
|
},
|
|
addExternalTemplate: function(template) {
|
|
$.extend(this._externalTemplates, template)
|
|
},
|
|
_getTemplates: function() {
|
|
return $.extend({}, this._templates, this._externalTemplates)
|
|
}
|
|
});
|
|
ui.ContainerWidget = ContainerWidget
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.template.js */
|
|
(function($, DX, undefined) {
|
|
var isString = DX.utils.isString;
|
|
var currentTemplateEngine;
|
|
var templateEngines = [];
|
|
var BaseTemplate = DevExpress.Class.inherit({
|
|
_compile: function(html, element) {
|
|
return element
|
|
},
|
|
_render: function(template, data) {
|
|
return template
|
|
},
|
|
ctor: function(element) {
|
|
this._element = $(element);
|
|
if (this._element.length === 1) {
|
|
if (this._element[0].nodeName.toLowerCase() !== "script")
|
|
this._element = $("<div />").append(this._element);
|
|
this._template = this._compile(this._element.html() || "", this._element)
|
|
}
|
|
},
|
|
render: function(container, data) {
|
|
var result;
|
|
if (this._template) {
|
|
result = this._render(this._template, data);
|
|
if (isString(result))
|
|
result = $.parseHTML(result);
|
|
result = $(result);
|
|
if (container)
|
|
container.append(result);
|
|
return result
|
|
}
|
|
},
|
|
dispose: $.noop
|
|
});
|
|
var createTemplateEngine = function(options) {
|
|
if (options && options.compile && options.render)
|
|
return BaseTemplate.inherit({
|
|
allowRenderToDetachedContainer: options.allowRenderToDetachedContainer !== false,
|
|
_compile: options.compile,
|
|
_render: options.render
|
|
});
|
|
else
|
|
throw Error("Template Engine must contains compile and render methods");
|
|
};
|
|
if (window.ko) {
|
|
var koCustomTemplateEngine = function(){};
|
|
koCustomTemplateEngine.prototype = ko.utils.extend(new ko.templateEngine, {
|
|
renderTemplateSource: function(templateSource, bindingContext, options) {
|
|
var precompiledTemplate = templateSource["data"]("precompiledTemplate");
|
|
if (!precompiledTemplate) {
|
|
precompiledTemplate = new currentTemplateEngine(templateSource.domElement);
|
|
templateSource["data"]("precompiledTemplate", precompiledTemplate)
|
|
}
|
|
return precompiledTemplate.render(null, bindingContext.$data)
|
|
},
|
|
allowTemplateRewriting: false
|
|
})
|
|
}
|
|
DevExpress.ui.setTemplateEngine = function(templateEngine) {
|
|
if (isString(templateEngine)) {
|
|
currentTemplateEngine = templateEngines && templateEngines[templateEngine];
|
|
if (!currentTemplateEngine && templateEngine !== "default")
|
|
throw Error(DX.utils.stringFormat("Template Engine \"{0}\" is not supported", templateEngine));
|
|
}
|
|
else
|
|
currentTemplateEngine = createTemplateEngine(templateEngine) || currentTemplateEngine;
|
|
if (window.ko)
|
|
ko.setTemplateEngine(currentTemplateEngine ? new koCustomTemplateEngine : new ko.nativeTemplateEngine)
|
|
};
|
|
DevExpress.ui.TemplateProvider = DevExpress.ui.TemplateProvider.inherit({getTemplateClass: function() {
|
|
if (currentTemplateEngine)
|
|
return currentTemplateEngine;
|
|
return this.callBase.apply(this, arguments)
|
|
}});
|
|
var registerTemplateEngine = function(name, templateOptions) {
|
|
templateEngines[name] = createTemplateEngine(templateOptions)
|
|
};
|
|
registerTemplateEngine("jquery-tmpl", {
|
|
compile: function(html, element) {
|
|
return element
|
|
},
|
|
render: function(template, data) {
|
|
return template.tmpl(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("jsrender", {
|
|
compile: function(html) {
|
|
return $.templates(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template.render(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("mustache", {
|
|
compile: function(html) {
|
|
return Mustache.compile(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("hogan", {
|
|
compile: function(html) {
|
|
return Hogan.compile(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template.render(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("underscore", {
|
|
compile: function(html) {
|
|
return _.template(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("handlebars", {
|
|
compile: function(html) {
|
|
return Handlebars.compile(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template(data)
|
|
}
|
|
});
|
|
registerTemplateEngine("doT", {
|
|
compile: function(html) {
|
|
return doT.template(html)
|
|
},
|
|
render: function(template, data) {
|
|
return template(data)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.collectionContainerWidget.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var CollectionContainerWidget = ui.ContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
items: [],
|
|
itemTemplate: "item",
|
|
itemRender: null,
|
|
itemClickAction: null,
|
|
itemRenderedAction: null,
|
|
noDataText: Globalize.localize("dxCollectionContainerWidget-noDataText"),
|
|
dataSource: null
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._cleanRenderedItems();
|
|
this._refreshDataSource()
|
|
},
|
|
_dataSourceOptions: function() {
|
|
var options = {
|
|
paginate: false,
|
|
_preferSync: false
|
|
};
|
|
if ($.isArray(this.option("dataSource")))
|
|
options._preferSync = true;
|
|
return options
|
|
},
|
|
_cleanRenderedItems: function() {
|
|
this._renderedItemsCount = 0
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"items":
|
|
this._cleanRenderedItems();
|
|
this._invalidate();
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
case"dataSource":
|
|
this._refreshDataSource();
|
|
if (!this._dataSource)
|
|
this.option("items", []);
|
|
this._renderEmptyMessage();
|
|
break;
|
|
case"noDataText":
|
|
this._renderEmptyMessage();
|
|
break;
|
|
case"itemRenderedAction":
|
|
this._createItemRenderAction();
|
|
break;
|
|
case"itemTemplate":
|
|
this._itemTemplateName = null;
|
|
this._invalidate();
|
|
break;
|
|
case"itemRender":
|
|
this._itemRender = null;
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
},
|
|
_expectNextPageLoading: function() {
|
|
this._startIndexForAppendedItems = 0
|
|
},
|
|
_expectLastItemLoading: function() {
|
|
this._startIndexForAppendedItems = -1
|
|
},
|
|
_forgetNextPageLoading: function() {
|
|
this._startIndexForAppendedItems = null
|
|
},
|
|
_handleDataSourceChanged: function(newItems) {
|
|
var items = this.option("items");
|
|
if (this._initialized && items && this._shouldAppendItems()) {
|
|
this._renderedItemsCount = items.length;
|
|
this.option().items = items.concat(newItems.slice(this._startIndexForAppendedItems));
|
|
this._renderContent();
|
|
this._forgetNextPageLoading()
|
|
}
|
|
else
|
|
this.option("items", newItems)
|
|
},
|
|
_handleDataSourceLoadError: function() {
|
|
this._forgetNextPageLoading()
|
|
},
|
|
_shouldAppendItems: function() {
|
|
return this._startIndexForAppendedItems != null && this._allowDinamicItemsAppend()
|
|
},
|
|
_allowDinamicItemsAppend: function() {
|
|
return false
|
|
},
|
|
_clean: function() {
|
|
this._itemContainer().empty()
|
|
},
|
|
_refresh: function() {
|
|
this._cleanRenderedItems();
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
_itemContainer: function() {
|
|
return this._element()
|
|
},
|
|
_itemClass: DX.abstract,
|
|
_itemSelector: function() {
|
|
return "." + this._itemClass()
|
|
},
|
|
_itemDataKey: DX.abstract,
|
|
_itemElements: function() {
|
|
return this._itemContainer().find(this._itemSelector())
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._attachClickEvent()
|
|
},
|
|
_attachClickEvent: function() {
|
|
var itemSelector = this._itemSelector(),
|
|
eventName = events.addNamespace("dxclick", this.NAME);
|
|
this._itemContainer().off(eventName, itemSelector).on(eventName, itemSelector, $.proxy(this._handleItemClick, this))
|
|
},
|
|
_handleItemClick: function(e) {
|
|
this._handleItemJQueryEvent(e, "itemClickAction")
|
|
},
|
|
_renderContentImpl: function() {
|
|
var items = this.option("items") || [];
|
|
if (this._renderedItemsCount)
|
|
this._renderItems(items.slice(this._renderedItemsCount));
|
|
else
|
|
this._renderItems(items)
|
|
},
|
|
_renderItems: function(items) {
|
|
if (items.length)
|
|
$.each(items, $.proxy(this._renderItem, this));
|
|
this._renderEmptyMessage()
|
|
},
|
|
_renderItem: function(index, item, container) {
|
|
container = container || this._itemContainer();
|
|
var itemRenderer = this._getItemRenderer(),
|
|
itemTemplateName = this._getItemTemplateName(),
|
|
itemTemplate = this._getTemplate(item.template || itemTemplateName, index, item),
|
|
itemElement,
|
|
renderArgs = {
|
|
index: index,
|
|
item: item,
|
|
container: container
|
|
};
|
|
if (itemRenderer)
|
|
itemElement = this._createItemByRenderer(itemRenderer, renderArgs);
|
|
else if (itemTemplate)
|
|
itemElement = this._createItemByTemplate(itemTemplate, renderArgs);
|
|
else
|
|
itemElement = this._createItemByRenderer(this._itemRenderDefault, renderArgs);
|
|
itemElement.addClass(this._itemClass()).data(this._itemDataKey(), item);
|
|
var postprocessRenderArgs = {
|
|
itemElement: itemElement,
|
|
itemData: item,
|
|
itemIndex: index
|
|
};
|
|
this._postprocessRenderItem(postprocessRenderArgs);
|
|
this._getItemRenderAction()({
|
|
itemElement: itemElement,
|
|
itemData: item
|
|
});
|
|
return itemElement
|
|
},
|
|
_createItemRenderAction: function() {
|
|
return this._itemRenderAction = this._createActionByOption("itemRenderedAction", {
|
|
element: this._element(),
|
|
excludeValidators: ["gesture", "designMode", "disabled"]
|
|
})
|
|
},
|
|
_getItemRenderAction: function() {
|
|
return this._itemRenderAction || this._createItemRenderAction()
|
|
},
|
|
_getItemRenderer: function() {
|
|
this._itemRender = this._itemRender || this.option("itemRender");
|
|
return this._itemRender
|
|
},
|
|
_createItemByRenderer: function(itemRenderer, renderArgs) {
|
|
var itemElement = $("<div />").appendTo(renderArgs.container);
|
|
var rendererResult = itemRenderer.call(this, renderArgs.item, renderArgs.index, itemElement);
|
|
if (rendererResult != null && itemElement[0] !== rendererResult[0])
|
|
itemElement.append(rendererResult);
|
|
return itemElement
|
|
},
|
|
_getItemTemplateName: function() {
|
|
this._itemTemplateName = this._itemTemplateName || this.option("itemTemplate");
|
|
return this._itemTemplateName
|
|
},
|
|
_createItemByTemplate: function(itemTemplate, renderArgs) {
|
|
return itemTemplate.render(renderArgs.container, renderArgs.item, renderArgs.index, "ignoreTarget")
|
|
},
|
|
_itemRenderDefault: function(item, index, itemElement) {
|
|
if ($.isPlainObject(item)) {
|
|
if (item.visible !== undefined && !item.visible)
|
|
itemElement.hide();
|
|
if (item.disabled)
|
|
itemElement.addClass("dx-state-disabled");
|
|
if (item.text)
|
|
itemElement.text(item.text);
|
|
if (item.html)
|
|
itemElement.html(item.html)
|
|
}
|
|
else
|
|
itemElement.html(String(item))
|
|
},
|
|
_postprocessRenderItem: $.noop,
|
|
_renderEmptyMessage: function() {
|
|
var noDataText = this.option("noDataText"),
|
|
items = this.option("items"),
|
|
dataSourceLoading = this._dataSource && this._dataSource.isLoading(),
|
|
hideNoData = !noDataText || items && items.length || dataSourceLoading;
|
|
if (hideNoData && this._$nodata) {
|
|
this._$nodata.remove();
|
|
this._$nodata = null
|
|
}
|
|
if (!hideNoData) {
|
|
this._$nodata = this._$nodata || $("<div />").addClass("dx-empty-message");
|
|
this._$nodata.appendTo(this._itemContainer()).text(noDataText)
|
|
}
|
|
},
|
|
_handleItemJQueryEvent: function(jQueryEvent, handlerOptionName, actionArgs, actionConfig) {
|
|
this._handleItemEvent(jQueryEvent.target, handlerOptionName, $.extend(actionArgs, {jQueryEvent: jQueryEvent}), actionConfig)
|
|
},
|
|
_closestItemElement: function($element) {
|
|
return $($element).closest(this._itemSelector())
|
|
},
|
|
_handleItemEvent: function(initiator, handlerOptionName, actionArgs, actionConfig) {
|
|
var $itemElement = this._closestItemElement($(initiator)),
|
|
action = this._createActionByOption(handlerOptionName, actionConfig);
|
|
actionArgs = $.extend({
|
|
itemElement: $itemElement,
|
|
itemData: this._getItemData($itemElement)
|
|
}, actionArgs);
|
|
return action(actionArgs)
|
|
},
|
|
_getItemData: function($itemElement) {
|
|
return $itemElement.data(this._itemDataKey())
|
|
}
|
|
}).include(ui.DataHelperMixin);
|
|
ui.CollectionContainerWidget = CollectionContainerWidget
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.selectableCollectionWidget.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var SelectableCollectionWidget = ui.CollectionContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
selectedIndex: -1,
|
|
itemSelectAction: null
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._renderSelectedIndex(this.option("selectedIndex"));
|
|
this._attachSelectedEvent()
|
|
},
|
|
_attachSelectedEvent: function() {
|
|
var itemSelector = this._itemSelector(),
|
|
itemSelectAction = this._createAction(this._handleItemSelect),
|
|
handleItemClick = $.proxy(this._handleItemClick, this),
|
|
eventName = events.addNamespace("dxclick", this.NAME);
|
|
this._element().off(eventName, itemSelector).on(eventName, itemSelector, function(e) {
|
|
var $itemElement = $(e.target).closest(itemSelector);
|
|
itemSelectAction({
|
|
itemElement: $itemElement,
|
|
jQueryEvent: e
|
|
});
|
|
handleItemClick(e)
|
|
})
|
|
},
|
|
_handleItemSelect: function(args) {
|
|
var e = args.jQueryEvent,
|
|
instance = args.component;
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
var itemElements = instance._itemElements(),
|
|
selectedItemElement = $(e.target).closest(instance._itemSelector()),
|
|
selectedItemIndex = itemElements.index(selectedItemElement);
|
|
if (instance.option("selectedIndex") !== selectedItemIndex)
|
|
instance._onItemSelectAction(selectedItemIndex)
|
|
},
|
|
_onItemSelectAction: function(newIndex) {
|
|
this.option("selectedIndex", newIndex)
|
|
},
|
|
_renderSelectedIndex: DX.abstract,
|
|
_renderEmptyMessage: $.noop,
|
|
_attachClickEvent: $.noop,
|
|
_optionChanged: function(name, value, prevValue) {
|
|
if (name === "selectedIndex") {
|
|
this._renderSelectedIndex(value, prevValue);
|
|
this._handleItemEvent(this._selectedItemElement(value), "itemSelectAction", null, {excludeValidators: ["gesture"]})
|
|
}
|
|
else
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
_selectedItemElement: function(index) {
|
|
return this._itemElements().eq(index)
|
|
}
|
|
});
|
|
ui.SelectableCollectionWidget = SelectableCollectionWidget
|
|
})(jQuery, DevExpress);
|
|
/*! Module core, file ui.optionsByDevice.js */
|
|
(function($, DX, undefined) {
|
|
var isSimulationMode = function(device) {
|
|
var realDevice = DX.devices.real,
|
|
isOldAndroid = realDevice.platform === "android" && realDevice.version.length && realDevice.version[0] < 4,
|
|
isPlatformForced = realDevice.platform !== device.platform,
|
|
isForcedGeneric = device.platform === "generic",
|
|
isForcedDesktop = device.platform === "desktop",
|
|
isTizen = realDevice.platform === "tizen",
|
|
isGeneric = realDevice.platform === "generic",
|
|
isRippleEmulator = DX.devices.isRippleEmulator(),
|
|
isSimulator = DX.devices.isSimulator();
|
|
return isOldAndroid || isTizen || isRippleEmulator || isSimulator || isPlatformForced && !isForcedGeneric && !(isGeneric && isForcedDesktop)
|
|
};
|
|
var isChromeBrowser = /chrome/i.test(navigator.userAgent);
|
|
var optionConfigurator = {};
|
|
optionConfigurator.dxActionSheet = function(device) {
|
|
if (device.platform === "ios" && device.tablet)
|
|
return {usePopover: true}
|
|
};
|
|
optionConfigurator.dxRadioGroup = function(device) {
|
|
if (device.tablet)
|
|
return {layout: "horizontal"}
|
|
};
|
|
optionConfigurator.dxDateBox = function(device) {
|
|
if (device.android || device.win8)
|
|
return {useNativePicker: false}
|
|
};
|
|
optionConfigurator.dxDatePicker = function(device) {
|
|
if (device.platform !== "win8")
|
|
return {
|
|
width: 333,
|
|
height: 280
|
|
};
|
|
else
|
|
return {showNames: true}
|
|
};
|
|
optionConfigurator.dxDialog = function(device) {
|
|
if (device.platform === "ios")
|
|
return {width: 276};
|
|
if (device.platform === "win8" && !device.phone)
|
|
return {width: "60%"};
|
|
if (device.platform === "win8")
|
|
return {
|
|
width: function() {
|
|
return $(window).width()
|
|
},
|
|
position: {
|
|
my: "top center",
|
|
at: "top center",
|
|
of: window,
|
|
offset: "0 0"
|
|
}
|
|
};
|
|
if (device.platform === "android")
|
|
return {
|
|
lWidth: "60%",
|
|
pWidth: "80%"
|
|
}
|
|
};
|
|
optionConfigurator.dxDropDownMenu = function(device) {
|
|
if (device.platform === "ios")
|
|
return {usePopover: true}
|
|
};
|
|
optionConfigurator.dxLoadIndicator = function(device) {
|
|
var realDevice = DevExpress.devices.real,
|
|
obsoleteAndroid = realDevice.platform === "android" && (realDevice.version[0] < 4 || realDevice.version[0] === 4 && realDevice.version[1] === 0);
|
|
if (DevExpress.browser.msie && DevExpress.browser.version[0] <= 10 || obsoleteAndroid)
|
|
return {viaImage: true}
|
|
};
|
|
optionConfigurator.dxLoadPanel = function(device) {
|
|
if (device.platform === "desktop")
|
|
return {width: 180}
|
|
};
|
|
optionConfigurator.dxLookup = function(device) {
|
|
if (device.platform === "win8" && device.phone)
|
|
return {
|
|
showCancelButton: false,
|
|
fullScreen: true
|
|
};
|
|
if (device.platform === "ios" && device.phone)
|
|
return {fullScreen: true};
|
|
if (device.platform === "ios" && device.tablet)
|
|
return {
|
|
popupWidth: function() {
|
|
return Math.min($(window).width(), $(window).height()) * 0.4
|
|
},
|
|
popupHeight: function() {
|
|
return Math.min($(window).width(), $(window).height()) * 0.4
|
|
},
|
|
usePopover: true
|
|
}
|
|
};
|
|
optionConfigurator.dxPopup = function(device) {
|
|
if (device.platform === "win8" && !device.phone)
|
|
return {width: "60%"};
|
|
if (device.platform === "win8" && device.phone)
|
|
return {position: {
|
|
my: "top center",
|
|
at: "top center",
|
|
of: window,
|
|
offset: "0 0"
|
|
}};
|
|
if (device.platform === "ios")
|
|
return {animation: {
|
|
show: {
|
|
type: "slide",
|
|
duration: 400,
|
|
from: {position: {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: window
|
|
}},
|
|
to: {position: {
|
|
my: "center",
|
|
at: "center",
|
|
of: window
|
|
}}
|
|
},
|
|
hide: {
|
|
type: "slide",
|
|
duration: 400,
|
|
from: {position: {
|
|
my: "center",
|
|
at: "center",
|
|
of: window
|
|
}},
|
|
to: {position: {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: window
|
|
}}
|
|
}
|
|
}}
|
|
};
|
|
optionConfigurator.dxScrollable = function(device) {
|
|
if (isSimulationMode(device))
|
|
return {
|
|
useNative: false,
|
|
useSimulatedScrollBar: true
|
|
};
|
|
else if (device.platform === "android" && !isChromeBrowser)
|
|
return {useSimulatedScrollBar: true}
|
|
};
|
|
optionConfigurator.dxScrollView = function(device) {
|
|
var result = optionConfigurator.dxScrollable(device) || {};
|
|
var realDevice = DevExpress.devices.real;
|
|
if (realDevice.platform === "ios" || device.platform === "desktop" || device.platform === "generic")
|
|
$.extend(result, {refreshStrategy: "pullDown"});
|
|
if (realDevice.platform === "android")
|
|
$.extend(result, {refreshStrategy: "swipeDown"});
|
|
if (realDevice.platform === "win8")
|
|
$.extend(result, {refreshStrategy: "slideDown"});
|
|
return result
|
|
};
|
|
optionConfigurator.dxList = function(device) {
|
|
var result = optionConfigurator.dxScrollable(device) || {};
|
|
if ("useNative" in result) {
|
|
result.useNativeScrolling = result.useNative;
|
|
delete result.useNative
|
|
}
|
|
delete result.useSimulatedScrollBar;
|
|
if (device.platform === "desktop")
|
|
$.extend(result, {
|
|
showNextButton: true,
|
|
autoPagingEnabled: false,
|
|
editConfig: {selectionMode: "control"}
|
|
});
|
|
if (device.platform === "ios" || device.platform === "ios7")
|
|
$.extend(result, {editConfig: {deleteMode: device.version === 7 ? "slideItem" : "slideButton"}});
|
|
if (device.platform === "android")
|
|
$.extend(result, {editConfig: {deleteMode: "swipe"}});
|
|
if (device.platform === "win8")
|
|
$.extend(result, {editConfig: {deleteMode: "hold"}});
|
|
if (device.platform === "generic")
|
|
$.extend(result, {editConfig: {deleteMode: "slideItem"}});
|
|
return result
|
|
};
|
|
optionConfigurator.dxToast = function(device) {
|
|
if (device.platform === "win8")
|
|
return {
|
|
position: {
|
|
my: "top center",
|
|
at: "top center",
|
|
of: window,
|
|
offset: "0 0"
|
|
},
|
|
width: function() {
|
|
return $(window).width() - 20
|
|
},
|
|
height: "35px"
|
|
}
|
|
};
|
|
optionConfigurator.dxToolbar = function(device) {
|
|
if (device.platform === "ios")
|
|
return {submenuType: "dxActionSheet"};
|
|
if (device.platform === "win8")
|
|
return {submenuType: "dxList"};
|
|
if (device.platform === "android")
|
|
return {submenuType: "dxDropDownMenu"}
|
|
};
|
|
DX.ui.optionsByDevice = function(device, componentName) {
|
|
var configurator = optionConfigurator[componentName];
|
|
return configurator && configurator(device)
|
|
}
|
|
})(jQuery, DevExpress)
|
|
}
|
|
if (!DevExpress.MOD_WIDGETS) {
|
|
if (!window.DevExpress)
|
|
throw Error('Required module is not referenced: core');
|
|
/*! Module widgets, file ui.scrollable.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var SCROLLABLE = "dxScrollable",
|
|
SCROLLABLE_CLASS = "dx-scrollable",
|
|
SCROLLABLE_DISABLED_CLASS = "dx-scrollable-disabled",
|
|
SCROLLABLE_CONTAINER_CLASS = "dx-scrollable-container",
|
|
SCROLLABLE_CONTENT_CLASS = "dx-scrollable-content",
|
|
VERTICAL = "vertical",
|
|
HORIZONTAL = "horizontal",
|
|
BOTH = "both";
|
|
ui.registerComponent(SCROLLABLE, ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
scrollAction: null,
|
|
direction: VERTICAL,
|
|
showScrollbar: true,
|
|
useNative: true,
|
|
updateAction: null,
|
|
useSimulatedScrollBar: false,
|
|
inertiaEnabled: true,
|
|
bounceEnabled: true,
|
|
startAction: null,
|
|
endAction: null,
|
|
bounceAction: null,
|
|
stopAction: null
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initMarkup();
|
|
this._attachWindowResizeCallback();
|
|
this._attachNativeScrollbarsCustomizationCss();
|
|
this._locked = false
|
|
},
|
|
_initMarkup: function() {
|
|
var $element = this._element().addClass(SCROLLABLE_CLASS),
|
|
$container = this._$container = $("<div>").addClass(SCROLLABLE_CONTAINER_CLASS),
|
|
$content = this._$content = $("<div>").addClass(SCROLLABLE_CONTENT_CLASS);
|
|
$content.append($element.contents()).appendTo($container);
|
|
$container.appendTo($element)
|
|
},
|
|
_attachWindowResizeCallback: function() {
|
|
var self = this;
|
|
self._windowResizeCallback = function() {
|
|
self.update()
|
|
};
|
|
DX.utils.windowResizeCallbacks.add(self._windowResizeCallback)
|
|
},
|
|
_attachNativeScrollbarsCustomizationCss: function() {
|
|
if (!(navigator.platform.indexOf('Mac') > -1 && DevExpress.browser['webkit']))
|
|
this._element().addClass("dx-scrollable-customizable-scrollbars")
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._renderDisabledState();
|
|
this._renderDirection();
|
|
this._createStrategy();
|
|
this._createActions();
|
|
this.update()
|
|
},
|
|
_renderDisabledState: function() {
|
|
this._$element.toggleClass(SCROLLABLE_DISABLED_CLASS, this.option("disabled"))
|
|
},
|
|
_renderDirection: function() {
|
|
this._element().removeClass("dx-scrollable-" + HORIZONTAL).removeClass("dx-scrollable-" + VERTICAL).removeClass("dx-scrollable-" + BOTH).addClass("dx-scrollable-" + this.option("direction"))
|
|
},
|
|
_createStrategy: function() {
|
|
this._strategy = this.option("useNative") || DX.designMode ? new ui.NativeScrollableStrategy(this) : new ui.SimulatedScrollableStrategy(this);
|
|
this._strategy.render()
|
|
},
|
|
_createActions: function() {
|
|
this._strategy.createActions()
|
|
},
|
|
_clean: function() {
|
|
this._strategy.dispose()
|
|
},
|
|
_dispose: function() {
|
|
this._detachWindowResizeCallback();
|
|
this.callBase()
|
|
},
|
|
_detachWindowResizeCallback: function() {
|
|
DX.utils.windowResizeCallbacks.remove(this._windowResizeCallback)
|
|
},
|
|
_optionChanged: function(optionName) {
|
|
switch (optionName) {
|
|
case"disabled":
|
|
this._renderDisabledState();
|
|
break;
|
|
case"startAction":
|
|
case"endAction":
|
|
case"stopAction":
|
|
case"updateAction":
|
|
case"scrollAction":
|
|
case"bounceAction":
|
|
this._createActions();
|
|
break;
|
|
case"direction":
|
|
case"showScrollbar":
|
|
case"useSimulatedScrollBar":
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_location: function() {
|
|
return this._strategy.location()
|
|
},
|
|
_normalizeLocation: function(location) {
|
|
var direction = this.option("direction");
|
|
return {
|
|
x: $.isPlainObject(location) ? -location.x || 0 : direction !== VERTICAL ? -location : 0,
|
|
y: $.isPlainObject(location) ? -location.y || 0 : direction !== HORIZONTAL ? -location : 0
|
|
}
|
|
},
|
|
_isLocked: function() {
|
|
return this._locked
|
|
},
|
|
_lock: function() {
|
|
this._locked = true
|
|
},
|
|
_unlock: function() {
|
|
this._locked = false
|
|
},
|
|
content: function() {
|
|
return this._$content
|
|
},
|
|
scrollOffset: function() {
|
|
var location = this._location();
|
|
return {
|
|
top: -location.top,
|
|
left: -location.left
|
|
}
|
|
},
|
|
clientHeight: function() {
|
|
return this._$container.height()
|
|
},
|
|
scrollHeight: function() {
|
|
return this.content().height()
|
|
},
|
|
clientWidth: function() {
|
|
return this._$container.width()
|
|
},
|
|
scrollWidth: function() {
|
|
return this.content().width()
|
|
},
|
|
update: function() {
|
|
this._strategy.update();
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
scrollBy: function(distance) {
|
|
distance = this._normalizeLocation(distance);
|
|
this._strategy.scrollBy(distance)
|
|
},
|
|
scrollTo: function(targetLocation) {
|
|
targetLocation = this._normalizeLocation(targetLocation);
|
|
var location = this._location();
|
|
this.scrollBy({
|
|
x: location.left - targetLocation.x,
|
|
y: location.top - targetLocation.y
|
|
})
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollbar.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var SCROLLBAR = "dxScrollbar",
|
|
SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar",
|
|
SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll",
|
|
SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
|
|
VERTICAL = "vertical",
|
|
HORIZONTAL = "horizontal";
|
|
ui.registerComponent(SCROLLBAR, ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
direction: null,
|
|
visible: false,
|
|
activeStateEnabled: false
|
|
})
|
|
},
|
|
_renderThumb: function() {
|
|
this._$thumb = $("<div>").addClass(SCROLLABLE_SCROLL_CLASS);
|
|
this._element().addClass(SCROLLABLE_SCROLLBAR_CLASS).append(this._$thumb)
|
|
},
|
|
_render: function() {
|
|
this._renderThumb();
|
|
this.callBase();
|
|
var direction = this.option("direction");
|
|
this._element().addClass("dx-scrollbar-" + direction);
|
|
this._dimension = direction === HORIZONTAL ? "width" : "height";
|
|
this._prop = direction === HORIZONTAL ? "left" : "top"
|
|
},
|
|
_renderDimensions: function() {
|
|
this._$thumb.height(this.option("height"));
|
|
this._$thumb.width(this.option("width"))
|
|
},
|
|
_toggleVisibility: function(visible) {
|
|
visible = visible && this._containerToContentRatio < 1;
|
|
this._$thumb.toggleClass("dx-state-invisible", !visible)
|
|
},
|
|
moveTo: function(location) {
|
|
if ($.isPlainObject(location))
|
|
location = location[this._prop] || 0;
|
|
var scrollBarLocation = {};
|
|
scrollBarLocation[this._prop] = this._calculateScrollBarPosition(location);
|
|
DX.translator.move(this._$thumb, scrollBarLocation)
|
|
},
|
|
_calculateScrollBarPosition: function(location) {
|
|
return -location * this._containerToContentRatio
|
|
},
|
|
update: function(containerSize, contentSize) {
|
|
containerSize = this._normalizeSize(containerSize);
|
|
contentSize = this._normalizeSize(contentSize);
|
|
this._containerToContentRatio = containerSize / contentSize;
|
|
var scrollSize = containerSize * this._containerToContentRatio;
|
|
this.option(this._dimension, scrollSize)
|
|
},
|
|
_normalizeSize: function(size) {
|
|
return $.isPlainObject(size) ? size[this._dimension] || 0 : size
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollable.native.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
devices = DX.devices,
|
|
abs = Math.abs;
|
|
var SCROLLABLE_NATIVE = "dxNativeScrollable",
|
|
SCROLLABLE_NATIVE_CLASS = "dx-scrollable-native",
|
|
SCROLLABLE_SCROLLBAR_SIMULATED = "dx-scrollable-scrollbar-simulated",
|
|
SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
|
|
VERTICAL = "vertical",
|
|
HORIZONTAL = "horizontal",
|
|
HIDE_SCROLLBAR_TIMOUT = 500,
|
|
GESTURE_LOCK_KEY = "dxGesture";
|
|
ui.NativeScrollableStrategy = DX.Class.inherit({
|
|
ctor: function(scrollable) {
|
|
this._init(scrollable);
|
|
this._attachScrollHandler()
|
|
},
|
|
_init: function(scrollable) {
|
|
this._component = scrollable;
|
|
this._$element = scrollable._element();
|
|
this._$container = scrollable._$container;
|
|
this._$content = scrollable._$content;
|
|
this.option = $.proxy(scrollable.option, scrollable);
|
|
this._createActionByOption = $.proxy(scrollable._createActionByOption, scrollable);
|
|
this._useSimulatedScrollBar = scrollable.option("useSimulatedScrollBar");
|
|
this._direction = scrollable.option("direction");
|
|
this._isLocked = $.proxy(scrollable._isLocked, scrollable)
|
|
},
|
|
_attachScrollHandler: function() {
|
|
$(this._$container).on(events.addNamespace("scroll", SCROLLABLE_NATIVE), $.proxy(this._handleScroll, this))
|
|
},
|
|
render: function() {
|
|
this._$element.addClass(SCROLLABLE_NATIVE_CLASS);
|
|
this._$element.addClass(SCROLLABLE_NATIVE_CLASS + "-" + devices.real.platform);
|
|
this._renderScrollbar()
|
|
},
|
|
_renderScrollbar: function() {
|
|
this._scrollbars = {};
|
|
this._$element.toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this.option("showScrollbar"));
|
|
if (!this.option("showScrollbar"))
|
|
return;
|
|
if (!this._useSimulatedScrollBar)
|
|
return;
|
|
if (this._direction !== HORIZONTAL) {
|
|
var $scrollbarVertical = $("<div>").dxScrollbar({
|
|
direction: VERTICAL,
|
|
disable: this._useSimulatedScrollBar
|
|
}).appendTo(this._$element);
|
|
this._scrollbars[VERTICAL] = $scrollbarVertical.dxScrollbar("instance")
|
|
}
|
|
if (this._direction !== VERTICAL) {
|
|
var $scrollbarHorizontal = $("<div>").dxScrollbar({
|
|
direction: HORIZONTAL,
|
|
disable: this._useSimulatedScrollBar
|
|
}).appendTo(this._$element);
|
|
this._scrollbars[VERTICAL] = $scrollbarHorizontal.dxScrollbar("instance")
|
|
}
|
|
this._hideScrollbarTimeout = 0;
|
|
this._$element.addClass(SCROLLABLE_SCROLLBAR_SIMULATED)
|
|
},
|
|
createActions: function() {
|
|
var actionConfig = {excludeValidators: ["gesture"]};
|
|
this._scrollAction = this._createActionByOption("scrollAction", actionConfig);
|
|
this._updateAction = this._createActionByOption("updateAction", actionConfig)
|
|
},
|
|
_createActionArgs: function() {
|
|
var location = this.location();
|
|
return {
|
|
jQueryEvent: eventForUserAction,
|
|
scrollOffset: {
|
|
top: -location.top,
|
|
left: -location.left
|
|
},
|
|
reachedLeft: this._direction !== VERTICAL ? location.left >= 0 : undefined,
|
|
reachedRight: this._direction !== VERTICAL ? location.left <= this._containerSize.width - this._contentSize.width : undefined,
|
|
reachedTop: this._direction !== HORIZONTAL ? location.top >= 0 : undefined,
|
|
reachedBottom: this._direction !== HORIZONTAL ? location.top <= this._containerSize.height - this._contentSize.height : undefined
|
|
}
|
|
},
|
|
dispose: function() {
|
|
if (this === activeScrollable)
|
|
activeScrollable = null;
|
|
$(this._$container).off(events.addNamespace("scroll", SCROLLABLE_NATIVE));
|
|
this._removeScrollbars();
|
|
clearTimeout(this._gestureEndTimer)
|
|
},
|
|
_removeScrollbars: function() {
|
|
$.each(this._scrollbars, function() {
|
|
this._element().remove()
|
|
})
|
|
},
|
|
_handleScroll: function(e) {
|
|
if (!this._isScrollLocationChanged()) {
|
|
e.stopImmediatePropagation();
|
|
return
|
|
}
|
|
eventForUserAction = e;
|
|
this._moveScrollbars();
|
|
this._scrollAction(this._createActionArgs());
|
|
this._treatNativeGesture();
|
|
this._lastLocation = this.location()
|
|
},
|
|
_isScrollLocationChanged: function() {
|
|
var currentLocation = this.location(),
|
|
lastLocation = this._lastLocation || {},
|
|
isTopChanged = lastLocation.top !== currentLocation.top,
|
|
isLeftChanged = lastLocation.left !== currentLocation.left;
|
|
return isTopChanged || isLeftChanged
|
|
},
|
|
_moveScrollbars: function() {
|
|
var self = this;
|
|
$.each(self._scrollbars, function() {
|
|
this.moveTo(self.location());
|
|
this.option("visible", true)
|
|
});
|
|
this._hideScrollbars()
|
|
},
|
|
_hideScrollbars: function() {
|
|
var self = this;
|
|
clearTimeout(self._hideScrollbarTimeout);
|
|
self._hideScrollbarTimeout = setTimeout(function() {
|
|
$.each(self._scrollbars, function() {
|
|
this.option("visible", false)
|
|
})
|
|
}, HIDE_SCROLLBAR_TIMOUT)
|
|
},
|
|
_treatNativeGesture: function() {
|
|
this._prepareGesture();
|
|
this._forgetGesture()
|
|
},
|
|
_prepareGesture: function() {
|
|
if (this._gestureEndTimer) {
|
|
clearTimeout(this._gestureEndTimer);
|
|
this._gestureEndTimer = null
|
|
}
|
|
else
|
|
this._$element.data(GESTURE_LOCK_KEY, true);
|
|
ui.feedback.reset()
|
|
},
|
|
_forgetGesture: function() {
|
|
this._gestureEndTimer = setTimeout($.proxy(function() {
|
|
this._$element.data(GESTURE_LOCK_KEY, false);
|
|
this._gestureEndTimer = null
|
|
}, this), 400)
|
|
},
|
|
location: function() {
|
|
return {
|
|
left: -this._$container.scrollLeft(),
|
|
top: -this._$container.scrollTop()
|
|
}
|
|
},
|
|
update: function() {
|
|
this._updateDimensions();
|
|
this._updateAction(this._createActionArgs());
|
|
this._updateScrollbars()
|
|
},
|
|
_updateDimensions: function() {
|
|
this._containerSize = {
|
|
height: this._$container.height(),
|
|
width: this._$container.width()
|
|
};
|
|
this._contentSize = {
|
|
height: this._component.content().height(),
|
|
width: this._component.content().width()
|
|
}
|
|
},
|
|
_updateScrollbars: function() {
|
|
if (!this._useSimulatedScrollBar)
|
|
return;
|
|
var self = this,
|
|
containerSize = this._containerSize,
|
|
contentSize = this._contentSize;
|
|
$.each(self._scrollbars, function() {
|
|
this.update(containerSize, contentSize)
|
|
})
|
|
},
|
|
_handleStart: $.noop,
|
|
_handleMove: $.noop,
|
|
_handleEnd: $.noop,
|
|
scrollBy: function(distance) {
|
|
var location = this.location();
|
|
this._$container.scrollTop(-location.top - distance.y);
|
|
this._$container.scrollLeft(-location.left - distance.x)
|
|
}
|
|
});
|
|
var STAGE_SLEEP = 0,
|
|
STAGE_TOUCHED = 1,
|
|
STAGE_SCROLLING = 2;
|
|
var activeScrollable,
|
|
scrollStage = STAGE_SLEEP,
|
|
parentsLength,
|
|
eventForUserAction,
|
|
startEventData = null;
|
|
var GESTURE_LOCK_DISTANCE = 10;
|
|
var closestScrollable = function(element) {
|
|
var $closestScrollable = $(element).closest("." + SCROLLABLE_NATIVE_CLASS);
|
|
if (!$closestScrollable.length)
|
|
return;
|
|
var components = $closestScrollable.data("dxComponents"),
|
|
scrollable;
|
|
$.each(components, function(index, componentName) {
|
|
var componentClass = ui[componentName];
|
|
if (componentClass === ui.dxScrollable || componentClass.subclassOf(ui.dxScrollable)) {
|
|
scrollable = $closestScrollable.data(componentName);
|
|
return false
|
|
}
|
|
});
|
|
return scrollable && scrollable.option("disabled") ? closestScrollable($closestScrollable.parent()) : scrollable._strategy
|
|
};
|
|
var reset = function() {
|
|
scrollStage = STAGE_SLEEP;
|
|
activeScrollable = null
|
|
};
|
|
var preventHangingCursorAndHideKeyboard = function(e) {
|
|
if (devices.real.platform !== "ios")
|
|
return;
|
|
var focusedElementInScrollable = $(":focus", activeScrollable._$element).length,
|
|
closestTextarea = $(e.target).closest("textarea").length;
|
|
if (focusedElementInScrollable && !closestTextarea)
|
|
DX.utils.resetActiveElement()
|
|
};
|
|
var handleStart = function(e) {
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
activeScrollable = closestScrollable(e.target);
|
|
if (activeScrollable) {
|
|
parentsLength = activeScrollable._$element.parents().length;
|
|
scrollStage = STAGE_TOUCHED;
|
|
activeScrollable._handleStart(e);
|
|
startEventData = events.eventData(e)
|
|
}
|
|
};
|
|
var handleBodyPointerMove = function(e) {
|
|
if (activeScrollable && scrollStage == STAGE_TOUCHED && e.originalEvent) {
|
|
var pointerMoveData = e.originalEvent.pointerMoveData || {},
|
|
direction = activeScrollable.option("direction"),
|
|
directionValue = pointerMoveData[direction];
|
|
if (directionValue && directionValue > parentsLength) {
|
|
handleEnd();
|
|
return
|
|
}
|
|
pointerMoveData[direction] = parentsLength;
|
|
e.originalEvent.pointerMoveData = pointerMoveData
|
|
}
|
|
};
|
|
var handleMove = function(e) {
|
|
if (activeScrollable) {
|
|
var pointerMoveData = e.originalEvent.pointerMoveData,
|
|
direction = activeScrollable.option("direction");
|
|
if (pointerMoveData && pointerMoveData[direction] !== parentsLength)
|
|
return;
|
|
e.originalEvent.isScrollingEvent = true;
|
|
if (activeScrollable._isLocked()) {
|
|
e.preventDefault();
|
|
return
|
|
}
|
|
if (scrollStage == STAGE_TOUCHED) {
|
|
preventHangingCursorAndHideKeyboard(e);
|
|
scrollStage = STAGE_SCROLLING
|
|
}
|
|
activeScrollable._handleMove(e);
|
|
if (startEventData) {
|
|
var delta = events.eventDelta(startEventData, events.eventData(e));
|
|
if (abs(delta.x) > GESTURE_LOCK_DISTANCE || abs(delta.y) > GESTURE_LOCK_DISTANCE) {
|
|
activeScrollable._prepareGesture();
|
|
startEventData = null
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var handleEnd = function(e) {
|
|
if (activeScrollable) {
|
|
activeScrollable._handleEnd(e);
|
|
activeScrollable._forgetGesture();
|
|
reset()
|
|
}
|
|
};
|
|
$(function() {
|
|
var actionArguments = {
|
|
context: ui.dxScrollable,
|
|
excludeValidators: ["gesture", "designMode"]
|
|
},
|
|
startAction = new DX.Action(handleStart, actionArguments),
|
|
scrollAction = new DX.Action(handleMove, actionArguments),
|
|
endAction = new DX.Action(handleEnd, actionArguments),
|
|
bodyMoveAction = new DX.Action(handleBodyPointerMove, actionArguments);
|
|
$("body").on(events.addNamespace("dxpointermove", SCROLLABLE_NATIVE), function(e) {
|
|
bodyMoveAction.execute(e)
|
|
});
|
|
$(document).on(events.addNamespace("dxpointerdown", SCROLLABLE_NATIVE), function(e) {
|
|
startAction.execute(e)
|
|
}).on(events.addNamespace("dxpointermove", SCROLLABLE_NATIVE), function(e) {
|
|
scrollAction.execute(e)
|
|
}).on(events.addNamespace("dxpointerup dxpointercancel", SCROLLABLE_NATIVE), function(e) {
|
|
endAction.execute(e)
|
|
})
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollable.simulated.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
math = Math;
|
|
var SCROLLABLE_SIMULATED = "dxSimulatedScrollable",
|
|
SCROLLABLE_SIMULATED_CLASS = "dx-scrollable-simulated",
|
|
SCROLLBAR = "dxScrollbar",
|
|
SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar",
|
|
SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll",
|
|
SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
|
|
VERTICAL = "vertical",
|
|
HORIZONTAL = "horizontal",
|
|
ACCELERATION = 0.92,
|
|
OUT_BOUNDS_ACCELERATION = 0.5,
|
|
BOUNCE_DURATION = 400,
|
|
MIN_VELOCITY_LIMIT = 1,
|
|
MIN_BOUNCE_VELOCITY_LIMIT = MIN_VELOCITY_LIMIT / 5,
|
|
FRAME_DURATION = math.round(1000 / 60),
|
|
BOUNCE_FRAMES = BOUNCE_DURATION / FRAME_DURATION,
|
|
BOUNCE_ACCELERATION_SUM = (1 - math.pow(ACCELERATION, BOUNCE_FRAMES)) / (1 - ACCELERATION),
|
|
ELASTIC = OUT_BOUNDS_ACCELERATION,
|
|
GESTURE_LOCK_KEY = "dxGesture";
|
|
var InertiaAnimator = DX.Animator.inherit({
|
|
ctor: function(scroller) {
|
|
this.callBase();
|
|
this.scroller = scroller
|
|
},
|
|
VELOCITY_LIMIT: MIN_VELOCITY_LIMIT,
|
|
_isFinished: function() {
|
|
return math.abs(this.scroller._velocity) <= this.VELOCITY_LIMIT
|
|
},
|
|
_step: function() {
|
|
this.scroller._scrollStep(this.scroller._velocity);
|
|
this.scroller._velocity *= this._acceleration()
|
|
},
|
|
_acceleration: function() {
|
|
return this.scroller._inBounds() ? ACCELERATION : OUT_BOUNDS_ACCELERATION
|
|
},
|
|
_complete: function() {
|
|
this.scroller._scrollComplete()
|
|
},
|
|
_stop: function() {
|
|
this.scroller._handleStop()
|
|
}
|
|
});
|
|
var BounceAnimator = InertiaAnimator.inherit({
|
|
VELOCITY_LIMIT: MIN_BOUNCE_VELOCITY_LIMIT,
|
|
_isFinished: function() {
|
|
return this.scroller._crossBoundOnNextStep() || this.callBase()
|
|
},
|
|
_acceleration: function() {
|
|
return ACCELERATION
|
|
},
|
|
_complete: function() {
|
|
this.scroller._move(this.scroller._bounceLocation);
|
|
this.callBase()
|
|
}
|
|
});
|
|
var Scroller = ui.Scroller = DX.Class.inherit({
|
|
ctor: function(options) {
|
|
this._initOptions(options);
|
|
this._initAnimators();
|
|
this._initScrollbar();
|
|
this._initCallbacks();
|
|
this._topReached = false;
|
|
this._bottomReached = false
|
|
},
|
|
_initOptions: function(options) {
|
|
var self = this;
|
|
this._location = 0;
|
|
this._axis = options.direction === HORIZONTAL ? "x" : "y";
|
|
this._prop = options.direction === HORIZONTAL ? "left" : "top";
|
|
this._dimension = options.direction === HORIZONTAL ? "width" : "height";
|
|
this._scrollProp = options.direction === HORIZONTAL ? "scrollLeft" : "scrollTop";
|
|
$.each(options, function(optionName, optionValue) {
|
|
self["_" + optionName] = optionValue
|
|
})
|
|
},
|
|
_initAnimators: function() {
|
|
this._inertiaAnimator = new InertiaAnimator(this);
|
|
this._bounceAnimator = new BounceAnimator(this)
|
|
},
|
|
_initScrollbar: function() {
|
|
this._$scrollbar = $("<div>").dxScrollbar({direction: this._direction}).appendTo(this._$container);
|
|
this._scrollbar = this._$scrollbar.dxScrollbar("instance")
|
|
},
|
|
_initCallbacks: function() {
|
|
this.topBouncedCallbacks = $.Callbacks();
|
|
this.bottomBouncedCallbacks = $.Callbacks()
|
|
},
|
|
_scrollStep: function(delta) {
|
|
this._location = this._location + delta;
|
|
this._suppressBounce();
|
|
this._move();
|
|
this._scrollAction()
|
|
},
|
|
_move: function(location) {
|
|
this._location = location !== undefined ? location : this._location;
|
|
this._moveContent();
|
|
this._moveScrollbar()
|
|
},
|
|
_moveContent: function() {
|
|
var targetLocation = {};
|
|
targetLocation[this._prop] = this._location;
|
|
DX.translator.move(this._$content, targetLocation)
|
|
},
|
|
_moveScrollbar: function() {
|
|
this._scrollbar.moveTo(this._calculateScrollBarPosition())
|
|
},
|
|
_calculateScrollBarPosition: function() {
|
|
return this._location
|
|
},
|
|
_suppressBounce: function() {
|
|
if (this._bounceEnabled || this._inBounds(this._location))
|
|
return;
|
|
this._velocity = 0;
|
|
this._location = this._boundLocation()
|
|
},
|
|
_boundLocation: function() {
|
|
var location = this._location;
|
|
if (location > this._maxOffset)
|
|
location = this._maxOffset;
|
|
else if (location < this._minOffset)
|
|
location = this._minOffset;
|
|
return location
|
|
},
|
|
_scrollComplete: function() {
|
|
if (this._inBounds()) {
|
|
this._hideScrollbar();
|
|
this._roundLocation();
|
|
if (this._completeDeferred)
|
|
this._completeDeferred.resolve()
|
|
}
|
|
this._scrollToBounds()
|
|
},
|
|
_roundLocation: function() {
|
|
this._location = math.round(this._location);
|
|
this._move()
|
|
},
|
|
_scrollToBounds: function() {
|
|
if (this._inBounds())
|
|
return;
|
|
this._bounceAction();
|
|
this._setupBounce();
|
|
this._bounceAnimator.start()
|
|
},
|
|
_setupBounce: function() {
|
|
var boundLocation = this._bounceLocation = this._boundLocation(),
|
|
bounceDistance = boundLocation - this._location;
|
|
this._velocity = bounceDistance / BOUNCE_ACCELERATION_SUM
|
|
},
|
|
_inBounds: function(location) {
|
|
location = location !== undefined ? location : this._location;
|
|
return location >= this._minOffset && location <= this._maxOffset
|
|
},
|
|
_crossBoundOnNextStep: function() {
|
|
var location = this._location,
|
|
nextLocation = location + this._velocity;
|
|
return location < this._minOffset && nextLocation >= this._minOffset || location > this._maxOffset && nextLocation <= this._maxOffset
|
|
},
|
|
_handleStart: function($target) {
|
|
this._stopDeferred = $.Deferred();
|
|
this._stopScrolling();
|
|
this._update();
|
|
return this._stopDeferred.promise()
|
|
},
|
|
_stopScrolling: function() {
|
|
this._hideScrollbar();
|
|
this._inertiaAnimator.stop();
|
|
this._bounceAnimator.stop()
|
|
},
|
|
_handleStop: function() {
|
|
if (this._stopDeferred)
|
|
this._stopDeferred.resolve()
|
|
},
|
|
_handleFirstMove: function() {
|
|
this._showScrollbar()
|
|
},
|
|
_handleMove: function(delta) {
|
|
delta = delta[this._axis];
|
|
if (!this._inBounds())
|
|
delta *= ELASTIC;
|
|
this._scrollStep(delta)
|
|
},
|
|
_handleMoveEnd: function(velocity) {
|
|
this._completeDeferred = $.Deferred();
|
|
this._velocity = velocity[this._axis];
|
|
this._suppressVelocity();
|
|
this._handleInertia();
|
|
return this._completeDeferred.promise()
|
|
},
|
|
_suppressVelocity: function() {
|
|
if (!this._inertiaEnabled)
|
|
this._velocity = 0
|
|
},
|
|
_handleTapEnd: function() {
|
|
this._scrollToBounds()
|
|
},
|
|
_handleInertia: function() {
|
|
this._inertiaAnimator.start()
|
|
},
|
|
_handleDispose: function() {
|
|
this._$scrollbar.remove()
|
|
},
|
|
_handleUpdate: function() {
|
|
this._update();
|
|
this._moveToBounds()
|
|
},
|
|
_update: function() {
|
|
this._stopScrolling();
|
|
this._updateLocation();
|
|
this._updateBounds();
|
|
this._updateScrollbar();
|
|
this._moveScrollbar()
|
|
},
|
|
_updateLocation: function() {
|
|
this._location = DX.translator.locate(this._$content)[this._prop]
|
|
},
|
|
_updateBounds: function() {
|
|
this._maxOffset = 0;
|
|
this._minOffset = math.min(this._containerSize() - this._contentSize(), 0)
|
|
},
|
|
_updateScrollbar: function() {
|
|
this._scrollbar.update(this._containerSize(), this._contentSize())
|
|
},
|
|
_moveToBounds: function() {
|
|
this._location = this._boundLocation();
|
|
this._move()
|
|
},
|
|
_handleCreateActions: function(actions) {
|
|
this._scrollAction = actions.scrollAction;
|
|
this._bounceAction = actions.bounceAction
|
|
},
|
|
_showScrollbar: function() {
|
|
this._scrollbar.option("visible", this._scrollbarVisible)
|
|
},
|
|
_hideScrollbar: function() {
|
|
this._scrollbar.option("visible", false)
|
|
},
|
|
_containerSize: function() {
|
|
return this._$container[this._dimension]()
|
|
},
|
|
_contentSize: function() {
|
|
return this._$content[this._dimension]()
|
|
},
|
|
_validateTarget: function($target) {
|
|
return $target.closest(this._$container)
|
|
},
|
|
_validateDirection: function(deltaEventData) {
|
|
return math.abs(deltaEventData[this._axis]) >= math.abs(deltaEventData[this._axis === "x" ? "y" : "x"])
|
|
},
|
|
_reachedMin: function() {
|
|
return this._location <= this._minOffset
|
|
},
|
|
_reachedMax: function() {
|
|
return this._location >= this._maxOffset
|
|
}
|
|
});
|
|
ui.SimulatedScrollableStrategy = DX.Class.inherit({
|
|
ctor: function(scrollable) {
|
|
this._init(scrollable);
|
|
this._attachScrollHandler()
|
|
},
|
|
_init: function(scrollable) {
|
|
this._component = scrollable;
|
|
this._$element = scrollable._element();
|
|
this._$container = scrollable._$container;
|
|
this._$content = scrollable._$content;
|
|
this.option = $.proxy(scrollable.option, scrollable);
|
|
this._createActionByOption = $.proxy(scrollable._createActionByOption, scrollable);
|
|
this._isLocked = $.proxy(scrollable._isLocked, scrollable)
|
|
},
|
|
_attachScrollHandler: function() {
|
|
$(this._$container).on(events.addNamespace("scroll", SCROLLABLE_SIMULATED), $.proxy(this._handleScroll, this))
|
|
},
|
|
_handleScroll: function(e) {
|
|
var distance = {
|
|
x: this._$container.scrollLeft(),
|
|
y: this._$container.scrollTop()
|
|
};
|
|
this._$container.scrollLeft(-distance.x);
|
|
this._$container.scrollTop(-distance.y);
|
|
this.scrollBy(distance)
|
|
},
|
|
render: function() {
|
|
this._$element.addClass(SCROLLABLE_SIMULATED_CLASS);
|
|
this._createScrollers()
|
|
},
|
|
_createScrollers: function() {
|
|
var direction = this.option("direction");
|
|
this._scrollers = {};
|
|
if (direction !== VERTICAL)
|
|
this._createScroller(HORIZONTAL);
|
|
if (direction !== HORIZONTAL)
|
|
this._createScroller(VERTICAL);
|
|
this._$element.toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this.option("showScrollbar"))
|
|
},
|
|
_createScroller: function(direction) {
|
|
this._scrollers[direction] = new Scroller(this._scrollerOptions(direction))
|
|
},
|
|
_scrollerOptions: function(direction) {
|
|
return {
|
|
direction: direction,
|
|
$content: this._$content,
|
|
$container: this._$container,
|
|
scrollbarVisible: this.option("showScrollbar"),
|
|
bounceEnabled: this.option("bounceEnabled"),
|
|
inertiaEnabled: this.option("inertiaEnabled")
|
|
}
|
|
},
|
|
createActions: function() {
|
|
this._startAction = this._createActionHandler("startAction");
|
|
this._stopAction = this._createActionHandler("stopAction");
|
|
this._endAction = this._createActionHandler("endAction");
|
|
this._updateAction = this._createActionHandler("updateAction");
|
|
this._createScrollerActions()
|
|
},
|
|
_createScrollerActions: function() {
|
|
this._handleEvent("CreateActions", {
|
|
scrollAction: this._createActionHandler("scrollAction"),
|
|
bounceAction: this._createActionHandler("bounceAction")
|
|
})
|
|
},
|
|
_createActionHandler: function(optionName) {
|
|
var self = this,
|
|
actionHandler = self._createActionByOption(optionName, {excludeValidators: ["gesture"]});
|
|
return function() {
|
|
actionHandler($.extend(self._createActionArgs(), arguments))
|
|
}
|
|
},
|
|
_createActionArgs: function() {
|
|
var scrollerX = this._scrollers[HORIZONTAL],
|
|
scrollerY = this._scrollers[VERTICAL];
|
|
return {
|
|
jQueryEvent: eventForUserAction,
|
|
scrollOffset: {
|
|
top: scrollerY && -scrollerY._location,
|
|
left: scrollerX && -scrollerX._location
|
|
},
|
|
reachedLeft: scrollerX && scrollerX._reachedMax(),
|
|
reachedRight: scrollerX && scrollerX._reachedMin(),
|
|
reachedTop: scrollerY && scrollerY._reachedMax(),
|
|
reachedBottom: scrollerY && scrollerY._reachedMin()
|
|
}
|
|
},
|
|
dispose: function() {
|
|
if (this === activeScrollable)
|
|
activeScrollable = null;
|
|
this._handleEvent("Dispose");
|
|
this._detachScrollHandler();
|
|
this._startAction = null;
|
|
this._stopAction = null;
|
|
this._endAction = null;
|
|
this._updateAction = null;
|
|
clearTimeout(this._gestureEndTimer)
|
|
},
|
|
_detachScrollHandler: function() {
|
|
$(this._$container).off(events.addNamespace("scroll", SCROLLABLE_SIMULATED), this._handleScroll)
|
|
},
|
|
_handleEvent: function(eventName) {
|
|
var args = $.makeArray(arguments).slice(1),
|
|
deferreds = $.map(this._scrollers, function(scroller) {
|
|
return scroller["_handle" + eventName].apply(scroller, args)
|
|
});
|
|
return $.when.apply($, deferreds).promise()
|
|
},
|
|
_handleStart: function($target) {
|
|
this._handleEvent("Start", $target).done($.proxy(this._forgetGesture, this)).done(this._stopAction)
|
|
},
|
|
_handleFirstMove: function() {
|
|
return this._handleEvent("FirstMove").done(this._startAction)
|
|
},
|
|
_prepareGesture: function() {
|
|
clearTimeout(this._gestureEndTimer);
|
|
this._$element.data(GESTURE_LOCK_KEY, true);
|
|
ui.feedback.reset()
|
|
},
|
|
_handleMove: function(delta) {
|
|
this._handleEvent("Move", delta)
|
|
},
|
|
_handleMoveEnd: function(velocity) {
|
|
return this._handleEvent("MoveEnd", velocity).done(this._endAction)
|
|
},
|
|
_forgetGesture: function() {
|
|
this._gestureEndTimer = setTimeout($.proxy(function() {
|
|
this._$element.data(GESTURE_LOCK_KEY, false)
|
|
}, this), 400)
|
|
},
|
|
_handleTapEnd: function() {
|
|
this._handleEvent("TapEnd")
|
|
},
|
|
location: function() {
|
|
return DX.translator.locate(this._$content)
|
|
},
|
|
_validateTarget: function($target) {
|
|
if (this.option("disabled"))
|
|
return false;
|
|
var result = false;
|
|
$.each(this._scrollers, function() {
|
|
result = result || this._validateTarget($target)
|
|
});
|
|
return result
|
|
},
|
|
_validateDirection: function(deltaEventData) {
|
|
var result = false;
|
|
$.each(this._scrollers, function() {
|
|
result = result || this._validateDirection(deltaEventData)
|
|
});
|
|
return result
|
|
},
|
|
update: function() {
|
|
return this._handleEvent("Update").done(this._updateAction)
|
|
},
|
|
scrollBy: function(distance) {
|
|
this._handleFirstMove();
|
|
this._handleMove(distance);
|
|
this._handleMoveEnd({
|
|
x: 0,
|
|
y: 0
|
|
})
|
|
}
|
|
});
|
|
var STAGE_SLEEP = 0,
|
|
STAGE_TOUCHED = 1,
|
|
STAGE_SCROLLING = 2;
|
|
var INTERTIA_TIMEOUT = 100,
|
|
VELOCITY_CALC_TIMEOUT = 200;
|
|
var activeScrollable,
|
|
parentsLength,
|
|
scrollStage = STAGE_SLEEP,
|
|
prevEventData,
|
|
savedEventData,
|
|
eventForUserAction,
|
|
startEventData = null;
|
|
var GESTURE_LOCK_DISTANCE = 10;
|
|
var closestScrollable = function(element) {
|
|
var $closestScrollable = $(element).closest("." + SCROLLABLE_SIMULATED_CLASS);
|
|
if (!$closestScrollable.length)
|
|
return;
|
|
var components = $closestScrollable.data("dxComponents"),
|
|
scrollable;
|
|
$.each(components, function(index, componentName) {
|
|
var componentClass = ui[componentName];
|
|
if (componentClass === ui.dxScrollable || componentClass.subclassOf(ui.dxScrollable)) {
|
|
scrollable = $closestScrollable.data(componentName);
|
|
return false
|
|
}
|
|
});
|
|
return scrollable && scrollable.option("disabled") ? closestScrollable($closestScrollable.parent()) : scrollable._strategy
|
|
};
|
|
var resetStage = function() {
|
|
scrollStage = STAGE_SLEEP
|
|
};
|
|
var preventHangingCursorAndHideKeyboard = function() {
|
|
DX.utils.resetActiveElement()
|
|
};
|
|
var preventSelectStartEvent = function(e) {
|
|
e.preventDefault()
|
|
};
|
|
var handleStart = function(e) {
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
activeScrollable = closestScrollable(e.target);
|
|
if (activeScrollable && activeScrollable._validateTarget($(e.target))) {
|
|
parentsLength = activeScrollable._$element.parents().length;
|
|
eventForUserAction = e;
|
|
startEventData = prevEventData = savedEventData = events.eventData(e);
|
|
scrollStage = STAGE_TOUCHED;
|
|
activeScrollable._handleStart($(e.target))
|
|
}
|
|
};
|
|
var handleScroll = function(e) {
|
|
if (!activeScrollable)
|
|
return;
|
|
if (e.originalEvent) {
|
|
var pointerMoveData = e.originalEvent.pointerMoveData,
|
|
direction = activeScrollable.option("direction");
|
|
if (pointerMoveData && pointerMoveData[direction] !== parentsLength) {
|
|
resetStage();
|
|
return
|
|
}
|
|
}
|
|
eventForUserAction = e;
|
|
if (scrollStage === STAGE_SLEEP)
|
|
return;
|
|
var currentEventData = events.eventData(e),
|
|
deltaEventData = events.eventDelta(prevEventData, currentEventData);
|
|
if (scrollStage === STAGE_TOUCHED)
|
|
handleFirstMove(deltaEventData);
|
|
if (scrollStage === STAGE_SCROLLING)
|
|
handleMove(currentEventData, deltaEventData)
|
|
};
|
|
var handleFirstMove = function(deltaEventData) {
|
|
if (!activeScrollable._validateDirection(deltaEventData)) {
|
|
resetStage();
|
|
return
|
|
}
|
|
if ($(":focus", activeScrollable._$element).length)
|
|
preventHangingCursorAndHideKeyboard();
|
|
activeScrollable._handleFirstMove();
|
|
scrollStage = STAGE_SCROLLING
|
|
};
|
|
var handleBodyPointerMove = function(e) {
|
|
if (scrollStage === STAGE_TOUCHED && e.originalEvent) {
|
|
var pointerMoveData = e.originalEvent.pointerMoveData || {},
|
|
direction = activeScrollable.option("direction"),
|
|
directionValue = pointerMoveData[direction];
|
|
if (directionValue && directionValue > parentsLength)
|
|
return;
|
|
pointerMoveData[direction] = parentsLength;
|
|
e.originalEvent.pointerMoveData = pointerMoveData
|
|
}
|
|
};
|
|
var handleMove = function(currentEventData, deltaEventData) {
|
|
if (activeScrollable._isLocked()) {
|
|
resetStage();
|
|
return
|
|
}
|
|
if (events.eventDelta(savedEventData, prevEventData).time > VELOCITY_CALC_TIMEOUT)
|
|
savedEventData = prevEventData;
|
|
prevEventData = currentEventData;
|
|
if (startEventData) {
|
|
var delta = events.eventDelta(startEventData, currentEventData);
|
|
if (math.abs(delta.x) > GESTURE_LOCK_DISTANCE || math.abs(delta.y) > GESTURE_LOCK_DISTANCE) {
|
|
activeScrollable._prepareGesture();
|
|
startEventData = null
|
|
}
|
|
}
|
|
activeScrollable._handleMove(deltaEventData)
|
|
};
|
|
var handleEnd = function(e) {
|
|
if (!activeScrollable)
|
|
return;
|
|
eventForUserAction = e;
|
|
if (scrollStage === STAGE_SCROLLING) {
|
|
var endEventData = events.eventData(e),
|
|
deltaEndEventData = events.eventDelta(prevEventData, endEventData),
|
|
velocity = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
if (deltaEndEventData.time < INTERTIA_TIMEOUT) {
|
|
var deltaSavedEventData = events.eventDelta(savedEventData, prevEventData);
|
|
velocity = {
|
|
x: deltaSavedEventData.x * FRAME_DURATION / deltaSavedEventData.time,
|
|
y: deltaSavedEventData.y * FRAME_DURATION / deltaSavedEventData.time
|
|
}
|
|
}
|
|
activeScrollable._handleMoveEnd(velocity).done($.proxy(activeScrollable._forgetGesture, activeScrollable))
|
|
}
|
|
else if (scrollStage === STAGE_TOUCHED)
|
|
activeScrollable._handleTapEnd();
|
|
resetStage()
|
|
};
|
|
var handleWheel = function(e, delta) {
|
|
handleStart(e);
|
|
e.pageY += delta;
|
|
handleScroll(e);
|
|
handleEnd(e)
|
|
};
|
|
$(function() {
|
|
var actionArguments = {
|
|
context: ui.dxScrollable,
|
|
excludeValidators: ["gesture"]
|
|
},
|
|
startAction = new DX.Action(handleStart, actionArguments),
|
|
scrollAction = new DX.Action(handleScroll, actionArguments),
|
|
endAction = new DX.Action(handleEnd, actionArguments),
|
|
bodyMoveAction = new DX.Action(handleBodyPointerMove, actionArguments);
|
|
$("body").on(events.addNamespace("dxpointermove", SCROLLABLE_SIMULATED), function(e) {
|
|
bodyMoveAction.execute(e)
|
|
});
|
|
$(document).on(events.addNamespace("dxpointerdown", SCROLLABLE_SIMULATED), function(e) {
|
|
startAction.execute(e)
|
|
}).on(events.addNamespace("dxpointermove", SCROLLABLE_SIMULATED), function(e) {
|
|
scrollAction.execute(e)
|
|
}).on(events.addNamespace("dxpointerup dxpointercancel", SCROLLABLE_SIMULATED), function(e) {
|
|
endAction.execute(e)
|
|
});
|
|
if ("mousewheel" in $.event.special) {
|
|
var wheelAction = new DX.Action(handleWheel, actionArguments);
|
|
$(document).on(events.addNamespace("mousewheel", SCROLLABLE_SIMULATED), function(e, delta) {
|
|
wheelAction.execute(e, delta)
|
|
})
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollView.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var SCROLLVIEW_CLASS = "dx-scrollview",
|
|
SCROLLVIEW_CONTENT_CLASS = "dx-scrollview-content",
|
|
SCROLLVIEW_TOP_POCKET_CLASS = "dx-scrollview-top-pocket",
|
|
SCROLLVIEW_BOTTOM_POCKET_CLASS = "dx-scrollview-bottom-pocket",
|
|
SCROLLVIEW_PULLDOWN_CLASS = SCROLLVIEW_CLASS + "-pull-down",
|
|
SCROLLVIEW_PULLDOWN_IMAGE_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-image",
|
|
SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-indicator",
|
|
SCROLLVIEW_PULLDOWN_TEXT_CLASS = SCROLLVIEW_PULLDOWN_CLASS + "-text",
|
|
SCROLLVIEW_REACHBOTTOM_CLASS = SCROLLVIEW_CLASS + "-scrollbottom",
|
|
SCROLLVIEW_REACHBOTTOM_INDICATOR_CLASS = SCROLLVIEW_REACHBOTTOM_CLASS + "-indicator",
|
|
SCROLLVIEW_REACHBOTTOM_TEXT_CLASS = SCROLLVIEW_REACHBOTTOM_CLASS + "-text";
|
|
ui.registerComponent("dxScrollView", ui.dxScrollable.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
pullingDownText: Globalize.localize("dxScrollView-pullingDownText"),
|
|
pulledDownText: Globalize.localize("dxScrollView-pulledDownText"),
|
|
refreshingText: Globalize.localize("dxScrollView-refreshingText"),
|
|
reachBottomText: Globalize.localize("dxScrollView-reachBottomText"),
|
|
pullDownAction: null,
|
|
reachBottomAction: null,
|
|
refreshStrategy: "pullDown"
|
|
})
|
|
},
|
|
_initMarkup: function() {
|
|
this.callBase();
|
|
this._element().addClass(SCROLLVIEW_CLASS);
|
|
this._initContent();
|
|
this._initTopPocket();
|
|
this._initBottomPocket()
|
|
},
|
|
_initContent: function() {
|
|
var $content = $("<div>").addClass(SCROLLVIEW_CONTENT_CLASS);
|
|
this._$content.wrapInner($content)
|
|
},
|
|
_initTopPocket: function() {
|
|
var $topPocket = this._$topPocket = $("<div>").addClass(SCROLLVIEW_TOP_POCKET_CLASS),
|
|
$pullDown = this._$pullDown = $("<div>").addClass(SCROLLVIEW_PULLDOWN_CLASS);
|
|
$topPocket.append($pullDown);
|
|
this._$content.prepend($topPocket)
|
|
},
|
|
_initBottomPocket: function() {
|
|
var $bottomPocket = this._$bottomPocket = $("<div>").addClass(SCROLLVIEW_BOTTOM_POCKET_CLASS),
|
|
$reachBottom = this._$reachBottom = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_CLASS),
|
|
$loadContainer = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_INDICATOR_CLASS),
|
|
$loadIndicator = $("<div>").dxLoadIndicator(),
|
|
$text = this._$reachBottomText = $("<div>").addClass(SCROLLVIEW_REACHBOTTOM_TEXT_CLASS);
|
|
this._updateReachBottomText();
|
|
$reachBottom.append($loadContainer.append($loadIndicator)).append($text);
|
|
$bottomPocket.append($reachBottom);
|
|
this._$content.append($bottomPocket)
|
|
},
|
|
_updateReachBottomText: function() {
|
|
this._$reachBottomText.text(this.option("reachBottomText"))
|
|
},
|
|
_createStrategy: function() {
|
|
var strategyName = this.option("useNative") || DX.designMode ? this.option("refreshStrategy") : "simulated";
|
|
var strategyClass = ui.scrollViewRefreshStrategies[strategyName];
|
|
if (!strategyClass)
|
|
throw Error("Unknown dxScrollView refresh strategy " + this.option("refreshStrategy"));
|
|
this._strategy = new strategyClass(this);
|
|
this._strategy.pullDownCallbacks.add($.proxy(this._handlePullDown, this));
|
|
this._strategy.releaseCallbacks.add($.proxy(this._handleRelease, this));
|
|
this._strategy.reachBottomCallbacks.add($.proxy(this._handleReachBottom, this));
|
|
this._strategy.render()
|
|
},
|
|
_createActions: function() {
|
|
this.callBase();
|
|
this._pullDownAction = this._createActionByOption("pullDownAction", {excludeValidators: ["gesture"]});
|
|
this._reachBottomAction = this._createActionByOption("reachBottomAction", {excludeValidators: ["gesture"]});
|
|
this._pullDownEnable(!!this.option("pullDownAction") && !DX.designMode);
|
|
this._reachBottomEnable(!!this.option("reachBottomAction") && !DX.designMode)
|
|
},
|
|
_pullDownEnable: function(enabled) {
|
|
this._$pullDown.toggle(enabled);
|
|
this._strategy.pullDownEnable(enabled)
|
|
},
|
|
_reachBottomEnable: function(enabled) {
|
|
this._$reachBottom.toggle(enabled);
|
|
this._strategy.reachBottomEnable(enabled)
|
|
},
|
|
_handlePullDown: function() {
|
|
this._pullDownAction();
|
|
this._lock()
|
|
},
|
|
_handleRelease: function() {
|
|
this._unlock()
|
|
},
|
|
_handleReachBottom: function() {
|
|
this._reachBottomAction();
|
|
this._lock()
|
|
},
|
|
_optionChanged: function(optionName, optionValue) {
|
|
switch (optionName) {
|
|
case"pullDownAction":
|
|
case"reachBottomAction":
|
|
this._createActions();
|
|
break;
|
|
case"pullingDownText":
|
|
case"pulledDownText":
|
|
case"refreshingText":
|
|
this._invalidate();
|
|
break;
|
|
case"reachBottomText":
|
|
this._updateReachBottomText();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
content: function() {
|
|
return this._$content.children().eq(1)
|
|
},
|
|
release: function(preventReachBottom) {
|
|
if (preventReachBottom !== undefined)
|
|
this.toggleLoading(!preventReachBottom);
|
|
return this._strategy.release()
|
|
},
|
|
toggleLoading: function(showOrHide) {
|
|
this._reachBottomEnable(showOrHide)
|
|
},
|
|
isFull: function() {
|
|
return this.content().height() >= this._$container.height()
|
|
}
|
|
}));
|
|
ui.scrollViewRefreshStrategies = {}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollView.native.pullDown.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
math = Math;
|
|
var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
|
|
SCROLLVIEW_PULLDOWN_READY_CLASS = "dx-scrollview-pull-down-ready",
|
|
SCROLLVIEW_PULLDOWN_IMAGE_CLASS = "dx-scrollview-pull-down-image",
|
|
SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = "dx-scrollview-pull-down-indicator",
|
|
SCROLLVIEW_PULLDOWN_TEXT_CLASS = "dx-scrollview-pull-down-text",
|
|
STATE_RELEASED = 0,
|
|
STATE_READY = 1,
|
|
STATE_REFRESHING = 2,
|
|
STATE_LOADING = 3;
|
|
var PullDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
|
|
_init: function(scrollView) {
|
|
this.callBase(scrollView);
|
|
this._$topPocket = scrollView._$topPocket;
|
|
this._$pullDown = scrollView._$pullDown;
|
|
this._$bottomPocket = scrollView._$bottomPocket;
|
|
this._$refreshingText = scrollView._$refreshingText;
|
|
this._$scrollViewContent = scrollView.content();
|
|
this._initCallbacks()
|
|
},
|
|
_initCallbacks: function() {
|
|
this.pullDownCallbacks = $.Callbacks();
|
|
this.releaseCallbacks = $.Callbacks();
|
|
this.reachBottomCallbacks = $.Callbacks()
|
|
},
|
|
render: function() {
|
|
this.callBase();
|
|
this._renderPullDown();
|
|
this._releaseState()
|
|
},
|
|
_renderPullDown: function() {
|
|
var $image = $("<div>").addClass(SCROLLVIEW_PULLDOWN_IMAGE_CLASS),
|
|
$loadContainer = $("<div>").addClass(SCROLLVIEW_PULLDOWN_INDICATOR_CLASS),
|
|
$loadIndicator = $("<div>").dxLoadIndicator(),
|
|
$text = this._$pullDownText = $("<div>").addClass(SCROLLVIEW_PULLDOWN_TEXT_CLASS);
|
|
this._$pullingDownText = $("<div>").text(this.option("pullingDownText")).appendTo($text);
|
|
this._$pulledDownText = $("<div>").text(this.option("pulledDownText")).appendTo($text);
|
|
this._$refreshingText = $("<div>").text(this.option("refreshingText")).appendTo($text);
|
|
this._$pullDown.empty().append($image).append($loadContainer.append($loadIndicator)).append($text)
|
|
},
|
|
_releaseState: function() {
|
|
this._state = STATE_RELEASED;
|
|
this._refreshPullDownText()
|
|
},
|
|
_refreshPullDownText: function() {
|
|
this._$pullingDownText.css("opacity", this._state === STATE_RELEASED ? 1 : 0);
|
|
this._$pulledDownText.css("opacity", this._state === STATE_READY ? 1 : 0);
|
|
this._$refreshingText.css("opacity", this._state === STATE_REFRESHING ? 1 : 0)
|
|
},
|
|
update: function() {
|
|
this.callBase();
|
|
this._setTopPocketOffset()
|
|
},
|
|
_updateDimensions: function() {
|
|
this.callBase();
|
|
this._topPocketSize = this._$topPocket.height();
|
|
this._bottomPocketSize = this._$bottomPocket.height();
|
|
this._scrollOffset = this._$container.height() - this._$content.height()
|
|
},
|
|
_setTopPocketOffset: function() {
|
|
this._$topPocket.css({
|
|
height: this._topPocketSize,
|
|
top: -this._topPocketSize
|
|
})
|
|
},
|
|
_handleEnd: function() {
|
|
var self = this;
|
|
if (self._state === STATE_READY) {
|
|
self._setPullDownOffset(self._topPocketSize);
|
|
setTimeout(function() {
|
|
self._pullDownRefreshing()
|
|
}, 400)
|
|
}
|
|
},
|
|
_setPullDownOffset: function(offset) {
|
|
DX.translator.move(this._$topPocket, {top: offset}, {cssTransform: true});
|
|
DX.translator.move(this._$scrollViewContent, {top: offset}, {cssTransform: true})
|
|
},
|
|
_handleScroll: function(e) {
|
|
this.callBase(e);
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._location = this.location().top;
|
|
if (this._isPullDown())
|
|
this._pullDownReady();
|
|
else if (this._isReachBottom())
|
|
this._reachBottom();
|
|
else
|
|
this._stateReleased()
|
|
},
|
|
_isPullDown: function() {
|
|
return this._pullDownEnabled && this._location >= this._topPocketSize
|
|
},
|
|
_isReachBottom: function() {
|
|
return this._reachBottomEnabled && this._location <= this._scrollOffset + this._bottomPocketSize
|
|
},
|
|
_reachBottom: function() {
|
|
if (this._state === STATE_LOADING)
|
|
return;
|
|
this._state = STATE_LOADING;
|
|
this.reachBottomCallbacks.fire()
|
|
},
|
|
_pullDownReady: function() {
|
|
if (this._state === STATE_READY)
|
|
return;
|
|
this._state = STATE_READY;
|
|
this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this._refreshPullDownText()
|
|
},
|
|
_stateReleased: function() {
|
|
if (this._state === STATE_RELEASED)
|
|
return;
|
|
this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this._releaseState()
|
|
},
|
|
_pullDownRefreshing: function() {
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._state = STATE_REFRESHING;
|
|
this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this._refreshPullDownText();
|
|
this.pullDownCallbacks.fire()
|
|
},
|
|
pullDownEnable: function(enabled) {
|
|
this._pullDownEnabled = enabled
|
|
},
|
|
reachBottomEnable: function(enabled) {
|
|
this._reachBottomEnabled = enabled
|
|
},
|
|
release: function() {
|
|
var deferred = $.Deferred();
|
|
this._updateDimensions();
|
|
setTimeout($.proxy(function() {
|
|
this._setPullDownOffset(0);
|
|
this._stateReleased();
|
|
this.releaseCallbacks.fire();
|
|
this._updateAction();
|
|
deferred.resolve()
|
|
}, this), 400);
|
|
return deferred.promise()
|
|
}
|
|
});
|
|
ui.scrollViewRefreshStrategies.pullDown = PullDownNativeScrollViewStrategy
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollView.native.swipeDown.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
math = Math;
|
|
var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
|
|
SCROLLVIEW_OBSOLETE_ANDROID_CLASS = "dx-scrollview-obsolete-android-browser",
|
|
PULLDOWN_HEIGHT = 160,
|
|
STATE_RELEASED = 0,
|
|
STATE_REFRESHING = 2,
|
|
STATE_LOADING = 3,
|
|
STATE_TOUCHED = 4,
|
|
STATE_PULLED = 5;
|
|
var SwipeDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
|
|
_init: function(scrollView) {
|
|
this.callBase(scrollView);
|
|
this._$topPocket = scrollView._$topPocket;
|
|
this._$bottomPocket = scrollView._$bottomPocket;
|
|
this._$pullDown = scrollView._$pullDown;
|
|
this._$scrollViewContent = scrollView.content();
|
|
this._initCallbacks();
|
|
this._initObsoleteBrowser();
|
|
this._releaseState();
|
|
this._location = 0
|
|
},
|
|
_initCallbacks: function() {
|
|
this.pullDownCallbacks = $.Callbacks();
|
|
this.releaseCallbacks = $.Callbacks();
|
|
this.reachBottomCallbacks = $.Callbacks()
|
|
},
|
|
_initObsoleteBrowser: function() {
|
|
var realDevice = DevExpress.devices.real,
|
|
obsoleteAndroid = realDevice.platform === "android" && (realDevice.version[0] < 4 || realDevice.version[0] === 4 && realDevice.version[1] === 0);
|
|
this._$element.toggleClass(SCROLLVIEW_OBSOLETE_ANDROID_CLASS, obsoleteAndroid)
|
|
},
|
|
render: function() {
|
|
this.callBase();
|
|
this._renderPullDown()
|
|
},
|
|
_renderPullDown: function() {
|
|
this._$pullDown.empty().append($("<div class='dx-scrollview-pulldown-pointer1'>")).append($("<div class='dx-scrollview-pulldown-pointer2'>")).append($("<div class='dx-scrollview-pulldown-pointer3'>")).append($("<div class='dx-scrollview-pulldown-pointer4'>"))
|
|
},
|
|
_releaseState: function() {
|
|
this._state = STATE_RELEASED;
|
|
this._$pullDown.css({
|
|
width: "0%",
|
|
opacity: 0
|
|
});
|
|
this._updateDimensions()
|
|
},
|
|
_updateDimensions: function() {
|
|
this.callBase();
|
|
this._topPocketSize = this._$topPocket.height();
|
|
this._bottomPocketSize = this._$bottomPocket.height();
|
|
this._scrollOffset = this._$container.height() - this._$content.height()
|
|
},
|
|
_handleStart: function(e) {
|
|
if (this._state === STATE_RELEASED && this._location === 0) {
|
|
this._startClientY = events.eventData(e).y;
|
|
this._state = STATE_TOUCHED
|
|
}
|
|
},
|
|
_handleMove: function(e) {
|
|
this._deltaY = events.eventData(e).y - this._startClientY;
|
|
if (this._state === STATE_TOUCHED)
|
|
if (this._deltaY > 0) {
|
|
e.preventDefault();
|
|
this._state = STATE_PULLED
|
|
}
|
|
else
|
|
this._handleEnd();
|
|
if (this._state === STATE_PULLED) {
|
|
if (this._deltaY < 0) {
|
|
this._handleEnd();
|
|
return
|
|
}
|
|
this._$pullDown.css({
|
|
opacity: 1,
|
|
width: math.min(math.abs(this._deltaY * 100 / PULLDOWN_HEIGHT), 100) + "%"
|
|
});
|
|
if (this._isPullDown())
|
|
this._pullDownRefreshing()
|
|
}
|
|
},
|
|
_isPullDown: function() {
|
|
return this._pullDownEnabled && this._deltaY >= PULLDOWN_HEIGHT
|
|
},
|
|
_handleEnd: function() {
|
|
if (this._state === STATE_TOUCHED || this._state === STATE_PULLED)
|
|
this._releaseState()
|
|
},
|
|
_handleScroll: function(e) {
|
|
this.callBase(e);
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._location = this.location().top;
|
|
if (this._isReachBottom())
|
|
this._reachBottom();
|
|
else
|
|
this._stateReleased()
|
|
},
|
|
_isReachBottom: function() {
|
|
return this._reachBottomEnabled && this._location <= this._scrollOffset + this._bottomPocketSize
|
|
},
|
|
_reachBottom: function() {
|
|
if (this._state === STATE_LOADING)
|
|
return;
|
|
this._state = STATE_LOADING;
|
|
this.reachBottomCallbacks.fire()
|
|
},
|
|
_stateReleased: function() {
|
|
if (this._state === STATE_RELEASED)
|
|
return;
|
|
this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS);
|
|
this._releaseState()
|
|
},
|
|
_pullDownRefreshing: function() {
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._state = STATE_REFRESHING;
|
|
var self = this;
|
|
setTimeout(function() {
|
|
self._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS);
|
|
self.pullDownCallbacks.fire()
|
|
}, 400)
|
|
},
|
|
pullDownEnable: function(enabled) {
|
|
this._$topPocket.toggle(enabled);
|
|
this._pullDownEnabled = enabled
|
|
},
|
|
reachBottomEnable: function(enabled) {
|
|
this._reachBottomEnabled = enabled
|
|
},
|
|
release: function() {
|
|
var self = this,
|
|
deferred = $.Deferred();
|
|
setTimeout(function() {
|
|
self._updateDimensions();
|
|
self._stateReleased();
|
|
self.releaseCallbacks.fire();
|
|
self._updateAction();
|
|
deferred.resolve()
|
|
}, 800);
|
|
return deferred.promise()
|
|
}
|
|
});
|
|
ui.scrollViewRefreshStrategies.swipeDown = SwipeDownNativeScrollViewStrategy
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollView.native.slideDown.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
math = Math,
|
|
events = ui.events;
|
|
var DX_SLIDE_DOWN_NATIVE_SCROLLVIEW_STRATEGY = "dxSlideDownNativeScrollViewStrategy",
|
|
SCROLLVIEW_LOCKED_CLASS = "dx-scrollview-locked",
|
|
SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-refreshing",
|
|
SCROLLVIEW_PULLDOWN_LOADING_CLASS = "dx-scrollview-pull-down-loading",
|
|
SCROLLVIEW_PULLDOWN_READY_CLASS = "dx-scrollview-pull-down-ready",
|
|
SCROLLVIEW_PULLDOWN_IMAGE_CLASS = "dx-scrollview-pull-down-image",
|
|
SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = "dx-scrollview-pull-down-indicator",
|
|
SCROLLVIEW_PULLDOWN_TEXT_CLASS = "dx-scrollview-pull-down-text",
|
|
STATE_RELEASED = 0,
|
|
STATE_READY = 1,
|
|
STATE_REFRESHING = 2,
|
|
STATE_LOADING = 3,
|
|
STATE_AFTER_REFRESHING = 4,
|
|
LOADING_HEIGHT = 80,
|
|
SCROLLING_STEP = 4;
|
|
var SlideUpAnimator = DX.Animator.inherit({
|
|
ctor: function(refreshStrategy) {
|
|
this.callBase();
|
|
this.refreshStrategy = refreshStrategy;
|
|
this._$content = refreshStrategy._$content
|
|
},
|
|
_isFinished: function() {
|
|
return this._$content.scrollTop() === 0
|
|
},
|
|
_step: function() {
|
|
this._lock();
|
|
var scrollTop = this._$content.scrollTop();
|
|
scrollTop -= Math.min(scrollTop, 2 * SCROLLING_STEP);
|
|
this._$content.scrollTop(scrollTop)
|
|
},
|
|
_complete: function() {
|
|
this._unlock()
|
|
},
|
|
_stop: function() {
|
|
this._unlock()
|
|
},
|
|
_lock: function() {
|
|
this.refreshStrategy._$container.addClass(SCROLLVIEW_LOCKED_CLASS)
|
|
},
|
|
_unlock: function() {
|
|
this.refreshStrategy._$container.removeClass(SCROLLVIEW_LOCKED_CLASS)
|
|
}
|
|
});
|
|
var SlideDownAnimator = SlideUpAnimator.inherit({
|
|
_isFinished: function() {
|
|
this._currentPosition = this._$content.scrollTop();
|
|
return this._currentPosition === this.refreshStrategy._topPocketSize
|
|
},
|
|
_step: function() {
|
|
this._lock();
|
|
var scrollTop = this._$content.scrollTop();
|
|
var currentPosition = this.refreshStrategy._topPocketSize - scrollTop;
|
|
scrollTop += currentPosition < 0 ? -Math.min(Math.abs(currentPosition), SCROLLING_STEP) : Math.min(currentPosition, SCROLLING_STEP);
|
|
this._$content.scrollTop(scrollTop)
|
|
},
|
|
_complete: function() {
|
|
this.callBase();
|
|
this.refreshStrategy._releaseState()
|
|
}
|
|
});
|
|
var SlideDownNativeScrollViewStrategy = ui.NativeScrollableStrategy.inherit({
|
|
_init: function(scrollView) {
|
|
this.callBase(scrollView);
|
|
this._$topPocket = scrollView._$topPocket;
|
|
this._$pullDown = scrollView._$pullDown;
|
|
this._$bottomPocket = scrollView._$bottomPocket;
|
|
this._$refreshingText = scrollView._$refreshingText;
|
|
this._$content = scrollView._$content;
|
|
this._$scrollViewContent = scrollView.content();
|
|
this._initCallbacks();
|
|
this._initAnimators();
|
|
$(document).on("dx.viewchanged", $.proxy(this._hidePullDown, this))
|
|
},
|
|
_initCallbacks: function() {
|
|
this.pullDownCallbacks = $.Callbacks();
|
|
this.releaseCallbacks = $.Callbacks();
|
|
this.reachBottomCallbacks = $.Callbacks()
|
|
},
|
|
_initAnimators: function() {
|
|
this._slideDown = new SlideDownAnimator(this);
|
|
this._slideUp = new SlideUpAnimator(this)
|
|
},
|
|
render: function() {
|
|
this.callBase();
|
|
this._renderPullDown();
|
|
this._renderBottom();
|
|
this._releaseState();
|
|
this._updateDimensions();
|
|
this._hidePullDown()
|
|
},
|
|
_renderPullDown: function() {
|
|
var $image = $("<div>").addClass(SCROLLVIEW_PULLDOWN_IMAGE_CLASS),
|
|
$loadContainer = $("<div>").addClass(SCROLLVIEW_PULLDOWN_INDICATOR_CLASS),
|
|
$loadIndicator = $("<progress>");
|
|
var $pullDownText = this._$pullDownText = $("<div>").addClass(SCROLLVIEW_PULLDOWN_TEXT_CLASS);
|
|
this._$pullingDownText = $("<div>").text(this.option("pullingDownText")).appendTo($pullDownText);
|
|
this._$pulledDownText = $("<div>").text(this.option("pulledDownText")).appendTo($pullDownText);
|
|
this._$refreshingText = $("<div>").text(this.option("refreshingText")).appendTo($pullDownText);
|
|
this._$pullDown.empty().append($image).append($loadContainer.append($loadIndicator)).append($pullDownText)
|
|
},
|
|
_renderBottom: function() {
|
|
this._$bottomPocket.empty().append("<progress>")
|
|
},
|
|
_releaseState: function() {
|
|
this._state = STATE_RELEASED;
|
|
this._$container.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_LOADING_CLASS);
|
|
this._refreshPullDownText()
|
|
},
|
|
_hidePullDown: function() {
|
|
if (this._$content.scrollTop() < this._topPocketSize)
|
|
this._$content.scrollTop(this._topPocketSize)
|
|
},
|
|
_refreshPullDownText: function() {
|
|
this._$pullingDownText.css("opacity", this._state === STATE_RELEASED ? 1 : 0);
|
|
this._$pulledDownText.css("opacity", this._state === STATE_READY ? 1 : 0);
|
|
this._$refreshingText.css("opacity", this._state === STATE_REFRESHING ? 1 : 0)
|
|
},
|
|
update: function() {
|
|
this.callBase();
|
|
this._hidePullDown();
|
|
this._updateScrollbars()
|
|
},
|
|
_updateDimensions: function() {
|
|
this._topPocketSize = this._$topPocket.height();
|
|
this._scrollOffset = this._$scrollViewContent.prop("scrollHeight") - this._$scrollViewContent.prop("clientHeight");
|
|
this._containerSize = {
|
|
height: this._$scrollViewContent.prop("clientHeight"),
|
|
width: this._$scrollViewContent.prop("clientWidth")
|
|
};
|
|
this._contentSize = {
|
|
height: this._$scrollViewContent.prop("scrollHeight"),
|
|
width: this._$scrollViewContent.prop("scrollWidth")
|
|
}
|
|
},
|
|
_contentSize: function() {
|
|
return {
|
|
height: this._$scrollViewContent.prop("scrollHeight"),
|
|
width: this._$scrollViewContent.prop("scrollWidth")
|
|
}
|
|
},
|
|
location: function() {
|
|
return {
|
|
left: -this._$scrollViewContent.scrollLeft(),
|
|
top: -this._$scrollViewContent.scrollTop()
|
|
}
|
|
},
|
|
_attachScrollHandler: function() {
|
|
this.callBase();
|
|
$(this._$content).on(events.addNamespace("scroll", DX_SLIDE_DOWN_NATIVE_SCROLLVIEW_STRATEGY), $.proxy(this._handleContentScroll, this));
|
|
$(this._$scrollViewContent).on(events.addNamespace("scroll", DX_SLIDE_DOWN_NATIVE_SCROLLVIEW_STRATEGY), $.proxy(this._handleScrollViewContentScroll, this))
|
|
},
|
|
_handleContentScroll: function(e) {
|
|
var contentLocation = this._$content.scrollTop();
|
|
if (this._isPullDown(contentLocation))
|
|
this._pullDownRefreshing();
|
|
else if (this._isReachBottom(contentLocation))
|
|
this._reachBottom();
|
|
else
|
|
this._pullDownReady()
|
|
},
|
|
_isPullDown: function(location) {
|
|
return this._pullDownEnabled && location === 0
|
|
},
|
|
_pullDownRefreshing: function() {
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._state = STATE_REFRESHING;
|
|
this._stopAnimators();
|
|
this._refreshPullDownText();
|
|
this._$container.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS);
|
|
this.pullDownCallbacks.fire()
|
|
},
|
|
_isReachBottom: function(location) {
|
|
this._scrollContent = this._$content.prop("scrollHeight") - this._$content.prop("clientHeight");
|
|
return this._reachBottomEnabled && location === this._scrollContent
|
|
},
|
|
_reachBottom: function() {
|
|
if (this._state === STATE_LOADING || !this._reachBottomEnabled)
|
|
return;
|
|
this._state = STATE_LOADING;
|
|
this._stopAnimators();
|
|
this._$container.addClass(SCROLLVIEW_PULLDOWN_LOADING_CLASS);
|
|
this.reachBottomCallbacks.fire()
|
|
},
|
|
_pullDownReady: function() {
|
|
if (this._state === STATE_READY || this._state === STATE_AFTER_REFRESHING)
|
|
return;
|
|
if (this._state === STATE_REFRESHING) {
|
|
if (!this._slideUp.inProgress())
|
|
this._startUpAnimation();
|
|
return
|
|
}
|
|
this._state = STATE_READY;
|
|
this._startDownAnimation()
|
|
},
|
|
_startUpAnimation: function() {
|
|
this._slideDown.stop();
|
|
this._slideUp.start()
|
|
},
|
|
_startDownAnimation: function() {
|
|
this._slideUp.stop();
|
|
this._slideDown.start()
|
|
},
|
|
_stopAnimators: function() {
|
|
this._slideDown.stop();
|
|
this._slideUp.stop()
|
|
},
|
|
_handleScrollViewContentScroll: function(e) {
|
|
this._handleScroll(e)
|
|
},
|
|
pullDownEnable: function(enabled) {
|
|
this._pullDownEnabled = enabled
|
|
},
|
|
reachBottomEnable: function(enabled) {
|
|
this._reachBottomEnabled = enabled;
|
|
this._$bottomPocket.toggle(enabled)
|
|
},
|
|
release: function() {
|
|
var deferred = $.Deferred();
|
|
this._updateDimensions();
|
|
this._updateScrollbars();
|
|
setTimeout($.proxy(function() {
|
|
this._state = STATE_AFTER_REFRESHING;
|
|
this._startDownAnimation();
|
|
this.releaseCallbacks.fire();
|
|
this._updateAction();
|
|
deferred.resolve()
|
|
}, this), 400);
|
|
return deferred.promise()
|
|
},
|
|
scrollBy: function(distance) {
|
|
var location = this.location();
|
|
this._component.content().scrollTop(-location.top - distance.y);
|
|
this._component.content().scrollLeft(-location.left - distance.x)
|
|
}
|
|
});
|
|
ui.scrollViewRefreshStrategies.slideDown = SlideDownNativeScrollViewStrategy;
|
|
ui.scrollViewRefreshStrategies.slideDown.__internals = {
|
|
slideDownAnimator: function(cls) {
|
|
if (cls === undefined)
|
|
return SlideDownAnimator;
|
|
SlideDownAnimator = cls
|
|
},
|
|
slideUpAnimator: function(cls) {
|
|
if (cls === undefined)
|
|
return SlideUpAnimator;
|
|
SlideUpAnimator = cls
|
|
},
|
|
LOADING_HEIGHT: LOADING_HEIGHT
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.scrollView.simulated.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
math = Math;
|
|
var SCROLLVIEW_PULLDOWN_REFRESHING_CLASS = "dx-scrollview-pull-down-loading",
|
|
SCROLLVIEW_PULLDOWN_READY_CLASS = "dx-scrollview-pull-down-ready",
|
|
SCROLLVIEW_PULLDOWN_IMAGE_CLASS = "dx-scrollview-pull-down-image",
|
|
SCROLLVIEW_PULLDOWN_INDICATOR_CLASS = "dx-scrollview-pull-down-indicator",
|
|
SCROLLVIEW_PULLDOWN_TEXT_CLASS = "dx-scrollview-pull-down-text",
|
|
STATE_RELEASED = 0,
|
|
STATE_READY = 1,
|
|
STATE_REFRESHING = 2,
|
|
STATE_LOADING = 3;
|
|
var ScrollViewScroller = ui.ScrollViewScroller = ui.Scroller.inherit({
|
|
ctor: function() {
|
|
this.callBase.apply(this, arguments);
|
|
this._releaseState()
|
|
},
|
|
_releaseState: function() {
|
|
this._state = STATE_RELEASED;
|
|
this._refreshPullDownText()
|
|
},
|
|
_refreshPullDownText: function() {
|
|
this._$pullingDownText.css("opacity", this._state === STATE_RELEASED ? 1 : 0);
|
|
this._$pulledDownText.css("opacity", this._state === STATE_READY ? 1 : 0);
|
|
this._$refreshingText.css("opacity", this._state === STATE_REFRESHING ? 1 : 0)
|
|
},
|
|
_initCallbacks: function() {
|
|
this.callBase();
|
|
this.pullDownCallbacks = $.Callbacks();
|
|
this.releaseCallbacks = $.Callbacks();
|
|
this.reachBottomCallbacks = $.Callbacks()
|
|
},
|
|
_updateBounds: function() {
|
|
var considerPockets = this._direction !== "horizontal";
|
|
this._topPocketSize = considerPockets ? this._$topPocket[this._dimension]() : 0;
|
|
this._bottomPocketSize = considerPockets ? this._$bottomPocket[this._dimension]() : 0;
|
|
this._updateOffsets()
|
|
},
|
|
_updateOffsets: function() {
|
|
this._minOffset = math.min(this._containerSize() - this._contentSize() + this._bottomPocketSize, -this._topPocketSize);
|
|
this._maxOffset = -this._topPocketSize;
|
|
this._bottomBound = this._minOffset - this._bottomPocketSize
|
|
},
|
|
_updateScrollbar: function() {
|
|
this._scrollbar.update(this._containerSize(), this._contentSize() - this._topPocketSize - this._bottomPocketSize)
|
|
},
|
|
_calculateScrollBarPosition: function() {
|
|
return this._topPocketSize + this._location
|
|
},
|
|
_moveContent: function() {
|
|
this.callBase();
|
|
if (this._isPullDown())
|
|
this._pullDownReady();
|
|
else if (this._isReachBottom())
|
|
this._reachBottomReady();
|
|
else if (this._state !== STATE_RELEASED)
|
|
this._stateReleased()
|
|
},
|
|
_isPullDown: function() {
|
|
return this._pullDownEnabled && this._location >= 0
|
|
},
|
|
_isReachBottom: function() {
|
|
return this._reachBottomEnabled && this._location <= this._bottomBound
|
|
},
|
|
_scrollComplete: function() {
|
|
if (this._inBounds() && this._state === STATE_READY)
|
|
this._pullDownRefreshing();
|
|
else if (this._inBounds() && this._state === STATE_LOADING)
|
|
this._reachBottomLoading();
|
|
else
|
|
this.callBase()
|
|
},
|
|
_reachBottomReady: function() {
|
|
if (this._state === STATE_LOADING)
|
|
return;
|
|
this._state = STATE_LOADING;
|
|
this._minOffset = math.min(this._containerSize() - this._contentSize(), 0)
|
|
},
|
|
_reachBottomLoading: function() {
|
|
this.reachBottomCallbacks.fire()
|
|
},
|
|
_pullDownReady: function() {
|
|
if (this._state === STATE_READY)
|
|
return;
|
|
this._state = STATE_READY;
|
|
this._maxOffset = 0;
|
|
this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this._refreshPullDownText()
|
|
},
|
|
_stateReleased: function() {
|
|
if (this._state === STATE_RELEASED)
|
|
return;
|
|
this._releaseState();
|
|
this._updateOffsets();
|
|
this._$pullDown.removeClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this.releaseCallbacks.fire()
|
|
},
|
|
_pullDownRefreshing: function() {
|
|
if (this._state === STATE_REFRESHING)
|
|
return;
|
|
this._state = STATE_REFRESHING;
|
|
this._$pullDown.addClass(SCROLLVIEW_PULLDOWN_REFRESHING_CLASS).removeClass(SCROLLVIEW_PULLDOWN_READY_CLASS);
|
|
this._refreshPullDownText();
|
|
this.pullDownCallbacks.fire()
|
|
},
|
|
_handleRelease: function() {
|
|
this._update();
|
|
return DX.utils.executeAsync($.proxy(this._release, this))
|
|
},
|
|
_release: function() {
|
|
this._stateReleased();
|
|
this._scrollComplete()
|
|
},
|
|
_handleReachBottomEnabling: function(enabled) {
|
|
if (this._reachBottomEnabled === enabled)
|
|
return;
|
|
this._reachBottomEnabled = enabled;
|
|
this._updateBounds()
|
|
},
|
|
_handlePullDownEnabling: function(enabled) {
|
|
if (this._pullDownEnabled === enabled)
|
|
return;
|
|
this._pullDownEnabled = enabled;
|
|
this._considerTopPocketChange();
|
|
this._handleUpdate()
|
|
},
|
|
_considerTopPocketChange: function() {
|
|
this._location -= this._$topPocket.height() || -this._topPocketSize;
|
|
this._move()
|
|
}
|
|
});
|
|
var SimulatedScrollViewStrategy = ui.SimulatedScrollableStrategy.inherit({
|
|
_init: function(scrollView) {
|
|
this.callBase(scrollView);
|
|
this._$pullDown = scrollView._$pullDown;
|
|
this._$topPocket = scrollView._$topPocket;
|
|
this._$bottomPocket = scrollView._$bottomPocket;
|
|
this._initCallbacks()
|
|
},
|
|
_initCallbacks: function() {
|
|
this.pullDownCallbacks = $.Callbacks();
|
|
this.releaseCallbacks = $.Callbacks();
|
|
this.reachBottomCallbacks = $.Callbacks()
|
|
},
|
|
render: function() {
|
|
this._renderPullDown();
|
|
this.callBase()
|
|
},
|
|
_renderPullDown: function() {
|
|
var $image = $("<div>").addClass(SCROLLVIEW_PULLDOWN_IMAGE_CLASS),
|
|
$loadContainer = $("<div>").addClass(SCROLLVIEW_PULLDOWN_INDICATOR_CLASS),
|
|
$loadIndicator = $("<div>").dxLoadIndicator(),
|
|
$text = this._$pullDownText = $("<div>").addClass(SCROLLVIEW_PULLDOWN_TEXT_CLASS);
|
|
this._$pullingDownText = $("<div>").text(this.option("pullingDownText")).appendTo($text);
|
|
this._$pulledDownText = $("<div>").text(this.option("pulledDownText")).appendTo($text);
|
|
this._$refreshingText = $("<div>").text(this.option("refreshingText")).appendTo($text);
|
|
this._$pullDown.empty().append($image).append($loadContainer.append($loadIndicator)).append($text)
|
|
},
|
|
pullDownEnable: function(enabled) {
|
|
this._handleEvent("PullDownEnabling", enabled)
|
|
},
|
|
reachBottomEnable: function(enabled) {
|
|
this._handleEvent("ReachBottomEnabling", enabled)
|
|
},
|
|
_createScroller: function(direction) {
|
|
var self = this;
|
|
var scroller = self._scrollers[direction] = new ScrollViewScroller(self._scrollerOptions(direction));
|
|
scroller.pullDownCallbacks.add(function() {
|
|
self.pullDownCallbacks.fire()
|
|
});
|
|
scroller.releaseCallbacks.add(function() {
|
|
self.releaseCallbacks.fire()
|
|
});
|
|
scroller.reachBottomCallbacks.add(function() {
|
|
self.reachBottomCallbacks.fire()
|
|
})
|
|
},
|
|
_scrollerOptions: function(direction) {
|
|
return $.extend(this.callBase(direction), {
|
|
$topPocket: this._$topPocket,
|
|
$bottomPocket: this._$bottomPocket,
|
|
$pullDown: this._$pullDown,
|
|
$pullDownText: this._$pullDownText,
|
|
$pullingDownText: this._$pullingDownText,
|
|
$pulledDownText: this._$pulledDownText,
|
|
$refreshingText: this._$refreshingText
|
|
})
|
|
},
|
|
release: function() {
|
|
return this._handleEvent("Release").done(this._updateAction)
|
|
}
|
|
});
|
|
ui.scrollViewRefreshStrategies.simulated = SimulatedScrollViewStrategy
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.map.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
utils = DX.utils,
|
|
winJS = DX.support.winJS;
|
|
ui.MapProvider = DX.Class.inherit({
|
|
_defaultRouteWeight: function() {
|
|
return 5
|
|
},
|
|
_defaultRouteOpacity: function() {
|
|
return .5
|
|
},
|
|
_defaultRouteColor: function() {
|
|
return "#0000FF"
|
|
},
|
|
ctor: function(map, $container) {
|
|
this._mapInstance = map;
|
|
this._$container = $container
|
|
},
|
|
load: $.noop,
|
|
render: DX.abstract,
|
|
updateDimensions: DX.abstract,
|
|
updateMapType: DX.abstract,
|
|
updateLocation: DX.abstract,
|
|
updateZoom: DX.abstract,
|
|
updateControls: DX.abstract,
|
|
updateMarkers: DX.abstract,
|
|
addMarkers: DX.abstract,
|
|
updateRoutes: DX.abstract,
|
|
addRoutes: DX.abstract,
|
|
clean: DX.abstract,
|
|
cancelEvents: false,
|
|
map: function() {
|
|
return this._map
|
|
},
|
|
mapRendered: function() {
|
|
return !!this._map
|
|
},
|
|
_option: function(name, value) {
|
|
if (value === undefined)
|
|
return this._mapInstance.option(name);
|
|
this._mapInstance.setOptionSilent(name, value)
|
|
},
|
|
_key: function(providerName) {
|
|
var key = this._option("key");
|
|
return key[providerName] === undefined ? key : key[providerName]
|
|
},
|
|
_parseTooltipOptions: function(option) {
|
|
return {
|
|
text: option.text || option,
|
|
visible: option.isShown || false
|
|
}
|
|
},
|
|
_createAction: function() {
|
|
return this._mapInstance._createAction.apply(this._mapInstance, $.makeArray(arguments))
|
|
},
|
|
_handleClickAction: function() {
|
|
var clickAction = this._createAction(this._option("clickAction") || $.noop);
|
|
clickAction()
|
|
}
|
|
});
|
|
var providers = {};
|
|
ui.registerMapProvider = function(name, provider) {
|
|
providers[name] = provider
|
|
};
|
|
var MAP_CLASS = "dx-map",
|
|
MAP_CONTAINER_CLASS = "dx-map-container",
|
|
MAP_SHIELD_CLASS = "dx-map-shield";
|
|
var wrapToArray = function(entity) {
|
|
return $.isArray(entity) ? entity : [entity]
|
|
};
|
|
ui.registerComponent("dxMap", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
location: {
|
|
lat: 0,
|
|
lng: 0
|
|
},
|
|
width: 300,
|
|
height: 300,
|
|
zoom: 1,
|
|
type: "roadmap",
|
|
provider: "google",
|
|
markers: [],
|
|
markerIconSrc: null,
|
|
routes: [],
|
|
key: {
|
|
bing: "",
|
|
google: "",
|
|
googleStatic: ""
|
|
},
|
|
controls: false,
|
|
readyAction: null,
|
|
updateAction: null
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initContainer();
|
|
this._grabEvents();
|
|
this._initProvider()
|
|
},
|
|
_initContainer: function() {
|
|
this._$container = $("<div />").addClass(MAP_CONTAINER_CLASS);
|
|
this._element().append(this._$container)
|
|
},
|
|
_grabEvents: function() {
|
|
var eventName = events.addNamespace("dxpointerdown", this.NAME);
|
|
this._element().on(eventName, $.proxy(this._cancelEvent, this))
|
|
},
|
|
_cancelEvent: function(e) {
|
|
var cancelByProvider = this._provider.cancelEvents && !this.option("disabled");
|
|
if (!DX.designMode && cancelByProvider)
|
|
e.stopPropagation()
|
|
},
|
|
_initProvider: function() {
|
|
var provider = this.option("provider");
|
|
if (winJS && this.option("provider") === "google")
|
|
throw new Error("Google provider cannot be used in winJS application");
|
|
if (this._provider)
|
|
this._provider.clean();
|
|
this._provider = new providers[provider](this, this._$container);
|
|
this._mapLoader = this._provider.load()
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(MAP_CLASS);
|
|
this._renderShield();
|
|
this._execAsyncProviderAction("render")
|
|
},
|
|
_renderShield: function() {
|
|
if (DX.designMode || this.option("disabled")) {
|
|
var $shield = $("<div/>").addClass(MAP_SHIELD_CLASS);
|
|
this._element().append($shield)
|
|
}
|
|
else {
|
|
var $shield = this._element().find("." + MAP_SHIELD_CLASS);
|
|
$shield.remove()
|
|
}
|
|
},
|
|
_clean: function() {
|
|
this._provider.clean()
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
if (this._cancelOptionChange)
|
|
return;
|
|
switch (name) {
|
|
case"disabled":
|
|
this._renderShield();
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
case"width":
|
|
case"height":
|
|
this.callBase.apply(this, arguments);
|
|
this._execAsyncProviderAction("updateDimensions");
|
|
break;
|
|
case"type":
|
|
this._execAsyncProviderAction("updateMapType");
|
|
break;
|
|
case"location":
|
|
this._execAsyncProviderAction("updateLocation");
|
|
break;
|
|
case"zoom":
|
|
this._execAsyncProviderAction("updateZoom");
|
|
break;
|
|
case"controls":
|
|
this._execAsyncProviderAction("updateControls");
|
|
break;
|
|
case"markers":
|
|
case"markerIcon":
|
|
this._execAsyncProviderAction("updateMarkers");
|
|
break;
|
|
case"routes":
|
|
this._execAsyncProviderAction("updateRoutes");
|
|
break;
|
|
case"key":
|
|
throw new Error("Key option can not be modified after initialisation");
|
|
case"provider":
|
|
this._initProvider();
|
|
this._invalidate();
|
|
break;
|
|
case"readyAction":
|
|
case"updateAction":
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_execAsyncProviderAction: function(name) {
|
|
if (!this._provider.mapRendered() && !(name === "render"))
|
|
return;
|
|
var deferred = $.Deferred(),
|
|
self = this,
|
|
options = $.makeArray(arguments).slice(1);
|
|
$.when(this._mapLoader).done(function() {
|
|
var provider = self._provider;
|
|
provider[name].apply(provider, options).done(function(mapRefreshed) {
|
|
self._triggerUpdateAction();
|
|
if (mapRefreshed)
|
|
self._triggerReadyAction();
|
|
deferred.resolve.apply(deferred, $.makeArray(arguments).slice(1))
|
|
})
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_triggerReadyAction: function() {
|
|
this._createActionByOption("readyAction")({originalMap: this._provider.map()})
|
|
},
|
|
_triggerUpdateAction: function() {
|
|
this._createActionByOption("updateAction")()
|
|
},
|
|
setOptionSilent: function(name, value) {
|
|
this._cancelOptionChange = true;
|
|
this.option(name, value);
|
|
this._cancelOptionChange = false
|
|
},
|
|
addMarker: function(markerOptions) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
markersOption = this._options.markers,
|
|
markers = wrapToArray(markerOptions);
|
|
markersOption.push.apply(markersOption, markers);
|
|
this._execAsyncProviderAction("addMarkers", markers).done(function(instance) {
|
|
d.resolveWith(self, markers.length > 1 ? [instance] : instance)
|
|
});
|
|
return d.promise()
|
|
},
|
|
removeMarker: function(marker) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
markersOption = this._options.markers,
|
|
markers = wrapToArray(marker);
|
|
$.each(markers, function(_, marker) {
|
|
var index = $.isNumeric(marker) ? marker : $.inArray(marker, markersOption);
|
|
if (index !== -1)
|
|
markersOption.splice(index, 1);
|
|
else
|
|
throw new Error("Marker '" + marker + "' you are trying to remove does not exist");
|
|
});
|
|
this._execAsyncProviderAction("updateMarkers").done(function() {
|
|
d.resolveWith(self)
|
|
});
|
|
return d.promise()
|
|
},
|
|
addRoute: function(routeOptions) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
routesOption = this._options.routes,
|
|
routes = wrapToArray(routeOptions);
|
|
routesOption.push.apply(routesOption, routes);
|
|
this._execAsyncProviderAction("addRoutes", routes).done(function(instance) {
|
|
d.resolveWith(self, routes.length > 1 ? [instance] : instance)
|
|
});
|
|
return d.promise()
|
|
},
|
|
removeRoute: function(route) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
routesOption = this._options.routes,
|
|
routes = wrapToArray(route);
|
|
$.each(routes, function(_, route) {
|
|
var index = $.isNumeric(route) ? route : $.inArray(route, routesOption);
|
|
if (index !== -1)
|
|
routesOption.splice(index, 1);
|
|
else
|
|
throw new Error("Route '" + route + "' you are trying to remove does not exist");
|
|
});
|
|
this._execAsyncProviderAction("updateRoutes").done(function() {
|
|
d.resolveWith(self)
|
|
});
|
|
return d.promise()
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.map.bing.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
winJS = DX.support.winJS;
|
|
var BING_MAP_READY = "_bingScriptReady",
|
|
BING_URL = "https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&s=1&onScriptLoad=" + BING_MAP_READY,
|
|
BING_LOCAL_FILES1 = "ms-appx:///Bing.Maps.JavaScript/js/veapicore.js",
|
|
BING_LOCAL_FILES2 = "ms-appx:///Bing.Maps.JavaScript/js/veapiModules.js",
|
|
BING_CREDENTIALS = "AhuxC0dQ1DBTNo8L-H9ToVMQStmizZzBJdraTSgCzDSWPsA1Qd8uIvFSflzxdaLH",
|
|
MIN_LOCATION_RECT_LENGTH = 0.0000000000000001;
|
|
var msMapsLoader;
|
|
ui.registerMapProvider("bing", ui.MapProvider.inherit({
|
|
_mapType: function(type) {
|
|
var mapTypes = {
|
|
roadmap: Microsoft.Maps.MapTypeId.road,
|
|
hybrid: Microsoft.Maps.MapTypeId.aerial
|
|
};
|
|
return mapTypes[type] || mapTypes.roadmap
|
|
},
|
|
_movementMode: function(type) {
|
|
var movementTypes = {
|
|
driving: Microsoft.Maps.Directions.RouteMode.driving,
|
|
walking: Microsoft.Maps.Directions.RouteMode.walking
|
|
};
|
|
return movementTypes[type] || movementTypes.driving
|
|
},
|
|
_resolveLocation: function(location) {
|
|
var d = $.Deferred();
|
|
if (typeof location === "string") {
|
|
var searchManager = new Microsoft.Maps.Search.SearchManager(this._map);
|
|
var searchRequest = {
|
|
where: location,
|
|
count: 1,
|
|
callback: function(searchResponse) {
|
|
var boundsBox = searchResponse.results[0].location;
|
|
d.resolve(new Microsoft.Maps.Location(boundsBox.latitude, boundsBox.longitude))
|
|
}
|
|
};
|
|
searchManager.geocode(searchRequest)
|
|
}
|
|
else if ($.isPlainObject(location) && $.isNumeric(location.lat) && $.isNumeric(location.lng))
|
|
d.resolve(new Microsoft.Maps.Location(location.lat, location.lng));
|
|
else if ($.isArray(location))
|
|
d.resolve(new Microsoft.Maps.Location(location[0], location[1]));
|
|
return d.promise()
|
|
},
|
|
_normalizeLocation: function(location) {
|
|
return {
|
|
lat: location.latitude,
|
|
lng: location.longitude
|
|
}
|
|
},
|
|
load: function() {
|
|
if (!msMapsLoader) {
|
|
msMapsLoader = $.Deferred();
|
|
window[BING_MAP_READY] = $.proxy(this._mapReady, this);
|
|
if (winJS)
|
|
$.when($.getScript(BING_LOCAL_FILES1), $.getScript(BING_LOCAL_FILES2)).done(function() {
|
|
Microsoft.Maps.loadModule("Microsoft.Maps.Map", {callback: window[BING_MAP_READY]})
|
|
});
|
|
else
|
|
$.getScript(BING_URL)
|
|
}
|
|
this._markers = [];
|
|
this._routes = [];
|
|
return msMapsLoader
|
|
},
|
|
_mapReady: function() {
|
|
try {
|
|
delete window[BING_MAP_READY]
|
|
}
|
|
catch(e) {
|
|
window[BING_MAP_READY] = undefined
|
|
}
|
|
var searchModulePromise = $.Deferred();
|
|
var directionsModulePromise = $.Deferred();
|
|
Microsoft.Maps.loadModule('Microsoft.Maps.Search', {callback: $.proxy(searchModulePromise.resolve, searchModulePromise)});
|
|
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', {callback: $.proxy(directionsModulePromise.resolve, directionsModulePromise)});
|
|
$.when(searchModulePromise, directionsModulePromise).done(function() {
|
|
msMapsLoader.resolve()
|
|
})
|
|
},
|
|
render: function() {
|
|
var deferred = $.Deferred(),
|
|
initPromise = $.Deferred(),
|
|
controls = this._option("controls");
|
|
var options = {
|
|
credentials: this._key("bing") || BING_CREDENTIALS,
|
|
mapTypeId: this._mapType(this._option("type")),
|
|
zoom: this._option("zoom"),
|
|
showDashboard: controls,
|
|
showMapTypeSelector: controls,
|
|
showScalebar: controls
|
|
};
|
|
this._map = new Microsoft.Maps.Map(this._$container[0], options);
|
|
var handler = Microsoft.Maps.Events.addHandler(this._map, 'tiledownloadcomplete', $.proxy(initPromise.resolve, initPromise));
|
|
this._viewChangeHandler = Microsoft.Maps.Events.addHandler(this._map, 'viewchange', $.proxy(this._handleViewChange, this));
|
|
this._clickHandler = Microsoft.Maps.Events.addHandler(this._map, 'click', $.proxy(this._handleClickAction, this));
|
|
var locationPromise = this._renderLocation();
|
|
var markersPromise = this._refreshMarkers();
|
|
var routesPromise = this._renderRoutes();
|
|
$.when(initPromise, locationPromise, markersPromise, routesPromise).done(function() {
|
|
Microsoft.Maps.Events.removeHandler(handler);
|
|
deferred.resolve(true)
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_handleViewChange: function() {
|
|
var center = this._map.getCenter();
|
|
this._option("location", this._normalizeLocation(center));
|
|
this._option("zoom", this._map.getZoom())
|
|
},
|
|
updateDimensions: function() {
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateMapType: function() {
|
|
this._map.setView({mapTypeId: this._mapType(this._option("type"))});
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateLocation: function() {
|
|
return this._renderLocation()
|
|
},
|
|
_renderLocation: function() {
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
this._resolveLocation(this._option("location")).done(function(location) {
|
|
self._map.setView({
|
|
animate: false,
|
|
center: location
|
|
});
|
|
deferred.resolve()
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
updateZoom: function() {
|
|
this._map.setView({
|
|
animate: false,
|
|
zoom: this._option("zoom")
|
|
});
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateControls: function() {
|
|
this.clean();
|
|
return this.render()
|
|
},
|
|
_clearBounds: function() {
|
|
this._bounds = null
|
|
},
|
|
_extendBounds: function(location) {
|
|
if (this._bounds)
|
|
this._bounds = new Microsoft.Maps.LocationRect.fromLocations(this._bounds.getNorthwest(), this._bounds.getSoutheast(), location);
|
|
else
|
|
this._bounds = new Microsoft.Maps.LocationRect(location, MIN_LOCATION_RECT_LENGTH, MIN_LOCATION_RECT_LENGTH)
|
|
},
|
|
_fitBounds: function() {
|
|
if (!this._bounds)
|
|
return;
|
|
this._bounds.height = this._bounds.height * 1.1;
|
|
this._bounds.width = this._bounds.width * 1.1;
|
|
this._map.setView({
|
|
animate: false,
|
|
bounds: this._bounds
|
|
})
|
|
},
|
|
updateMarkers: function() {
|
|
return this._refreshMarkers()
|
|
},
|
|
_refreshMarkers: function() {
|
|
this._clearMarkers();
|
|
return this._renderMarkers()
|
|
},
|
|
_clearMarkers: function() {
|
|
var self = this;
|
|
this._clearBounds();
|
|
$.each(this._markers, function(_, marker) {
|
|
self._map.entities.remove(marker.pushpin);
|
|
if (marker.infobox)
|
|
self._map.entities.remove(marker.infobox);
|
|
if (marker.handler)
|
|
Microsoft.Maps.Events.removeHandler(marker.handler)
|
|
});
|
|
this._markers = []
|
|
},
|
|
addMarkers: function(options) {
|
|
return this._renderMarkers(options)
|
|
},
|
|
_renderMarkers: function(options) {
|
|
options = options || this._option("markers");
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
var markerPromises = $.map(options, function(markerOptions) {
|
|
return self._addMarker(markerOptions)
|
|
});
|
|
$.when.apply($, markerPromises).done(function() {
|
|
var instances = $.map($.makeArray(arguments), function(marker) {
|
|
return marker.pushpin
|
|
});
|
|
deferred.resolve(false, instances)
|
|
});
|
|
deferred.done(function() {
|
|
self._fitBounds()
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_addMarker: function(options) {
|
|
var self = this;
|
|
return this._renderMarker(options).done(function(marker) {
|
|
self._markers.push(marker)
|
|
})
|
|
},
|
|
_renderMarker: function(options) {
|
|
var d = $.Deferred(),
|
|
self = this;
|
|
this._resolveLocation(options.location).done(function(location) {
|
|
var pushpinOptions = null,
|
|
markerIcon = self._option("markerIconSrc");
|
|
if (markerIcon)
|
|
pushpinOptions = {icon: markerIcon};
|
|
if (options.iconSrc)
|
|
pushpinOptions = {icon: options.iconSrc};
|
|
var pushpin = new Microsoft.Maps.Pushpin(location, pushpinOptions);
|
|
self._map.entities.push(pushpin, null);
|
|
var infobox = self._renderTooltip(location, options.tooltip);
|
|
var handler;
|
|
if (options.clickAction || options.tooltip) {
|
|
var markerClickAction = self._createAction(options.clickAction || $.noop);
|
|
handler = Microsoft.Maps.Events.addHandler(pushpin, "click", function() {
|
|
markerClickAction({location: self._normalizeLocation(location)});
|
|
if (infobox)
|
|
infobox.setOptions({visible: true})
|
|
})
|
|
}
|
|
self._extendBounds(location);
|
|
d.resolve({
|
|
pushpin: pushpin,
|
|
infobox: infobox,
|
|
handler: handler
|
|
})
|
|
});
|
|
return d.promise()
|
|
},
|
|
_renderTooltip: function(location, options) {
|
|
if (!options)
|
|
return;
|
|
options = this._parseTooltipOptions(options);
|
|
var infobox = new Microsoft.Maps.Infobox(location, {
|
|
description: options.text,
|
|
offset: new Microsoft.Maps.Point(0, 33),
|
|
visible: options.visible
|
|
});
|
|
this._map.entities.push(infobox, null);
|
|
return infobox
|
|
},
|
|
updateRoutes: function() {
|
|
return this._refreshRoutes()
|
|
},
|
|
addRoutes: function(options) {
|
|
return this._renderRoutes(options)
|
|
},
|
|
_refreshRoutes: function() {
|
|
this._clearRoutes();
|
|
return this._renderRoutes()
|
|
},
|
|
_renderRoutes: function(options) {
|
|
options = options || this._option("routes");
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
var routePromises = $.map(options, function(routeOptions) {
|
|
return self._addRoute(routeOptions)
|
|
});
|
|
$.when.apply($, routePromises).done(function() {
|
|
deferred.resolve(false, $.makeArray(arguments))
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_clearRoutes: function() {
|
|
var self = this;
|
|
$.each(this._routes, function(_, route) {
|
|
route.dispose()
|
|
});
|
|
this._routes = []
|
|
},
|
|
_addRoute: function(routeOptions) {
|
|
var self = this;
|
|
return this._renderRoute(routeOptions).done(function(route) {
|
|
self._routes.push(route)
|
|
})
|
|
},
|
|
_renderRoute: function(options) {
|
|
var d = $.Deferred(),
|
|
self = this;
|
|
var points = $.map(options.locations, function(point) {
|
|
return self._resolveLocation(point)
|
|
});
|
|
$.when.apply($, points).done(function() {
|
|
var locations = $.makeArray(arguments),
|
|
direction = new Microsoft.Maps.Directions.DirectionsManager(self._map),
|
|
color = new DX.Color(options.color || self._defaultRouteColor()).toHex(),
|
|
routeColor = new Microsoft.Maps.Color.fromHex(color);
|
|
routeColor.a = (options.opacity || self._defaultRouteOpacity()) * 255;
|
|
direction.setRenderOptions({
|
|
autoUpdateMapView: false,
|
|
displayRouteSelector: false,
|
|
waypointPushpinOptions: {visible: false},
|
|
drivingPolylineOptions: {
|
|
strokeColor: routeColor,
|
|
strokeThickness: options.weight || self._defaultRouteWeight()
|
|
},
|
|
walkingPolylineOptions: {
|
|
strokeColor: routeColor,
|
|
strokeThickness: options.weight || self._defaultRouteWeight()
|
|
}
|
|
});
|
|
direction.setRequestOptions({
|
|
routeMode: self._movementMode(options.mode),
|
|
routeDraggable: false
|
|
});
|
|
$.each(locations, function(_, location) {
|
|
var waypoint = new Microsoft.Maps.Directions.Waypoint({location: location});
|
|
direction.addWaypoint(waypoint)
|
|
});
|
|
var handler = Microsoft.Maps.Events.addHandler(direction, 'directionsUpdated', function() {
|
|
Microsoft.Maps.Events.removeHandler(handler);
|
|
d.resolve(direction)
|
|
});
|
|
direction.calculateDirections()
|
|
});
|
|
return d.promise()
|
|
},
|
|
clean: function() {
|
|
if (this._map) {
|
|
Microsoft.Maps.Events.removeHandler(this._viewChangeHandler);
|
|
Microsoft.Maps.Events.removeHandler(this._clickHandler);
|
|
this._clearMarkers();
|
|
this._clearRoutes();
|
|
this._map.dispose()
|
|
}
|
|
},
|
|
cancelEvents: true
|
|
}));
|
|
if (!ui.dxMap.__internals)
|
|
ui.dxMap.__internals = {};
|
|
var prevRemapConstant = ui.dxMap.__internals.remapConstant || $.noop;
|
|
ui.dxMap.__internals.remapConstant = function(variable, newValue) {
|
|
switch (variable) {
|
|
case"BING_URL":
|
|
BING_URL = newValue;
|
|
break;
|
|
default:
|
|
prevRemapConstant.apply(this, arguments)
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.map.google.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var GOOGLE_MAP_READY = "_googleScriptReady",
|
|
GOOGLE_URL = "https://maps.google.com/maps/api/js?v=3.9&sensor=false&callback=" + GOOGLE_MAP_READY;
|
|
var googleMapsLoader;
|
|
ui.registerMapProvider("google", ui.MapProvider.inherit({
|
|
_mapType: function(type) {
|
|
var mapTypes = {
|
|
hybrid: google.maps.MapTypeId.HYBRID,
|
|
roadmap: google.maps.MapTypeId.ROADMAP
|
|
};
|
|
return mapTypes[type] || mapTypes.hybrid
|
|
},
|
|
_movementMode: function(type) {
|
|
var movementTypes = {
|
|
driving: google.maps.TravelMode.DRIVING,
|
|
walking: google.maps.TravelMode.WALKING
|
|
};
|
|
return movementTypes[type] || movementTypes.driving
|
|
},
|
|
_resolveLocation: function(location) {
|
|
var d = $.Deferred();
|
|
if (typeof location === "string") {
|
|
var geocoder = new google.maps.Geocoder;
|
|
geocoder.geocode({address: location}, function(results, status) {
|
|
if (status === google.maps.GeocoderStatus.OK)
|
|
d.resolve(results[0].geometry.location)
|
|
})
|
|
}
|
|
else if ($.isArray(location))
|
|
d.resolve(new google.maps.LatLng(location[0], location[1]));
|
|
else if ($.isPlainObject(location) && $.isNumeric(location.lat) && $.isNumeric(location.lng))
|
|
d.resolve(new google.maps.LatLng(location.lat, location.lng));
|
|
return d.promise()
|
|
},
|
|
_normalizeLocation: function(location) {
|
|
return {
|
|
lat: location.lat(),
|
|
lng: location.lng()
|
|
}
|
|
},
|
|
load: function() {
|
|
if (!googleMapsLoader) {
|
|
googleMapsLoader = $.Deferred();
|
|
var key = this._key("google");
|
|
window[GOOGLE_MAP_READY] = $.proxy(this._mapReady, this);
|
|
$.getScript(GOOGLE_URL + (key ? "&key=" + key : ""))
|
|
}
|
|
this._markers = [];
|
|
this._routes = [];
|
|
return googleMapsLoader.promise()
|
|
},
|
|
_mapReady: function() {
|
|
try {
|
|
delete window[GOOGLE_MAP_READY]
|
|
}
|
|
catch(e) {
|
|
window[GOOGLE_MAP_READY] = undefined
|
|
}
|
|
googleMapsLoader.resolve()
|
|
},
|
|
render: function() {
|
|
var deferred = $.Deferred(),
|
|
initPromise = $.Deferred(),
|
|
controls = this._option("controls");
|
|
var options = {
|
|
zoom: this._option("zoom"),
|
|
center: new google.maps.LatLng(0, 0),
|
|
mapTypeId: this._mapType(this._option("type")),
|
|
panControl: controls,
|
|
zoomControl: controls,
|
|
mapTypeControl: controls,
|
|
streetViewControl: controls
|
|
};
|
|
this._map = new google.maps.Map(this._$container[0], options);
|
|
var listner = google.maps.event.addListener(this._map, 'idle', $.proxy(initPromise.resolve, initPromise));
|
|
this._zoomChangeListener = google.maps.event.addListener(this._map, 'zoom_changed', $.proxy(this._handleZoomChange, this));
|
|
this._centerChangeListener = google.maps.event.addListener(this._map, 'center_changed', $.proxy(this._handleCenterChange, this));
|
|
this._clickListener = google.maps.event.addListener(this._map, 'click', $.proxy(this._handleClickAction, this));
|
|
var locationPromise = this._renderLocation();
|
|
var markersPromise = this._refreshMarkers();
|
|
var routesPromise = this._renderRoutes();
|
|
$.when(initPromise, locationPromise, markersPromise, routesPromise).done(function() {
|
|
google.maps.event.removeListener(listner);
|
|
deferred.resolve(true)
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
updateDimensions: function() {
|
|
google.maps.event.trigger(this._map, 'resize');
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateMapType: function() {
|
|
this._map.setMapTypeId(this._mapType(this._option("type")));
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateLocation: function() {
|
|
return this._renderLocation()
|
|
},
|
|
_handleCenterChange: function() {
|
|
var center = this._map.getCenter();
|
|
this._option("location", this._normalizeLocation(center))
|
|
},
|
|
_renderLocation: function() {
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
this._resolveLocation(this._option("location")).done(function(location) {
|
|
self._map.setCenter(location);
|
|
deferred.resolve()
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_handleZoomChange: function() {
|
|
this._option("zoom", this._map.getZoom())
|
|
},
|
|
updateZoom: function() {
|
|
this._map.setZoom(this._option("zoom"));
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateControls: function() {
|
|
var controls = this._option("controls");
|
|
this._map.setOptions({
|
|
panControl: controls,
|
|
zoomControl: controls,
|
|
mapTypeControl: controls,
|
|
streetViewControl: controls
|
|
});
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
_clearBounds: function() {
|
|
this._bounds = null
|
|
},
|
|
_extendBounds: function(location) {
|
|
if (this._bounds)
|
|
this._bounds.extend(location);
|
|
else {
|
|
this._bounds = new google.maps.LatLngBounds;
|
|
this._bounds.extend(location)
|
|
}
|
|
},
|
|
_fitBounds: function() {
|
|
if (!this._bounds)
|
|
return;
|
|
this._map.fitBounds(this._bounds)
|
|
},
|
|
updateMarkers: function() {
|
|
return this._refreshMarkers()
|
|
},
|
|
_refreshMarkers: function() {
|
|
this._clearMarkers();
|
|
return this._renderMarkers()
|
|
},
|
|
_clearMarkers: function() {
|
|
var self = this;
|
|
this._clearBounds();
|
|
$.each(this._markers, function(_, marker) {
|
|
marker.instance.setMap(null);
|
|
if (marker.listner)
|
|
google.maps.event.removeListener(marker.listner)
|
|
});
|
|
this._markers = []
|
|
},
|
|
addMarkers: function(options) {
|
|
return this._renderMarkers(options)
|
|
},
|
|
_renderMarkers: function(options) {
|
|
options = options || this._option("markers");
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
var markerPromises = $.map(options, function(markerOptions) {
|
|
return self._addMarker(markerOptions)
|
|
});
|
|
$.when.apply($, markerPromises).done(function() {
|
|
var instances = $.map($.makeArray(arguments), function(marker) {
|
|
return marker.instance
|
|
});
|
|
deferred.resolve(false, instances)
|
|
});
|
|
deferred.done(function() {
|
|
self._fitBounds()
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_addMarker: function(options) {
|
|
var self = this;
|
|
return this._renderMarker(options).done(function(marker) {
|
|
self._markers.push(marker)
|
|
})
|
|
},
|
|
_renderMarker: function(options) {
|
|
var d = $.Deferred(),
|
|
self = this;
|
|
this._resolveLocation(options.location).done(function(location) {
|
|
var marker,
|
|
markerOptions = {
|
|
position: location,
|
|
map: self._map
|
|
},
|
|
markerIcon = self._option("markerIconSrc"),
|
|
listner;
|
|
if (markerIcon)
|
|
markerOptions.icon = markerIcon;
|
|
if (options.iconSrc)
|
|
markerOptions.icon = options.iconSrc;
|
|
marker = new google.maps.Marker(markerOptions);
|
|
var infoWindow = self._renderTooltip(marker, options.tooltip);
|
|
if (options.clickAction || options.tooltip) {
|
|
var markerClickAction = self._createAction(options.clickAction || $.noop);
|
|
listner = google.maps.event.addListener(marker, "click", function() {
|
|
markerClickAction({location: self._normalizeLocation(location)});
|
|
if (infoWindow)
|
|
infoWindow.open(self._map, marker)
|
|
})
|
|
}
|
|
self._extendBounds(location);
|
|
d.resolve({
|
|
instance: marker,
|
|
listner: listner
|
|
})
|
|
});
|
|
return d.promise()
|
|
},
|
|
_renderTooltip: function(marker, options) {
|
|
if (!options)
|
|
return;
|
|
options = this._parseTooltipOptions(options);
|
|
var infoWindow = new google.maps.InfoWindow({content: options.text});
|
|
if (options.visible)
|
|
infoWindow.open(this._map, marker);
|
|
return infoWindow
|
|
},
|
|
updateRoutes: function() {
|
|
return this._refreshRoutes()
|
|
},
|
|
addRoutes: function(options) {
|
|
return this._renderRoutes()
|
|
},
|
|
_refreshRoutes: function() {
|
|
this._clearRoutes();
|
|
return this._renderRoutes()
|
|
},
|
|
_clearRoutes: function() {
|
|
var self = this;
|
|
$.each(this._routes, function(_, route) {
|
|
route.setMap(null)
|
|
});
|
|
this._routes = []
|
|
},
|
|
_renderRoutes: function(options) {
|
|
options = options || this._option("routes");
|
|
var deferred = $.Deferred(),
|
|
self = this;
|
|
var routePromises = $.map(options, function(routeOptions) {
|
|
return self._addRoute(routeOptions)
|
|
});
|
|
$.when.apply($, routePromises).done(function() {
|
|
deferred.resolve(false, $.makeArray(arguments))
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_addRoute: function(options) {
|
|
var self = this;
|
|
return this._renderRoute(options).done(function(route) {
|
|
self._routes.push(route)
|
|
})
|
|
},
|
|
_renderRoute: function(options) {
|
|
var d = $.Deferred(),
|
|
self = this,
|
|
directionsService = new google.maps.DirectionsService;
|
|
var points = $.map(options.locations, function(point) {
|
|
return self._resolveLocation(point)
|
|
});
|
|
$.when.apply($, points).done(function() {
|
|
var locations = $.makeArray(arguments),
|
|
origin = locations.shift(),
|
|
destination = locations.pop(),
|
|
waypoints = $.map(locations, function(location) {
|
|
return {
|
|
location: location,
|
|
stopover: true
|
|
}
|
|
});
|
|
var request = {
|
|
origin: origin,
|
|
destination: destination,
|
|
waypoints: waypoints,
|
|
optimizeWaypoints: true,
|
|
travelMode: self._movementMode(options.mode)
|
|
};
|
|
directionsService.route(request, function(response, status) {
|
|
if (status === google.maps.DirectionsStatus.OK) {
|
|
var color = new DX.Color(options.color || self._defaultRouteColor()).toHex(),
|
|
directionOptions = {
|
|
directions: response,
|
|
map: self._map,
|
|
suppressMarkers: true,
|
|
preserveViewport: true,
|
|
polylineOptions: {
|
|
strokeWeight: options.weight || self._defaultRouteWeight(),
|
|
strokeOpacity: options.opacity || self._defaultRouteOpacity(),
|
|
strokeColor: color
|
|
}
|
|
};
|
|
var route = new google.maps.DirectionsRenderer(directionOptions);
|
|
d.resolve(route)
|
|
}
|
|
})
|
|
});
|
|
return d.promise()
|
|
},
|
|
clean: function() {
|
|
if (this._map) {
|
|
google.maps.event.removeListener(this._zoomChangeListener);
|
|
google.maps.event.removeListener(this._centerChangeListener);
|
|
google.maps.event.removeListener(this._clickListener);
|
|
this._clearMarkers();
|
|
this._clearRoutes();
|
|
delete this._map;
|
|
this._$container.empty()
|
|
}
|
|
},
|
|
cancelEvents: true
|
|
}));
|
|
if (!ui.dxMap.__internals)
|
|
ui.dxMap.__internals = {};
|
|
var prevRemapConstant = ui.dxMap.__internals.remapConstant || $.noop;
|
|
ui.dxMap.__internals.remapConstant = function(variable, newValue) {
|
|
switch (variable) {
|
|
case"GOOGLE_URL":
|
|
GOOGLE_URL = newValue;
|
|
break;
|
|
default:
|
|
prevRemapConstant.apply(this, arguments)
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.map.googleStatic.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var GOOGLE_STATIC_URL = "https://maps.google.com/maps/api/staticmap?";
|
|
ui.registerMapProvider("googleStatic", ui.MapProvider.inherit({
|
|
_locationToString: function(location) {
|
|
return !$.isPlainObject(location) ? location.toString().replace(/ /g, "+") : location.lat + "," + location.lng
|
|
},
|
|
render: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateDimensions: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateMapType: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateLocation: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateZoom: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateControls: function() {
|
|
return $.Deferred().resolve().promise()
|
|
},
|
|
updateMarkers: function() {
|
|
return this._updateMap()
|
|
},
|
|
addMarkers: function() {
|
|
return this._updateMap()
|
|
},
|
|
updateRoutes: function() {
|
|
return this._updateMap()
|
|
},
|
|
addRoutes: function() {
|
|
return this._updateMap()
|
|
},
|
|
clean: function() {
|
|
this._$container.css("background-image", "none")
|
|
},
|
|
mapRendered: function() {
|
|
return true
|
|
},
|
|
_updateMap: function() {
|
|
var key = this._key("googleStatic");
|
|
var requestOptions = ["sensor=false", "size=" + this._option("width") + "x" + this._option("height"), "maptype=" + this._option("type"), "center=" + this._locationToString(this._option("location")), "zoom=" + this._option("zoom"), this._markersSubstring()];
|
|
requestOptions.push.apply(requestOptions, this._routeSubstrings());
|
|
if (key)
|
|
requestOptions.push("key=" + this._key("googleStatic"));
|
|
var request = GOOGLE_STATIC_URL + requestOptions.join("&");
|
|
this._$container.css("background", "url(\"" + request + "\") no-repeat 0 0");
|
|
return $.Deferred().resolve(true).promise()
|
|
},
|
|
_markersSubstring: function() {
|
|
var self = this,
|
|
markers = [],
|
|
markerIcon = this._option("markerIconSrc");
|
|
if (markerIcon)
|
|
markers.push("icon:" + markerIcon);
|
|
$.each(this._option("markers"), function(_, marker) {
|
|
markers.push(self._locationToString(marker.location))
|
|
});
|
|
return "markers=" + markers.join("|")
|
|
},
|
|
_routeSubstrings: function() {
|
|
var self = this,
|
|
routes = [];
|
|
$.each(this._option("routes"), function(_, route) {
|
|
var color = new DX.Color(route.color || ROUTE_COLOR_DEFAULT).toHex().replace('#', '0x'),
|
|
opacity = Math.round((route.opacity || ROUTE_OPACITY_DEFAULT) * 255).toString(16),
|
|
width = route.weight || ROUTE_WEIGHT_DEFAULT,
|
|
locations = [];
|
|
$.each(route.locations, function(_, routePoint) {
|
|
locations.push(self._locationToString(routePoint))
|
|
});
|
|
routes.push("path=color:" + color + opacity + "|weight:" + width + "|" + locations.join("|"))
|
|
});
|
|
return routes
|
|
}
|
|
}));
|
|
if (!ui.dxMap.__internals)
|
|
ui.dxMap.__internals = {};
|
|
var prevRemapConstant = ui.dxMap.__internals.remapConstant || $.noop;
|
|
ui.dxMap.__internals.remapConstant = function(variable, newValue) {
|
|
switch (variable) {
|
|
case"GOOGLE_STATIC_URL":
|
|
GOOGLE_STATIC_URL = newValue;
|
|
break;
|
|
case"GOOGLE_DIRECTIONS_URL":
|
|
GOOGLE_DIRECTIONS_URL = newValue;
|
|
break;
|
|
default:
|
|
prevRemapConstant.apply(this, arguments)
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.swipeable.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
DX_SWIPEABLE = "dxSwipeable",
|
|
SWIPEABLE_CLASS = "dx-swipeable",
|
|
ACTION_TO_EVENT_MAP = {
|
|
startAction: "dxswipestart",
|
|
updateAction: "dxswipe",
|
|
endAction: "dxswipeend",
|
|
cancelAction: "dxswipecancel"
|
|
};
|
|
ui.registerComponent(DX_SWIPEABLE, ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
elastic: true,
|
|
direction: "horizontal",
|
|
itemSizeFunc: null,
|
|
startAction: null,
|
|
updateAction: null,
|
|
endAction: null,
|
|
cancelAction: null
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(SWIPEABLE_CLASS);
|
|
this._attachEventHandlers()
|
|
},
|
|
_attachEventHandlers: function() {
|
|
if (this.option("disabled"))
|
|
return;
|
|
var NAME = this.NAME;
|
|
this._createEventData();
|
|
$.each(ACTION_TO_EVENT_MAP, $.proxy(function(actionName, eventName) {
|
|
var action = this._createActionByOption(actionName, {
|
|
context: this,
|
|
excludeValidators: ["gesture"]
|
|
}),
|
|
eventName = events.addNamespace(eventName, NAME);
|
|
this._element().off(eventName).on(eventName, this._eventData, function(e) {
|
|
return action({jQueryEvent: e})
|
|
})
|
|
}, this))
|
|
},
|
|
_createEventData: function() {
|
|
this._eventData = {
|
|
elastic: this.option("elastic"),
|
|
itemSizeFunc: this.option("itemSizeFunc"),
|
|
direction: this.option("direction")
|
|
}
|
|
},
|
|
_detachEventHanlers: function() {
|
|
this._element().off("." + DX_SWIPEABLE)
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"disabled":
|
|
case"startAction":
|
|
case"updateAction":
|
|
case"endAction":
|
|
case"cancelAction":
|
|
case"elastic":
|
|
case"itemSizeFunc":
|
|
case"direction":
|
|
this._detachEventHanlers();
|
|
this._attachEventHandlers();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.button.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var BUTTON_CLASS = "dx-button",
|
|
BUTTON_CONTENT_CLASS = "dx-button-content",
|
|
BUTTON_CONTENT_SELECTOR = ".dx-button-content",
|
|
BUTTON_TEXT_CLASS = "dx-button-text",
|
|
BUTTON_TEXT_SELECTOR = ".dx-button-text",
|
|
BUTTON_BACK_ARROW_CLASS = "dx-button-back-arrow",
|
|
ICON_CLASS = "dx-icon",
|
|
ICON_SELECTOR = ".dx-icon",
|
|
BUTTON_FEEDBACK_HIDE_TIMEOUT = 100;
|
|
ui.registerComponent("dxButton", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
type: "normal",
|
|
text: "",
|
|
icon: "",
|
|
iconSrc: "",
|
|
hoverStateEnabled: true
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._feedbackHideTimeout = BUTTON_FEEDBACK_HIDE_TIMEOUT
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(BUTTON_CLASS).append($("<div />").addClass(BUTTON_CONTENT_CLASS));
|
|
this._renderIcon();
|
|
this._renderType();
|
|
this._renderText()
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._removeTypesCss()
|
|
},
|
|
_removeTypesCss: function() {
|
|
var css = this._element().attr("class");
|
|
css = css.replace(/\bdx-button-[-a-z0-9]+\b/gi, "");
|
|
this._element().attr("class", css)
|
|
},
|
|
_renderIcon: function() {
|
|
var contentElement = this._element().find(BUTTON_CONTENT_SELECTOR),
|
|
iconElement = contentElement.find(ICON_SELECTOR),
|
|
icon = this.option("icon"),
|
|
iconSrc = this.option("iconSrc");
|
|
iconElement.remove();
|
|
if (this.option("type") === "back" && !icon)
|
|
icon = "back";
|
|
if (!icon && !iconSrc)
|
|
return;
|
|
if (icon)
|
|
iconElement = $("<span />").addClass("dx-icon-" + icon);
|
|
else if (iconSrc)
|
|
iconElement = $("<img />").attr("src", iconSrc);
|
|
contentElement.prepend(iconElement.addClass(ICON_CLASS))
|
|
},
|
|
_renderType: function() {
|
|
var type = this.option("type");
|
|
if (type)
|
|
this._element().addClass("dx-button-" + type);
|
|
if (type === "back")
|
|
this._element().prepend($("<span />").addClass(BUTTON_BACK_ARROW_CLASS))
|
|
},
|
|
_renderText: function() {
|
|
var text = this.option("text"),
|
|
contentElement = this._element().find(BUTTON_CONTENT_SELECTOR),
|
|
back = this.option("type") === "back";
|
|
var textElement = contentElement.find(BUTTON_TEXT_SELECTOR);
|
|
if (!text && !back) {
|
|
textElement.remove();
|
|
return
|
|
}
|
|
if (!textElement.length)
|
|
textElement = $('<span />').addClass(BUTTON_TEXT_CLASS).appendTo(contentElement);
|
|
textElement.text(text || DX.localization.localizeString("@Back"))
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"icon":
|
|
case"iconSrc":
|
|
this._renderIcon();
|
|
break;
|
|
case"text":
|
|
this._renderText();
|
|
break;
|
|
case"type":
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.checkBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var CHECKBOX_CLASS = "dx-checkbox",
|
|
CHECKBOX_ICON_CLASS = "dx-checkbox-icon",
|
|
CHECKBOX_CHECKED_CLASS = "dx-checkbox-checked",
|
|
CHECKBOX_FEEDBACK_HIDE_TIMEOUT = 100;
|
|
ui.registerComponent("dxCheckBox", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
checked: false,
|
|
hoverStateEnabled: true
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._feedbackHideTimeout = CHECKBOX_FEEDBACK_HIDE_TIMEOUT
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(CHECKBOX_CLASS);
|
|
$("<span />").addClass(CHECKBOX_ICON_CLASS).appendTo(this._element());
|
|
this._renderValue()
|
|
},
|
|
_renderClick: function() {
|
|
var self = this,
|
|
eventName = events.addNamespace("dxclick", this.NAME),
|
|
action = this._createActionByOption("clickAction", {beforeExecute: function() {
|
|
self.option("checked", !self.option("checked"))
|
|
}});
|
|
this._element().off(eventName).on(eventName, function(e) {
|
|
action({jQueryEvent: e})
|
|
})
|
|
},
|
|
_renderValue: function() {
|
|
this._element().toggleClass(CHECKBOX_CHECKED_CLASS, Boolean(this.option("checked")))
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"checked":
|
|
this._renderValue();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.switch.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
fx = DX.fx;
|
|
var SWITCH_CLASS = "dx-switch",
|
|
SWITCH_WRAPPER_CLASS = SWITCH_CLASS + "-wrapper",
|
|
SWITCH_INNER_CLASS = SWITCH_CLASS + "-inner",
|
|
SWITCH_HANDLE_CLASS = SWITCH_CLASS + "-handle",
|
|
SWITCH_ON_VALUE_CLASS = SWITCH_CLASS + "-on-value",
|
|
SWITCH_ON_CLASS = SWITCH_CLASS + "-on",
|
|
SWITCH_OFF_CLASS = SWITCH_CLASS + "-off",
|
|
SWITCH_ANIMATION_DURATION = 100;
|
|
ui.registerComponent("dxSwitch", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
onText: Globalize.localize("dxSwitch-onText"),
|
|
offText: Globalize.localize("dxSwitch-offText"),
|
|
value: false,
|
|
valueChangeAction: null
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._animating = false;
|
|
this._animationDuration = SWITCH_ANIMATION_DURATION
|
|
},
|
|
_render: function() {
|
|
var element = this._element();
|
|
this._$switchInner = $("<div />").addClass(SWITCH_INNER_CLASS);
|
|
this._$handle = $("<div />").addClass(SWITCH_HANDLE_CLASS).appendTo(this._$switchInner);
|
|
this._$labelOn = $("<div />").addClass(SWITCH_ON_CLASS).prependTo(this._$switchInner);
|
|
this._$labelOff = $("<div />").addClass(SWITCH_OFF_CLASS).appendTo(this._$switchInner);
|
|
this._$switchWrapper = $("<div />").addClass(SWITCH_WRAPPER_CLASS).append(this._$switchInner);
|
|
element.addClass(SWITCH_CLASS).append(this._$switchWrapper);
|
|
element.dxSwipeable({
|
|
elastic: false,
|
|
startAction: $.proxy(this._handleSwipeStart, this),
|
|
updateAction: $.proxy(this._handleSwipeUpdate, this),
|
|
endAction: $.proxy(this._handleSwipeEnd, this)
|
|
});
|
|
this._renderLabels();
|
|
this.callBase();
|
|
this._updateMarginBound();
|
|
this._renderValue();
|
|
this._renderValueChangeAction()
|
|
},
|
|
_renderValueChangeAction: function() {
|
|
this._changeAction = this._createActionByOption("valueChangeAction")
|
|
},
|
|
_updateMarginBound: function() {
|
|
this._marginBound = this._$switchWrapper.outerWidth(true) - this._$handle.width()
|
|
},
|
|
_renderPosition: function(state, swipeOffset) {
|
|
var stateInt = state ? 1 : 0;
|
|
this._$switchInner.css("marginLeft", this._marginBound * (stateInt + swipeOffset - 1))
|
|
},
|
|
_validateValue: function() {
|
|
var check = this.option("value");
|
|
if (typeof check !== "boolean")
|
|
this._options["value"] = !!check
|
|
},
|
|
_renderClick: function() {
|
|
this.callBase();
|
|
var eventName = events.addNamespace("dxclick", this.NAME),
|
|
clickAction = this._createAction($.proxy(this._handleClick, this));
|
|
this._element().on(eventName, function(e) {
|
|
clickAction({jQueryEvent: e})
|
|
})
|
|
},
|
|
_handleClick: function(args) {
|
|
var self = args.component;
|
|
if (self._animating || self._swiping)
|
|
return;
|
|
self._animating = true;
|
|
var startValue = self.option("value"),
|
|
endValue = !startValue;
|
|
fx.animate(this._$switchInner, {
|
|
from: {marginLeft: (Number(startValue) - 1) * this._marginBound},
|
|
to: {marginLeft: (Number(endValue) - 1) * this._marginBound},
|
|
duration: self._animationDuration,
|
|
complete: function() {
|
|
self._animating = false;
|
|
self.option("value", endValue)
|
|
}
|
|
})
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
var state = this.option("value");
|
|
e.jQueryEvent.maxLeftOffset = state ? 1 : 0;
|
|
e.jQueryEvent.maxRightOffset = state ? 0 : 1;
|
|
this._swiping = true
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
this._renderPosition(this.option("value"), e.jQueryEvent.offset)
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
var self = this;
|
|
fx.animate(this._$switchInner, {
|
|
to: {marginLeft: this._marginBound * (self.option("value") + e.jQueryEvent.targetOffset - 1)},
|
|
duration: self._animationDuration,
|
|
complete: function() {
|
|
self._swiping = false;
|
|
var pos = self.option("value") + e.jQueryEvent.targetOffset;
|
|
self.option("value", Boolean(pos))
|
|
}
|
|
})
|
|
},
|
|
_renderValue: function() {
|
|
this._validateValue();
|
|
var val = this.option("value");
|
|
this._renderPosition(val, 0);
|
|
this._element().toggleClass(SWITCH_ON_VALUE_CLASS, val)
|
|
},
|
|
_renderLabels: function() {
|
|
this._$labelOn.text(this.option("onText"));
|
|
this._$labelOff.text(this.option("offText"))
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"visible":
|
|
case"width":
|
|
this._refresh();
|
|
break;
|
|
case"value":
|
|
this._renderValue();
|
|
this._changeAction(value);
|
|
break;
|
|
case"valueChangeAction":
|
|
this._renderValueChangeAction();
|
|
break;
|
|
case"onText":
|
|
case"offText":
|
|
this._renderLabels();
|
|
break;
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
},
|
|
_feedbackOff: function(isGestureStart) {
|
|
if (isGestureStart)
|
|
return;
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.editBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var EDITBOX_CLASS = "dx-editbox",
|
|
EDITBOX_INPUT_CLASS = "dx-editbox-input",
|
|
EDITBOX_INPUT_SELECTOR = "." + EDITBOX_INPUT_CLASS,
|
|
EDITBOX_BORDER_CLASS = "dx-editbox-border",
|
|
EDITBOX_PLACEHOLDER_CLASS = "dx-placeholder",
|
|
EVENTS_LIST = ["focusIn", "focusOut", "keyDown", "keyPress", "keyUp", "change"];
|
|
var nativePlaceholderSupport = function() {
|
|
var check = document.createElement("input");
|
|
return "placeholder" in check
|
|
}();
|
|
ui.registerComponent("dxEditBox", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
value: "",
|
|
valueUpdateEvent: "change",
|
|
valueUpdateAction: null,
|
|
placeholder: "",
|
|
readOnly: false,
|
|
focusInAction: null,
|
|
focusOutAction: null,
|
|
keyDownAction: null,
|
|
keyPressAction: null,
|
|
keyUpAction: null,
|
|
changeAction: null,
|
|
enterKeyAction: null,
|
|
mode: "text"
|
|
})
|
|
},
|
|
_input: function() {
|
|
return this._element().find(EDITBOX_INPUT_SELECTOR)
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(EDITBOX_CLASS);
|
|
this._renderInput();
|
|
this._renderInputType();
|
|
this._renderValue();
|
|
this._renderProps();
|
|
this._renderPlaceholder();
|
|
this._renderEvents();
|
|
this._renderEnterKeyAction();
|
|
this.callBase()
|
|
},
|
|
_renderInput: function() {
|
|
this._element().append($("<input />").addClass(EDITBOX_INPUT_CLASS)).append($("<div />").addClass(EDITBOX_BORDER_CLASS))
|
|
},
|
|
_renderValue: function() {
|
|
if (this._input().val() !== this.option("value"))
|
|
this._input().val(this.option("value"))
|
|
},
|
|
_renderProps: function() {
|
|
this._input().prop({
|
|
placeholder: this.option("placeholder"),
|
|
readOnly: this._readOnlyPropValue(),
|
|
disabled: this.option("disabled")
|
|
})
|
|
},
|
|
_readOnlyPropValue: function() {
|
|
return this.option("readOnly")
|
|
},
|
|
_renderPlaceholder: function() {
|
|
if (nativePlaceholderSupport)
|
|
return;
|
|
var self = this,
|
|
placeholderText = self.option("placeholder"),
|
|
$input = self._input(),
|
|
$placeholder = $('<div />').addClass(EDITBOX_PLACEHOLDER_CLASS).addClass("dx-hide").attr("data-dx_placeholder", placeholderText),
|
|
startEvent = events.addNamespace("dxpointerdown", this.NAME);
|
|
$placeholder.on(startEvent, function() {
|
|
$input.focus()
|
|
});
|
|
$input.wrap($placeholder).on("focus.dxEditBox focusin.dxEditBox", function() {
|
|
self._setStatePlaceholder.call(self, true)
|
|
}).on("blur.dxEditBox focusout.dxEditBox", function() {
|
|
self._setStatePlaceholder.call(self, false)
|
|
});
|
|
self._setStatePlaceholder()
|
|
},
|
|
_renderEvents: function() {
|
|
var self = this,
|
|
$input = self._input();
|
|
$.each(EVENTS_LIST, function(_, event) {
|
|
var eventName = events.addNamespace(event.toLowerCase(), self.NAME),
|
|
action = self._createActionByOption(event + "Action");
|
|
$input.off(eventName).on(eventName, function(e) {
|
|
action({jQueryEvent: e})
|
|
})
|
|
});
|
|
self._renderValueUpdateEvent()
|
|
},
|
|
_renderValueUpdateEvent: function() {
|
|
var valueUpdateEventName = events.addNamespace(this.option("valueUpdateEvent"), this.NAME);
|
|
this._input().off("." + this.NAME, this._handleValueChange).on(valueUpdateEventName, $.proxy(this._handleValueChange, this));
|
|
this._changeAction = this._createActionByOption("valueUpdateAction")
|
|
},
|
|
_setStatePlaceholder: function(state) {
|
|
if (nativePlaceholderSupport)
|
|
return;
|
|
var $input = this._input(),
|
|
$placeholder = $input.parent("." + EDITBOX_PLACEHOLDER_CLASS);
|
|
if (state === undefined)
|
|
if (!$input.val() && !$input.prop("disabled") && $input.prop("placeholder"))
|
|
state = false;
|
|
if ($input.val())
|
|
state = true;
|
|
$placeholder.toggleClass("dx-hide", state)
|
|
},
|
|
_handleValueChange: function(e) {
|
|
this._currentValueUpdateEvent = e;
|
|
this.option("value", this._input().val());
|
|
if (this._currentValueUpdateEvent)
|
|
this._dispatchChangeAction()
|
|
},
|
|
_renderEnterKeyAction: function() {
|
|
if (this.option("enterKeyAction")) {
|
|
this._enterKeyAction = this._createActionByOption("enterKeyAction");
|
|
this._input().on("keyup.enterKey.dxEditBox", $.proxy(this._onKeyDownHandler, this))
|
|
}
|
|
else {
|
|
this._input().off("keyup.enterKey.dxEditBox");
|
|
this._enterKeyAction = undefined
|
|
}
|
|
},
|
|
_onKeyDownHandler: function(e) {
|
|
if (e.which === 13)
|
|
this._enterKeyAction({jQueryEvent: e})
|
|
},
|
|
_toggleDisabledState: function() {
|
|
this.callBase.apply(this, arguments);
|
|
this._renderProps()
|
|
},
|
|
_dispatchChangeAction: function() {
|
|
this._changeAction({
|
|
actionValue: this.option("value"),
|
|
jQueryEvent: this._currentValueUpdateEvent
|
|
});
|
|
this._currentValueUpdateEvent = undefined
|
|
},
|
|
_updateValue: function() {
|
|
this._renderValue();
|
|
this._setStatePlaceholder();
|
|
this._dispatchChangeAction()
|
|
},
|
|
_optionChanged: function(optionName) {
|
|
if ($.inArray(optionName.replace("Action", ""), EVENTS_LIST) > -1) {
|
|
this._renderEvents();
|
|
return
|
|
}
|
|
switch (optionName) {
|
|
case"value":
|
|
this._updateValue();
|
|
break;
|
|
case"valueUpdateEvent":
|
|
case"valueUpdateAction":
|
|
this._renderValueUpdateEvent();
|
|
break;
|
|
case"readOnly":
|
|
this._renderProps();
|
|
break;
|
|
case"mode":
|
|
this._renderInputType();
|
|
break;
|
|
case"enterKeyAction":
|
|
this._renderEnterKeyAction();
|
|
break;
|
|
case"placeholder":
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_renderInputType: function() {
|
|
var input = this._input();
|
|
try {
|
|
input.prop("type", this.option("mode"))
|
|
}
|
|
catch(e) {
|
|
input.prop("type", "text")
|
|
}
|
|
},
|
|
focus: function() {
|
|
this._input().trigger("focus")
|
|
}
|
|
}));
|
|
ui.dxEditBox.__internals = {nativePlaceholderSupport: function(newState) {
|
|
if (arguments.length)
|
|
nativePlaceholderSupport = !!newState;
|
|
return nativePlaceholderSupport
|
|
}}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.textBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var TEXTBOX_CLASS = "dx-textbox";
|
|
var ignoreCode = [8, 9, 13, 33, 34, 35, 36, 37, 38, 39, 40, 46];
|
|
ui.registerComponent("dxTextBox", ui.dxEditBox.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
mode: "text",
|
|
maxLength: null
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(TEXTBOX_CLASS);
|
|
if (this._isAndroid())
|
|
this._input().on(events.addNamespace("keydown", this.NAME), $.proxy(this._onKeyDownAndroidHandler, this)).on(events.addNamespace("change", this.NAME), $.proxy(this._onChangeAndroidHandler, this))
|
|
},
|
|
_renderProps: function() {
|
|
this.callBase();
|
|
if (this._isAndroid())
|
|
return;
|
|
var maxLength = this.option("maxLength");
|
|
if (maxLength > 0)
|
|
this._input().prop("maxLength", maxLength)
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"maxLength":
|
|
this._renderProps();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_onKeyDownAndroidHandler: function(e) {
|
|
var maxLength = this.option("maxLength");
|
|
if (maxLength) {
|
|
var $input = $(e.target),
|
|
code = e.keyCode;
|
|
this._cutOffExtraChar($input);
|
|
return $input.val().length < maxLength || $.inArray(code, ignoreCode) !== -1 || window.getSelection().toString() !== ""
|
|
}
|
|
else
|
|
return true
|
|
},
|
|
_onChangeAndroidHandler: function(e) {
|
|
var $input = $(e.target);
|
|
if (this.option("maxLength"))
|
|
this._cutOffExtraChar($input)
|
|
},
|
|
_cutOffExtraChar: function($input) {
|
|
var maxLength = this.option("maxLength"),
|
|
textInput = $input.val();
|
|
if (textInput.length > maxLength)
|
|
$input.val(textInput.substr(0, maxLength))
|
|
},
|
|
_isAndroid: function() {
|
|
var ua = window.navigator.userAgent,
|
|
version = DX.devices.real.version.join(".");
|
|
return DX.devices.real.platform === "android" && version && /^(2\.|4\.0|4\.1)/.test(version) && ua.indexOf("Chrome") === -1
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.textArea.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var TEXTAREA_CLASS = "dx-textarea",
|
|
EDITBOX_INPUT_CLASS = "dx-editbox-input",
|
|
EDITBOX_BORDER_CLASS = "dx-editbox-border";
|
|
ui.registerComponent("dxTextArea", ui.dxTextBox.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(TEXTAREA_CLASS)
|
|
},
|
|
_renderInput: function() {
|
|
this._element().append($("<textarea>").addClass(EDITBOX_INPUT_CLASS)).append($("<div />").addClass(EDITBOX_BORDER_CLASS));
|
|
this._renderScrollHandler()
|
|
},
|
|
_renderScrollHandler: function() {
|
|
var $input = this._input(),
|
|
eventY = 0;
|
|
$input.on(events.addNamespace("dxpointerdown", this.NAME), function(e) {
|
|
eventY = events.eventData(e).y
|
|
});
|
|
$input.on(events.addNamespace("dxpointermove", this.NAME), function(e) {
|
|
var scrollTopPos = $input.scrollTop(),
|
|
scrollBottomPos = $input.prop("scrollHeight") - $input.prop("clientHeight") - scrollTopPos;
|
|
if (scrollTopPos === 0 && scrollBottomPos === 0)
|
|
return;
|
|
var currentEventY = events.eventData(e).y;
|
|
var isScrollFromTop = scrollTopPos === 0 && eventY >= currentEventY;
|
|
var isScrollFromBottom = scrollBottomPos === 0 && eventY <= currentEventY;
|
|
var isScrollFromMiddle = scrollTopPos > 0 && scrollBottomPos > 0;
|
|
if (isScrollFromTop || isScrollFromBottom || isScrollFromMiddle)
|
|
e.originalEvent.isScrollingEvent = true;
|
|
eventY = currentEventY
|
|
})
|
|
},
|
|
_renderInputType: $.noop,
|
|
_renderDimensions: function() {
|
|
this.callBase();
|
|
var width = this.option("width"),
|
|
height = this.option("height");
|
|
this._input().width(width);
|
|
this._input().height(height)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.numberBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
math = Math,
|
|
events = ui.events;
|
|
ui.registerComponent("dxNumberBox", ui.dxEditBox.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
value: 0,
|
|
min: -Number.MAX_VALUE,
|
|
max: Number.MAX_VALUE,
|
|
mode: "number"
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-numberbox");
|
|
this._setInputInvalidHandler()
|
|
},
|
|
_renderProps: function() {
|
|
this.callBase();
|
|
this._input().prop({
|
|
min: this.option("min"),
|
|
max: this.option("max")
|
|
})
|
|
},
|
|
_setInputInvalidHandler: function() {
|
|
var self = this,
|
|
valueUpdateEvent = events.addNamespace(this.option("valueUpdateEvent"), this.NAME);
|
|
this._input().on(valueUpdateEvent, function() {
|
|
var validatingInput = self._input()[0];
|
|
if (typeof validatingInput.checkValidity === "function")
|
|
validatingInput.checkValidity()
|
|
}).focusout($.proxy(this._trimInputValue, this)).on("invalid", $.proxy(this._inputInvalidHandler, this))
|
|
},
|
|
_renderValue: function() {
|
|
var value = this.option("value") ? this.option("value").toString() : this.option("value");
|
|
if (this._input().val() !== value)
|
|
this._input().val(this.option("value"))
|
|
},
|
|
_trimInputValue: function() {
|
|
var $input = this._input(),
|
|
value = $.trim($input.val());
|
|
if (value[value.length - 1] === ".")
|
|
value = value.slice(0, -1);
|
|
this._forceRefreshInputValue(value)
|
|
},
|
|
_inputInvalidHandler: function() {
|
|
var $input = this._input(),
|
|
value = $input.val();
|
|
if (this._oldValue) {
|
|
this.option("value", this._oldValue);
|
|
$input.val(this._oldValue);
|
|
this._oldValue = null;
|
|
return
|
|
}
|
|
if (value && !/,/.test(value))
|
|
return;
|
|
this.option("value", "");
|
|
$input.val("")
|
|
},
|
|
_handleValueChange: function() {
|
|
var $input = this._input(),
|
|
value = $.trim($input.val());
|
|
value = value.replace(",", ".");
|
|
if (!this._validateValue(value))
|
|
return;
|
|
value = this._parseValue(value);
|
|
if (!value && value !== 0)
|
|
return;
|
|
this.option("value", value);
|
|
if ($input.val() != value)
|
|
$input.val(value)
|
|
},
|
|
_forceRefreshInputValue: function(value) {
|
|
var $input = this._input();
|
|
$input.val("").val(value)
|
|
},
|
|
_validateValue: function(value) {
|
|
var valueUpdateEvent = events.addNamespace(this.option("valueUpdateEvent"), this.NAME),
|
|
$input = this._input();
|
|
this._oldValue = null;
|
|
this._hasCommaChar = null;
|
|
if (!value) {
|
|
this._oldValue = this.option("value");
|
|
this.option("value", "");
|
|
if (this._hasCommaChar)
|
|
$input.trigger("invalid");
|
|
return false
|
|
}
|
|
if (value[value.length - 1] === ".")
|
|
return false;
|
|
return true
|
|
},
|
|
_calcPointsCount: function(string) {
|
|
var count = 0,
|
|
position = -1;
|
|
while ((position = $.inArray(".", string.split(""), position + 1)) > -1)
|
|
count++;
|
|
return count
|
|
},
|
|
_parseValue: function(value) {
|
|
var number = Globalize.parseFloat(value, 10, Globalize.cultures["default"].language);
|
|
if (isNaN(number)) {
|
|
this._input().val(this.option("value"));
|
|
return undefined
|
|
}
|
|
number = math.max(number, this.option("min"));
|
|
number = math.min(number, this.option("max"));
|
|
return number
|
|
},
|
|
_optionChanged: function(name) {
|
|
if (name === "min" || name === "max")
|
|
this._renderProps(arguments);
|
|
else
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.slider.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
translator = DX.translator,
|
|
utils = DX.utils;
|
|
var SLIDER_CLASS = "dx-slider",
|
|
SLIDER_WRAPPER_CLASS = SLIDER_CLASS + "-wrapper",
|
|
SLIDER_HANDLE_CLASS = SLIDER_CLASS + "-handle",
|
|
SLIDER_HANDLE_SELECTOR = "." + SLIDER_HANDLE_CLASS,
|
|
SLIDER_BAR_CLASS = SLIDER_CLASS + "-bar",
|
|
SLIDER_RANGE_CLASS = SLIDER_CLASS + "-range";
|
|
ui.registerComponent("dxSlider", ui.Widget.inherit({
|
|
_activeStateUnit: SLIDER_HANDLE_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
min: 0,
|
|
max: 100,
|
|
step: 1,
|
|
value: 50
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
utils.windowResizeCallbacks.add(this._refreshHandler = $.proxy(this._refresh, this))
|
|
},
|
|
_dispose: function() {
|
|
this.callBase();
|
|
utils.windowResizeCallbacks.remove(this._refreshHandler)
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._$wrapper = $("<div />").addClass(SLIDER_WRAPPER_CLASS);
|
|
this._$bar = $("<div />").addClass(SLIDER_BAR_CLASS).appendTo(this._$wrapper);
|
|
this._$selectedRange = $("<div />").addClass(SLIDER_RANGE_CLASS).appendTo(this._$bar);
|
|
this._$handle = $("<div />").addClass(SLIDER_HANDLE_CLASS).appendTo(this._$bar);
|
|
this._element().addClass(SLIDER_CLASS).append(this._$wrapper);
|
|
this._$wrapper.dxSwipeable({
|
|
elastic: false,
|
|
startAction: $.proxy(this._handleSwipeStart, this),
|
|
updateAction: $.proxy(this._handleSwipeUpdate, this),
|
|
cancelAction: $.proxy(this._handleSwipeCancel, this),
|
|
itemWidthFunc: $.proxy(this._itemWidthFunc, this)
|
|
});
|
|
this._renderValue();
|
|
this._renderStartHandler()
|
|
},
|
|
_renderStartHandler: function() {
|
|
var eventName = events.addNamespace("dxpointerdown", this.NAME),
|
|
startAction = this._createAction($.proxy(this._handleStart, this), {excludeValidators: ["gesture"]});
|
|
this._element().off(eventName).on(eventName, function(e) {
|
|
startAction({jQueryEvent: e})
|
|
})
|
|
},
|
|
_itemWidthFunc: function() {
|
|
return this._element().width()
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
this._startOffset = this._currentRatio;
|
|
e.jQueryEvent.maxLeftOffset = this._startOffset;
|
|
e.jQueryEvent.maxRightOffset = 1 - this._startOffset
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
this._handleValueChange(this._startOffset + e.jQueryEvent.offset)
|
|
},
|
|
_handleSwipeCancel: function(e) {
|
|
this._feedbackOff()
|
|
},
|
|
_handleValueChange: function(ratio) {
|
|
var min = this.option("min"),
|
|
max = this.option("max"),
|
|
step = this.option("step"),
|
|
newChange = ratio * (max - min),
|
|
newValue = min + newChange;
|
|
if (!step || isNaN(step))
|
|
step = 1;
|
|
step = parseFloat(step.toFixed(5));
|
|
if (step === 0)
|
|
step = 0.00001;
|
|
if (step < 0)
|
|
return;
|
|
if (newValue === max || newValue === min)
|
|
this.option("value", newValue);
|
|
else {
|
|
var stepChunks = (step + "").split('.'),
|
|
exponent = stepChunks.length > 1 ? stepChunks[1].length : exponent;
|
|
newValue = Number((Math.round(newChange / step) * step + min).toFixed(exponent));
|
|
this.option("value", this._fitValue(newValue))
|
|
}
|
|
},
|
|
_fitValue: function(value) {
|
|
value = Math.min(value, this.option("max"));
|
|
value = Math.max(value, this.option("min"));
|
|
return value
|
|
},
|
|
_handleStart: function(args) {
|
|
var e = args.jQueryEvent;
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
this._currentRatio = (ui.events.eventData(e).x - this._$bar.offset().left) / this._$bar.width();
|
|
this._handleValueChange(this._currentRatio)
|
|
},
|
|
_renderValue: function() {
|
|
var val = this.option("value"),
|
|
min = this.option("min"),
|
|
max = this.option("max");
|
|
if (min > max)
|
|
return;
|
|
if (val < min) {
|
|
this.option("value", min);
|
|
this._currentRatio = 0;
|
|
return
|
|
}
|
|
if (val > max) {
|
|
this.option("value", max);
|
|
this._currentRatio = 1;
|
|
return
|
|
}
|
|
var handleWidth = this._$handle.outerWidth(),
|
|
barWidth = this._$bar.width(),
|
|
ratio = min === max ? 0 : (val - min) / (max - min);
|
|
this._$selectedRange.width(ratio * barWidth);
|
|
translator.move(this._$handle, {left: ratio * barWidth - handleWidth / 2});
|
|
this._currentRatio = ratio
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"min":
|
|
case"max":
|
|
case"step":
|
|
case"value":
|
|
this._renderValue();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_feedbackOff: function(isGestureStart) {
|
|
if (isGestureStart)
|
|
return;
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.rangeSlider.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
translator = DX.translator;
|
|
var SLIDER_HANDLE_CLASS = "dx-slider-handle";
|
|
ui.registerComponent("dxRangeSlider", ui.dxSlider.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
start: 40,
|
|
end: 60,
|
|
value: 50
|
|
})
|
|
},
|
|
_render: function() {
|
|
this._$handleRight = $("<div />").addClass(SLIDER_HANDLE_CLASS);
|
|
this.callBase();
|
|
this._$handleRight.appendTo(this._$bar)
|
|
},
|
|
_handleStart: function(args) {
|
|
var e = args.jQueryEvent;
|
|
var eventOffsetX = events.eventData(e).x - this._$bar.offset().left,
|
|
leftHandleX = this._$handle.position().left,
|
|
rightHandleX = this._$handleRight.position().left;
|
|
this._$handlersDistance = Math.abs(leftHandleX - rightHandleX);
|
|
this._capturedHandle = (leftHandleX + rightHandleX) / 2 > eventOffsetX ? this._$handle : this._$handleRight;
|
|
this.callBase(args)
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
if (Math.abs(this.option("start") - this.option("end")) === 0 && this._$handlersDistance < this._$handle.outerWidth()) {
|
|
this._feedbackOff(true);
|
|
this._capturedHandle = e.jQueryEvent.offset <= 0 ? this._$handle : this._$handleRight;
|
|
this._feedbackOn(this._capturedHandle, true)
|
|
}
|
|
this.callBase(e)
|
|
},
|
|
_handleValueChange: function(ratio) {
|
|
this.callBase(ratio);
|
|
var option = this._capturedHandle === this._$handle ? "start" : "end",
|
|
start = this.option("start"),
|
|
end = this.option("end"),
|
|
newValue = this.option("value"),
|
|
max = this.option("max"),
|
|
min = this.option("min");
|
|
if (start > max) {
|
|
start = max;
|
|
this.option("start", max)
|
|
}
|
|
if (start < min) {
|
|
start = min;
|
|
this.option("start", min)
|
|
}
|
|
if (end > max) {
|
|
end = max;
|
|
this.option("end", max)
|
|
}
|
|
if (newValue > end && option === "start")
|
|
newValue = end;
|
|
if (newValue < start && option === "end")
|
|
newValue = start;
|
|
this.option(option, newValue)
|
|
},
|
|
_renderValue: function() {
|
|
var valStart = this.option("start"),
|
|
valEnd = this.option("end"),
|
|
min = this.option("min"),
|
|
max = this.option("max");
|
|
if (valStart < min)
|
|
valStart = min;
|
|
if (valStart > max)
|
|
valStart = max;
|
|
if (valEnd > max)
|
|
valEnd = max;
|
|
if (valEnd < valStart)
|
|
valEnd = valStart;
|
|
var handleWidth = this._$handle.outerWidth(),
|
|
barWidth = this._$bar.width(),
|
|
ratio1 = max === min ? 0 : (valStart - min) / (max - min),
|
|
ratio2 = max === min ? 0 : (valEnd - min) / (max - min);
|
|
this._$selectedRange.width((ratio2 - ratio1) * barWidth);
|
|
translator.move(this._$selectedRange, {left: ratio1 * barWidth});
|
|
translator.move(this._$handle, {left: ratio1 * barWidth - handleWidth / 2});
|
|
translator.move(this._$handleRight, {left: ratio2 * barWidth - handleWidth / 2})
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"start":
|
|
case"end":
|
|
this._renderValue();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.radioGroup.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var RADIO_GROUP_CLASS = "dx-radio-group",
|
|
RADIO_GROUP_VERTICAL_CLASS = "dx-radio-group-vertical",
|
|
RADIO_GROUP_HORIZONTAL_CLASS = "dx-radio-group-horizontal",
|
|
RADIO_BUTTON_CLASS = "dx-radio-button",
|
|
RADIO_BUTTON_SELECTOR = "." + RADIO_BUTTON_CLASS,
|
|
RADIO_BUTTON_VALUE_CLASS = "dx-radio-button-value",
|
|
RADIO_VALUE_CONTAINER_CLASS = "dx-radio-value-container",
|
|
RADIO_BUTTON_ACTIVE_STATE = "dx-state-active",
|
|
RADIO_BUTTON_DATA_KEY = "dxRadioButtonData",
|
|
RADIO_FEEDBACK_HIDE_TIMEOUT = 100;
|
|
ui.registerComponent("dxRadioGroup", ui.SelectableCollectionWidget.inherit({
|
|
_activeStateUnit: RADIO_BUTTON_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
layout: "vertical",
|
|
value: undefined,
|
|
valueExpr: null,
|
|
hoverStateEnabled: true
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return RADIO_BUTTON_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return RADIO_BUTTON_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._element()
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
if (!this._dataSource)
|
|
this._itemsToDataSource();
|
|
this._feedbackHideTimeout = RADIO_FEEDBACK_HIDE_TIMEOUT
|
|
},
|
|
_itemsToDataSource: function() {
|
|
this._dataSource = new DevExpress.data.DataSource(this.option("items"))
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(RADIO_GROUP_CLASS);
|
|
this._compileValueGetter();
|
|
this.callBase();
|
|
this._renderLayout();
|
|
this._renderValue()
|
|
},
|
|
_compileValueGetter: function() {
|
|
this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
|
|
},
|
|
_valueGetterExpr: function() {
|
|
return this.option("valueExpr") || this._dataSource && this._dataSource._store._key || "this"
|
|
},
|
|
_renderLayout: function() {
|
|
var layout = this.option("layout");
|
|
this._element().toggleClass(RADIO_GROUP_VERTICAL_CLASS, layout === "vertical");
|
|
this._element().toggleClass(RADIO_GROUP_HORIZONTAL_CLASS, layout === "horizontal")
|
|
},
|
|
_renderValue: function() {
|
|
this.option("value") ? this._setIndexByValue() : this._setValueByIndex()
|
|
},
|
|
_setIndexByValue: function(value) {
|
|
var self = this;
|
|
value = value === undefined ? self.option("value") : value;
|
|
self._searchValue(value).done(function(item) {
|
|
if (self._dataSource.isLoaded())
|
|
self._setIndexByItem(item);
|
|
else
|
|
self._dataSource.load().done(function() {
|
|
self._setIndexByItem(item)
|
|
})
|
|
})
|
|
},
|
|
_setIndexByItem: function(item) {
|
|
this.option("selectedIndex", $.inArray(item, this._dataSource.items()))
|
|
},
|
|
_searchValue: function(value) {
|
|
var self = this,
|
|
store = self._dataSource.store(),
|
|
valueExpr = self._valueGetterExpr();
|
|
var deffered = $.Deferred();
|
|
if (valueExpr === store.key() || store instanceof DX.data.CustomStore)
|
|
store.byKey(value).done(function(result) {
|
|
deffered.resolveWith(self, [result])
|
|
});
|
|
else
|
|
store.load({filter: [valueExpr, value]}).done(function(result) {
|
|
deffered.resolveWith(self, result)
|
|
});
|
|
return deffered.promise()
|
|
},
|
|
_setValueByIndex: function() {
|
|
var index = this.option("selectedIndex"),
|
|
$items = this._itemElements();
|
|
if (index < 0 || index >= $items.length)
|
|
return undefined;
|
|
var itemElement = this._selectedItemElement(index),
|
|
itemData = this._getItemData(itemElement);
|
|
this.option("value", this._getItemValue(itemData))
|
|
},
|
|
_getItemValue: function(item) {
|
|
return this._valueGetter(item) || item.text
|
|
},
|
|
_renderSelectedIndex: function(index) {
|
|
var $items = this._itemElements();
|
|
if (index >= 0 && index < $items.length) {
|
|
var $selectedItem = $items.eq(index),
|
|
$radioGroup = $selectedItem.closest("." + RADIO_GROUP_CLASS);
|
|
$radioGroup.find(RADIO_BUTTON_SELECTOR).removeClass("checked");
|
|
$selectedItem.closest(RADIO_BUTTON_SELECTOR).addClass("checked")
|
|
}
|
|
},
|
|
_createItemByRenderer: function(itemRenderer, renderArgs) {
|
|
var $itemElement = this.callBase.apply(this, arguments);
|
|
this._renderInput($itemElement, renderArgs.item);
|
|
return $itemElement
|
|
},
|
|
_createItemByTemplate: function(itemTemplate, renderArgs) {
|
|
var $itemElement = this.callBase.apply(this, arguments);
|
|
this._renderInput($itemElement, renderArgs.item);
|
|
return $itemElement
|
|
},
|
|
_renderInput: function($element, item) {
|
|
if (item.html)
|
|
return;
|
|
var $radio = $("<div>").addClass(RADIO_BUTTON_VALUE_CLASS),
|
|
$radioContainer = $("<div>").append($radio).addClass(RADIO_VALUE_CONTAINER_CLASS);
|
|
$element.prepend($radioContainer)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"value":
|
|
this._setIndexByValue(value);
|
|
break;
|
|
case"selectedIndex":
|
|
this.callBase.apply(this, arguments);
|
|
this._setValueByIndex();
|
|
break;
|
|
case"layout":
|
|
this._renderLayout();
|
|
break;
|
|
case"valueExpr":
|
|
this._compileValueGetter();
|
|
this._setValueByIndex();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.tabs.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
TABS_CLASS = "dx-tabs",
|
|
TABS_WRAPPER_CLASS = "dx-indent-wrapper",
|
|
TABS_ITEM_CLASS = "dx-tab",
|
|
TABS_ITEM_SELECTOR = ".dx-tab",
|
|
TABS_ITEM_SELECTED_CLASS = "dx-tab-selected",
|
|
TABS_ITEM_TEXT_CLASS = "dx-tab-text",
|
|
ICON_CLASS = "dx-icon",
|
|
TABS_ITEM_DATA_KEY = "dxTabData",
|
|
FEEDBACK_HIDE_TIMEOUT = 100;
|
|
ui.registerComponent("dxTabs", ui.SelectableCollectionWidget.inherit({
|
|
_activeStateUnit: TABS_ITEM_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._feedbackHideTimeout = FEEDBACK_HIDE_TIMEOUT
|
|
},
|
|
_itemClass: function() {
|
|
return TABS_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return TABS_ITEM_DATA_KEY
|
|
},
|
|
_itemRenderDefault: function(item, index, itemElement) {
|
|
this.callBase(item, index, itemElement);
|
|
if (item.html)
|
|
return;
|
|
var text = item.text,
|
|
icon = item.icon,
|
|
iconSrc = item.iconSrc,
|
|
iconElement;
|
|
if (text)
|
|
itemElement.wrapInner($("<span />").addClass(TABS_ITEM_TEXT_CLASS));
|
|
if (icon)
|
|
iconElement = $("<span />").addClass(ICON_CLASS + "-" + icon);
|
|
else if (iconSrc)
|
|
iconElement = $("<img />").attr("src", iconSrc);
|
|
if (iconElement)
|
|
iconElement.addClass(ICON_CLASS).prependTo(itemElement)
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(TABS_CLASS);
|
|
this._renderWrapper()
|
|
},
|
|
_renderWrapper: function() {
|
|
this._element().wrapInner($("<div />").addClass(TABS_WRAPPER_CLASS))
|
|
},
|
|
_renderSelectedIndex: function(current, previous) {
|
|
var $tabs = this._itemElements();
|
|
if (previous >= 0)
|
|
$tabs.eq(previous).removeClass(TABS_ITEM_SELECTED_CLASS);
|
|
if (current >= 0)
|
|
$tabs.eq(current).addClass(TABS_ITEM_SELECTED_CLASS)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.navBar.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
NAVBAR_CLASS = "dx-navbar",
|
|
NABAR_ITEM_CLASS = "dx-nav-item",
|
|
NAVBAR_ITEM_CONTENT_CLASS = "dx-nav-item-content";
|
|
ui.registerComponent("dxNavBar", ui.dxTabs.inherit({
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(NAVBAR_CLASS)
|
|
},
|
|
_renderItem: function(index, item) {
|
|
var itemElement = this.callBase(index, item);
|
|
return itemElement.addClass(NABAR_ITEM_CLASS).wrapInner($("<div />").addClass(NAVBAR_ITEM_CONTENT_CLASS))
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.pivotTabs.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
fx = DX.fx,
|
|
translator = DX.translator,
|
|
events = ui.events;
|
|
var PIVOT_TABS_CLASS = "dx-pivottabs",
|
|
PIVOT_TAB_CLASS = "dx-pivottabs-tab",
|
|
PIVOT_TAB_SELECTED_CLASS = "dx-pivottabs-tab-selected",
|
|
PIVOT_GHOST_TAB_CLASS = "dx-pivottabs-ghosttab",
|
|
PIVOT_TAB_DATA_KEY = "dxPivotTabData",
|
|
PIVOT_TAB_MOVE_DURATION = 200,
|
|
PIVOT_TAB_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)";
|
|
var animation = {
|
|
moveTo: function($tab, position, completeAction) {
|
|
return fx.animate($tab, {
|
|
type: "slide",
|
|
to: {left: position},
|
|
duration: PIVOT_TAB_MOVE_DURATION,
|
|
easing: PIVOT_TAB_MOVE_EASING,
|
|
complete: completeAction
|
|
})
|
|
},
|
|
slideAppear: function($tab, position) {
|
|
return fx.animate($tab, {
|
|
type: "slide",
|
|
to: {
|
|
left: position,
|
|
opacity: 1
|
|
},
|
|
duration: PIVOT_TAB_MOVE_DURATION,
|
|
easing: PIVOT_TAB_MOVE_EASING
|
|
})
|
|
},
|
|
slideDisappear: function($tab, position) {
|
|
return fx.animate($tab, {
|
|
type: "slide",
|
|
to: {
|
|
left: position,
|
|
opacity: 0
|
|
},
|
|
duration: PIVOT_TAB_MOVE_DURATION,
|
|
easing: PIVOT_TAB_MOVE_EASING
|
|
})
|
|
}
|
|
};
|
|
var completeAnimation = function(elements) {
|
|
if (!elements)
|
|
return;
|
|
$.each(elements, function(_, element) {
|
|
fx.stop(element, true)
|
|
})
|
|
};
|
|
ui.registerComponent("dxPivotTabs", ui.SelectableCollectionWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
selectedIndex: 0,
|
|
prepareAction: null,
|
|
updatePositionAction: null,
|
|
rollbackAction: null,
|
|
completeAction: null
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return PIVOT_TAB_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return PIVOT_TAB_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._element()
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initGhostTab();
|
|
this._initSwipeHandlers();
|
|
this._initActions()
|
|
},
|
|
_initGhostTab: function() {
|
|
this._$ghostTab = $("<div>").addClass(PIVOT_GHOST_TAB_CLASS)
|
|
},
|
|
_initActions: function() {
|
|
var excludeValidators = {excludeValidators: ["gesture"]};
|
|
this._updatePositionAction = this._createActionByOption("updatePositionAction", excludeValidators);
|
|
this._rollbackAction = this._createActionByOption("rollbackAction", excludeValidators);
|
|
this._completeAction = this._createActionByOption("completeAction", excludeValidators);
|
|
this._prepareAction = this._createActionByOption("prepareAction", excludeValidators)
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(PIVOT_TABS_CLASS);
|
|
this.callBase();
|
|
this._renderGhostTab()
|
|
},
|
|
_renderGhostTab: function() {
|
|
this._itemContainer().append(this._$ghostTab);
|
|
this._toggleGhostTab(false)
|
|
},
|
|
_toggleGhostTab: function(visible) {
|
|
var $ghostTab = this._$ghostTab;
|
|
if (visible) {
|
|
this._updateGhostTabContent();
|
|
$ghostTab.css("opacity", 1)
|
|
}
|
|
else
|
|
$ghostTab.css("opacity", 0)
|
|
},
|
|
_isGhostTabVisible: function() {
|
|
return this._$ghostTab.css("opacity") == 1
|
|
},
|
|
_updateGhostTabContent: function(prevIndex) {
|
|
prevIndex = prevIndex === undefined ? this._previousIndex() : prevIndex;
|
|
var $ghostTab = this._$ghostTab,
|
|
$items = this._itemElements();
|
|
$ghostTab.html($items.eq(prevIndex).html())
|
|
},
|
|
_updateTabsPositions: function(offset) {
|
|
var $tabs = this._allTabElements(),
|
|
offset = this._applyOffsetBoundaries(offset),
|
|
isRightSwipeHandled = offset > 0,
|
|
tabPositions = this._calculateTabPositions(isRightSwipeHandled ? "replace" : "append");
|
|
this._moveTabs(tabPositions, offset);
|
|
this._toggleGhostTab(isRightSwipeHandled)
|
|
},
|
|
_moveTabs: function(positions, offset) {
|
|
offset = offset || 0;
|
|
var $tabs = this._allTabElements();
|
|
$tabs.each(function(index) {
|
|
translator.move($(this), {left: positions[index] + offset})
|
|
})
|
|
},
|
|
_applyOffsetBoundaries: function(offset) {
|
|
offset = offset || 0;
|
|
var maxOffset = offset > 0 ? this._maxRightOffset : this._maxLeftOffset;
|
|
return offset * maxOffset
|
|
},
|
|
_animateRollback: function() {
|
|
var self = this,
|
|
$tabs = this._itemElements(),
|
|
positions = this._calculateTabPositions("prepend");
|
|
if (this._isGhostTabVisible()) {
|
|
this._swapGhostWithTab($tabs.eq(this._previousIndex()));
|
|
animation.moveTo(this._$ghostTab, positions[this._indexBoundary()], function() {
|
|
self._toggleGhostTab(false)
|
|
})
|
|
}
|
|
$tabs.each(function(index) {
|
|
animation.moveTo($(this), positions[index])
|
|
})
|
|
},
|
|
_animateComplete: function(newIndex, currentIndex) {
|
|
var self = this,
|
|
$tabs = this._itemElements(),
|
|
isRightSwipeHandled = this._isGhostTabVisible();
|
|
$tabs.eq(currentIndex).removeClass(PIVOT_TAB_SELECTED_CLASS);
|
|
var animations = isRightSwipeHandled ? this._animateIndexDecreasing(newIndex) : this._animateIndexIncreasing(newIndex);
|
|
$tabs.eq(newIndex).addClass(PIVOT_TAB_SELECTED_CLASS);
|
|
animations.done(function() {
|
|
self._indexChangeOnAnimation = true;
|
|
self.option("selectedIndex", newIndex);
|
|
self._indexChangeOnAnimation = false
|
|
})
|
|
},
|
|
_animateIndexDecreasing: function(newIndex) {
|
|
var $tabs = this._itemElements(),
|
|
positions = this._calculateTabPositions("append", newIndex),
|
|
animations = [];
|
|
$tabs.each(function(index) {
|
|
animations.push(animation.moveTo($(this), positions[index]))
|
|
});
|
|
animations.push(animation.slideDisappear(this._$ghostTab, positions[this._indexBoundary()]));
|
|
return $.when.apply($, animations)
|
|
},
|
|
_animateIndexIncreasing: function(newIndex) {
|
|
var self = this,
|
|
$tabs = this._itemElements(),
|
|
positions = this._calculateTabPositions("prepend", newIndex),
|
|
previousIndex = this._previousIndex(newIndex),
|
|
isLeftSwipeHandled = translator.locate($tabs.eq(previousIndex)).left < 0,
|
|
animations = [];
|
|
if (!isLeftSwipeHandled)
|
|
this._moveTabs(this._calculateTabPositions("append", previousIndex));
|
|
this._updateGhostTabContent(previousIndex);
|
|
this._swapGhostWithTab($tabs.eq(previousIndex));
|
|
$tabs.each(function(index) {
|
|
var $tab = $(this),
|
|
newPosition = positions[index];
|
|
animations.push(index === previousIndex ? animation.slideAppear($tab, newPosition) : animation.moveTo($tab, newPosition))
|
|
});
|
|
animations.push(animation.moveTo(this._$ghostTab, positions[this._indexBoundary()], function() {
|
|
self._toggleGhostTab(false)
|
|
}));
|
|
return $.when.apply($, animations)
|
|
},
|
|
_swapGhostWithTab: function($tab) {
|
|
var $ghostTab = this._$ghostTab,
|
|
lastTabPosition = translator.locate($tab).left,
|
|
lastTabOpacity = $tab.css("opacity");
|
|
translator.move($tab, {left: translator.locate($ghostTab).left});
|
|
$tab.css("opacity", $ghostTab.css("opacity"));
|
|
translator.move($ghostTab, {left: lastTabPosition});
|
|
$ghostTab.css("opacity", lastTabOpacity)
|
|
},
|
|
_calculateTabPositions: function(ghostPosition, index) {
|
|
index = index === undefined ? this.option("selectedIndex") : index;
|
|
var mark = index + ghostPosition;
|
|
if (this._calculetedPositionsMark !== mark) {
|
|
this._calculetedPositions = this._calculateTabPositionsImpl(index, ghostPosition);
|
|
this._calculetedPositionsMark = mark
|
|
}
|
|
return this._calculetedPositions
|
|
},
|
|
_calculateTabPositionsImpl: function(currentIndex, ghostPosition) {
|
|
var prevIndex = this._normalizeIndex(currentIndex - 1),
|
|
$tabs = this._itemElements(),
|
|
widths = [],
|
|
nextPosition = 0,
|
|
positions = [];
|
|
$tabs.each(function() {
|
|
widths.push($(this).outerWidth())
|
|
});
|
|
var calculateTabPosition = function(currentIndex, width) {
|
|
positions.splice(currentIndex, 0, nextPosition);
|
|
nextPosition += width
|
|
};
|
|
$.each(widths.slice(currentIndex), calculateTabPosition);
|
|
$.each(widths.slice(0, currentIndex), calculateTabPosition);
|
|
switch (ghostPosition) {
|
|
case"replace":
|
|
var lastTabPosition = positions[prevIndex];
|
|
positions.splice(prevIndex, 1, -widths[prevIndex]);
|
|
positions.push(lastTabPosition);
|
|
break;
|
|
case"prepend":
|
|
positions.push(-widths[prevIndex]);
|
|
break;
|
|
case"append":
|
|
positions.push(nextPosition);
|
|
break
|
|
}
|
|
return positions
|
|
},
|
|
_allTabElements: function() {
|
|
return this._itemContainer().find("." + PIVOT_TAB_CLASS + ", ." + PIVOT_GHOST_TAB_CLASS)
|
|
},
|
|
_initSwipeHandlers: function() {
|
|
this._element().on(events.addNamespace("dxswipestart", this.NAME), $.proxy(this._swipeStartHandler, this)).on(events.addNamespace("dxswipe", this.NAME), $.proxy(this._swipeUpdateHandler, this)).on(events.addNamespace("dxswipeend", this.NAME), $.proxy(this._swipeEndHandler, this))
|
|
},
|
|
_swipeStartHandler: function(e) {
|
|
this._prepareAnimation();
|
|
this._prepareAction();
|
|
if (this.option("disabled") || this._indexBoundary() <= 1)
|
|
e.cancel = true
|
|
},
|
|
_prepareAnimation: function() {
|
|
this._stopAnimation()
|
|
},
|
|
_stopAnimation: function() {
|
|
completeAnimation(this._allTabElements())
|
|
},
|
|
_swipeUpdateHandler: function(e) {
|
|
var offset = e.offset;
|
|
this._updatePositionAction({offset: offset});
|
|
this._updateTabsPositions(offset)
|
|
},
|
|
_swipeEndHandler: function(e) {
|
|
var selectedIndex = this.option("selectedIndex"),
|
|
targetOffset = e.targetOffset;
|
|
if (targetOffset === 0) {
|
|
this._animateRollback();
|
|
this._rollbackAction()
|
|
}
|
|
else {
|
|
var newIndex = this._normalizeIndex(selectedIndex - targetOffset);
|
|
this._animateComplete(newIndex, selectedIndex);
|
|
this._completeAction({newIndex: newIndex})
|
|
}
|
|
},
|
|
_previousIndex: function(atIndex) {
|
|
atIndex = atIndex === undefined ? this.option("selectedIndex") : atIndex;
|
|
return this._normalizeIndex(atIndex - 1)
|
|
},
|
|
_normalizeIndex: function(index) {
|
|
var boundary = this._indexBoundary();
|
|
if (index < 0)
|
|
index = boundary + index;
|
|
if (index >= boundary)
|
|
index = index - boundary;
|
|
return index
|
|
},
|
|
_indexBoundary: function() {
|
|
return this.option("items").length
|
|
},
|
|
_onItemSelectAction: function(newIndex) {
|
|
this._prepareAnimation();
|
|
this._prepareAction();
|
|
this._animateComplete(newIndex, this.option("selectedIndex"));
|
|
this._completeAction({newIndex: newIndex})
|
|
},
|
|
_renderSelectedIndex: function(current, previous) {
|
|
var $tabs = this._itemElements();
|
|
this._calculateMaxOffsets(current);
|
|
if (!this._indexChangeOnAnimation) {
|
|
$tabs.eq(previous).removeClass(PIVOT_TAB_SELECTED_CLASS);
|
|
this._updateTabsPositions();
|
|
$tabs.eq(current).addClass(PIVOT_TAB_SELECTED_CLASS)
|
|
}
|
|
},
|
|
_calculateMaxOffsets: function(index) {
|
|
var $tabs = this._itemElements();
|
|
this._maxLeftOffset = $tabs.eq(index).outerWidth();
|
|
this._maxRightOffset = $tabs.eq(this._previousIndex(index)).outerWidth()
|
|
},
|
|
_itemRenderDefault: function(item, index, $itemElement) {
|
|
var $itemText = $("<span>").text(item.title);
|
|
$itemElement.html($itemText)
|
|
},
|
|
_optionChanged: function(name) {
|
|
if (name === "items")
|
|
delete this._calculetedPositionsMark;
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
prepare: function() {
|
|
this._prepareAnimation()
|
|
},
|
|
updatePosition: function(offset) {
|
|
this._updateTabsPositions(offset)
|
|
},
|
|
rollback: function() {
|
|
this._animateRollback()
|
|
},
|
|
complete: function(newIndex) {
|
|
this._animateComplete(newIndex, this.option("selectedIndex"))
|
|
}
|
|
}));
|
|
ui.dxPivotTabs.__internals = {animation: animation}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.pivot.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
fx = DX.fx,
|
|
translator = DX.translator;
|
|
var PIVOT_CLASS = "dx-pivot",
|
|
PIVOT_TABS_CONTAINER_CLASS = "dx-pivottabs-container",
|
|
PIVOT_ITEM_CONTAINER_CLASS = "dx-pivot-itemcontainer",
|
|
PIVOT_ITEM_WRAPPER_CLASS = "dx-pivot-itemwrapper",
|
|
PIVOT_ITEM_CLASS = "dx-pivot-item",
|
|
PIVOT_ITEM_HIDDEN_CLASS = "dx-pivot-item-hidden",
|
|
PIVOT_ITEM_DATA_KEY = "dxPivotItemData",
|
|
PIVOT_RETURN_BACK_DURATION = 200,
|
|
PIVOT_SLIDE_AWAY_DURATION = 50,
|
|
PIVOT_SLIDE_BACK_DURATION = 250,
|
|
PIVOT_SLIDE_BACK_EASING = "cubic-bezier(.10, 1, 0, 1)";
|
|
var animation = {
|
|
returnBack: function($element) {
|
|
fx.animate($element, {
|
|
type: "slide",
|
|
to: {left: 0},
|
|
duration: PIVOT_RETURN_BACK_DURATION
|
|
})
|
|
},
|
|
slideAway: function($element, position, completeAction) {
|
|
fx.animate($element, {
|
|
type: "slide",
|
|
to: {left: position},
|
|
duration: PIVOT_SLIDE_AWAY_DURATION,
|
|
complete: completeAction
|
|
})
|
|
},
|
|
slideBack: function($element) {
|
|
fx.animate($element, {
|
|
type: "slide",
|
|
to: {left: 0},
|
|
easing: PIVOT_SLIDE_BACK_EASING,
|
|
duration: PIVOT_SLIDE_BACK_DURATION
|
|
})
|
|
}
|
|
};
|
|
var completeAnimation = function(element) {
|
|
fx.stop(element, true)
|
|
};
|
|
ui.registerComponent("dxPivot", ui.SelectableCollectionWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {selectedIndex: 0})
|
|
},
|
|
_itemClass: function() {
|
|
return PIVOT_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return PIVOT_ITEM_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$itemWrapper
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initTabs();
|
|
this._initItemContainer();
|
|
this._clearItemsCache();
|
|
this._initSwipeHandlers()
|
|
},
|
|
_initItemContainer: function() {
|
|
var $itemContainer = $("<div>").addClass(PIVOT_ITEM_CONTAINER_CLASS);
|
|
this._element().append($itemContainer);
|
|
this._$itemWrapper = $("<div>").addClass(PIVOT_ITEM_WRAPPER_CLASS);
|
|
$itemContainer.append(this._$itemWrapper)
|
|
},
|
|
_clearItemsCache: function() {
|
|
this._itemsCache = []
|
|
},
|
|
_initTabs: function() {
|
|
var self = this,
|
|
$tabsContainer = $("<div>").addClass(PIVOT_TABS_CONTAINER_CLASS);
|
|
this._element().append($tabsContainer);
|
|
$tabsContainer.dxPivotTabs({
|
|
items: this.option("items"),
|
|
selectedIndex: this.option("selectedIndex"),
|
|
prepareAction: function() {
|
|
self._prepareAnimation()
|
|
},
|
|
updatePositionAction: function(args) {
|
|
self._updateContentPosition(args.offset)
|
|
},
|
|
rollbackAction: function() {
|
|
self._animateRollback()
|
|
},
|
|
completeAction: function(args) {
|
|
self._animateComplete(args.newIndex)
|
|
}
|
|
});
|
|
this._tabs = $tabsContainer.dxPivotTabs("instance")
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(PIVOT_CLASS);
|
|
this.callBase()
|
|
},
|
|
_renderCurrentContent: function(currentIndex, previousIndex) {
|
|
var itemsCache = this._itemsCache;
|
|
itemsCache[previousIndex] = this._selectedItemElement();
|
|
itemsCache[previousIndex].addClass(PIVOT_ITEM_HIDDEN_CLASS);
|
|
if (itemsCache[currentIndex])
|
|
itemsCache[currentIndex].removeClass(PIVOT_ITEM_HIDDEN_CLASS);
|
|
else
|
|
this._renderContent()
|
|
},
|
|
_updateContentPosition: function(offset) {
|
|
translator.move(this._$itemWrapper, {left: this._calculatePixelOffset(offset)})
|
|
},
|
|
_animateRollback: function() {
|
|
animation.returnBack(this._$itemWrapper)
|
|
},
|
|
_animateComplete: function(newIndex) {
|
|
var self = this,
|
|
$itemWrapper = this._$itemWrapper,
|
|
isRightSwipeHandled = this._isRightSwipeHandled(),
|
|
intermediatePosition = isRightSwipeHandled ? this._itemWrapperWidth : -this._itemWrapperWidth;
|
|
animation.slideAway($itemWrapper, intermediatePosition, function() {
|
|
translator.move($itemWrapper, {left: -intermediatePosition});
|
|
self._indexChangeOnAnimation = true;
|
|
self.option("selectedIndex", newIndex);
|
|
self._indexChangeOnAnimation = false;
|
|
animation.slideBack($itemWrapper)
|
|
})
|
|
},
|
|
_calculatePixelOffset: function(offset) {
|
|
offset = offset || 0;
|
|
return offset * this._itemWrapperWidth
|
|
},
|
|
_isRightSwipeHandled: function() {
|
|
return translator.locate(this._$itemWrapper).left > 0
|
|
},
|
|
_initSwipeHandlers: function() {
|
|
this._element().on(events.addNamespace("dxswipestart", this.NAME), $.proxy(this._swipeStartHandler, this)).on(events.addNamespace("dxswipe", this.NAME), $.proxy(this._swipeUpdateHandler, this)).on(events.addNamespace("dxswipeend", this.NAME), $.proxy(this._swipeEndHandler, this))
|
|
},
|
|
_swipeStartHandler: function(e) {
|
|
this._prepareAnimation();
|
|
this._tabs.prepare();
|
|
if (this.option("disabled") || this._indexBoundary() <= 1)
|
|
e.cancel = true
|
|
},
|
|
_prepareAnimation: function() {
|
|
this._stopAnimation();
|
|
this._itemWrapperWidth = this._$itemWrapper.outerWidth()
|
|
},
|
|
_stopAnimation: function() {
|
|
completeAnimation(this._$itemWrapper);
|
|
completeAnimation(this._$itemWrapper)
|
|
},
|
|
_swipeUpdateHandler: function(e) {
|
|
var offset = e.offset;
|
|
this._updateContentPosition(offset);
|
|
this._tabs.updatePosition(offset)
|
|
},
|
|
_swipeEndHandler: function(e) {
|
|
var selectedIndex = this.option("selectedIndex"),
|
|
targetOffset = e.targetOffset;
|
|
if (targetOffset === 0) {
|
|
this._animateRollback();
|
|
this._tabs.rollback()
|
|
}
|
|
else {
|
|
var newIndex = this._normalizeIndex(selectedIndex - targetOffset);
|
|
this._animateComplete(newIndex, selectedIndex);
|
|
this._tabs.complete(newIndex)
|
|
}
|
|
},
|
|
_renderSelectedIndex: function(current, previous) {
|
|
if (previous !== undefined)
|
|
this._renderCurrentContent(current, previous)
|
|
},
|
|
_normalizeIndex: function(index) {
|
|
var boundary = this._indexBoundary();
|
|
if (index < 0)
|
|
index = boundary + index;
|
|
if (index >= boundary)
|
|
index = index - boundary;
|
|
return index
|
|
},
|
|
_indexBoundary: function() {
|
|
return this.option("items").length
|
|
},
|
|
_renderContentImpl: function() {
|
|
var items = this.option("items"),
|
|
selectedIndex = this.option("selectedIndex");
|
|
if (items.length)
|
|
this._renderItems([items[selectedIndex]])
|
|
},
|
|
_selectedItemElement: function() {
|
|
return this._$itemWrapper.children(":not(." + PIVOT_ITEM_HIDDEN_CLASS + ")")
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"selectedIndex":
|
|
if (!this._indexChangeOnAnimation)
|
|
this._tabs.option("selectedIndex", value);
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
case"items":
|
|
this._tabs.option("items", value);
|
|
this._clearItemsCache();
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}));
|
|
ui.dxPivot.__internals = {animation: animation}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.toolbar.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
fx = DX.fx,
|
|
utils = DX.utils,
|
|
translator = DX.translator;
|
|
var TOOLBAR_CLASS = "dx-toolbar",
|
|
TOOLBAR_BOTTOM_CLASS = "dx-toolbar-bottom",
|
|
TOOLBAR_MINI_CLASS = "dx-toolbar-mini",
|
|
TOOLBAR_ITEM_CLASS = "dx-toolbar-item",
|
|
TOOLBAR_LABEL_CLASS = "dx-toolbar-label",
|
|
TOOLBAR_BUTTON_CLASS = "dx-toolbar-button",
|
|
TOOLBAR_MENU_CONTAINER_CLASS = "dx-toolbar-menu-container",
|
|
TOOLBAR_MENU_BUTTON_CLASS = "dx-toolbar-menu-button",
|
|
TOOLBAR_ITEMS_CONTAINER_CLASS = "dx-toolbar-items-container",
|
|
TOOLBAR_LABEL_SELECTOR = "." + TOOLBAR_LABEL_CLASS,
|
|
TOOLBAR_ITEM_DATA_KEY = "dxToolbarItemDataKey",
|
|
SUBMENU_SWIPE_EASING = "easeOutCubic",
|
|
SUBMENU_HIDE_DURATION = 200,
|
|
SUBMENU_SHOW_DURATION = 400;
|
|
var slideSubmenu = function($element, position, isShowAnimation) {
|
|
var duration = isShowAnimation ? SUBMENU_SHOW_DURATION : SUBMENU_HIDE_DURATION;
|
|
fx.animate($element, {
|
|
type: "slide",
|
|
to: {top: position},
|
|
easing: SUBMENU_SWIPE_EASING,
|
|
duration: duration
|
|
})
|
|
};
|
|
ui.registerComponent("dxToolbar", ui.CollectionContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
menuItemRender: null,
|
|
menuItemTemplate: "item",
|
|
submenuType: "dxDropDownMenu",
|
|
renderAs: "topToolbar"
|
|
})
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$toolbarItemsContainer.find([".dx-toolbar-left", ".dx-toolbar-center", ".dx-toolbar-right"].join(","))
|
|
},
|
|
_itemClass: function() {
|
|
return TOOLBAR_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return TOOLBAR_ITEM_DATA_KEY
|
|
},
|
|
_itemRenderDefault: function(item, index, itemElement) {
|
|
this.callBase(item, index, itemElement);
|
|
var widget = item.widget;
|
|
if (widget) {
|
|
var widgetElement = $("<div>").appendTo(itemElement),
|
|
widgetName = DX.inflector.camelize("dx-" + widget),
|
|
options = item.options || {};
|
|
widgetElement[widgetName](options)
|
|
}
|
|
else if (item.text)
|
|
itemElement.wrapInner("<div>")
|
|
},
|
|
_render: function() {
|
|
this._renderToolbar();
|
|
this._renderSections();
|
|
this.callBase();
|
|
this._renderMenu();
|
|
this._arrangeTitle();
|
|
this._windowTitleResizeCallback = $.proxy(this._arrangeTitle, this);
|
|
utils.windowResizeCallbacks.add(this._windowTitleResizeCallback)
|
|
},
|
|
_renderToolbar: function() {
|
|
this._element().addClass(TOOLBAR_CLASS).toggleClass(TOOLBAR_BOTTOM_CLASS, this.option("renderAs") === "bottomToolbar");
|
|
this._$toolbarItemsContainer = $("<div>").appendTo(this._element());
|
|
this._$toolbarItemsContainer.addClass(TOOLBAR_ITEMS_CONTAINER_CLASS)
|
|
},
|
|
_renderSections: function() {
|
|
var $container = this._$toolbarItemsContainer,
|
|
self = this;
|
|
$.each(["left", "center", "right"], function() {
|
|
var sectionClass = "dx-toolbar-" + this,
|
|
$section = $container.find("." + sectionClass);
|
|
if (!$section.length)
|
|
self["_$" + this + "Section"] = $section = $("<div>").addClass(sectionClass).appendTo($container)
|
|
})
|
|
},
|
|
_arrangeTitle: function() {
|
|
var $container = this._$toolbarItemsContainer,
|
|
$centerSection = this._$centerSection,
|
|
$label = $centerSection.children(TOOLBAR_LABEL_SELECTOR).eq(0);
|
|
if ($label.length === 0)
|
|
return;
|
|
var containerWidth = $container.width(),
|
|
leftWidth = this._$leftSection.outerWidth(),
|
|
rightWidth = this._$rightSection.outerWidth();
|
|
var elemsAtCenterWidth = 10;
|
|
$centerSection.children().not(TOOLBAR_LABEL_SELECTOR).each(function() {
|
|
elemsAtCenterWidth += $(this).outerWidth()
|
|
});
|
|
var maxLabelWidth = containerWidth - leftWidth - rightWidth - elemsAtCenterWidth;
|
|
var labelLongerThanMax = $label.width() > maxLabelWidth;
|
|
$centerSection.css({
|
|
marginLeft: labelLongerThanMax ? leftWidth : "",
|
|
marginRight: labelLongerThanMax ? rightWidth : ""
|
|
});
|
|
$label.css("max-width", maxLabelWidth)
|
|
},
|
|
_renderItem: function(index, item) {
|
|
var align = item.location || item.align || "center",
|
|
container = this._$toolbarItemsContainer.find(".dx-toolbar-" + align);
|
|
var itemElement = this.callBase(index, item, container);
|
|
itemElement.addClass(TOOLBAR_BUTTON_CLASS);
|
|
if (item.text)
|
|
itemElement.addClass(TOOLBAR_LABEL_CLASS).removeClass(TOOLBAR_BUTTON_CLASS);
|
|
return itemElement
|
|
},
|
|
_hasVisibleMenuItems: function() {
|
|
var menuItems = this._getMenuItems(),
|
|
result = false;
|
|
var optionGetter = DevExpress.data.utils.compileGetter("visible");
|
|
$.each(menuItems, function(index, item) {
|
|
var itemVisible = optionGetter(item, {functionsAsIs: true});
|
|
if (itemVisible !== false)
|
|
result = true
|
|
});
|
|
return result
|
|
},
|
|
_getToolbarItems: function() {
|
|
return $.grep(this.option("items") || [], function(item) {
|
|
return item.location !== "menu"
|
|
})
|
|
},
|
|
_getMenuItems: function() {
|
|
return $.grep(this.option("items") || [], function(item) {
|
|
return item.location === "menu"
|
|
})
|
|
},
|
|
_renderContentImpl: function() {
|
|
var items = this._getToolbarItems();
|
|
this._element().toggleClass(TOOLBAR_MINI_CLASS, items.length === 0);
|
|
if (this._renderedItemsCount)
|
|
this._renderItems(items.slice(this._renderedItemsCount));
|
|
else
|
|
this._renderItems(items)
|
|
},
|
|
_renderMenu: function() {
|
|
var self = this,
|
|
itemClickAction = this._createActionByOption("itemClickAction");
|
|
var options = {
|
|
itemRender: this.option("menuItemRender"),
|
|
itemTemplate: this.option("menuItemTemplate"),
|
|
itemClickAction: function(e) {
|
|
self._toggleMenuVisibility(false, true);
|
|
itemClickAction(e)
|
|
}
|
|
};
|
|
this._menuType = this.option("submenuType");
|
|
if (this._menuType === "dxList" && this.option("renderAs") === "topToolbar")
|
|
this._menuType = "dxDropDownMenu";
|
|
switch (this._menuType) {
|
|
case"dxActionSheet":
|
|
this._renderActionSheet(options);
|
|
break;
|
|
case"dxDropDownMenu":
|
|
this._renderDropDown(options);
|
|
break;
|
|
case"dxList":
|
|
this._renderList(options);
|
|
break
|
|
}
|
|
},
|
|
_renderMenuButton: function(options) {
|
|
var buttonOptions = $.extend({clickAction: $.proxy(this._handleMenuButtonClick, this)}, options);
|
|
this._renderMenuButtonContainer();
|
|
this._$button = $("<div>").appendTo(this._$menuButtonContainer).addClass(TOOLBAR_MENU_BUTTON_CLASS).dxButton(buttonOptions)
|
|
},
|
|
_renderMenuButtonContainer: function() {
|
|
var $rightSection = this._$rightSection;
|
|
this._$menuButtonContainer = $("<div>").appendTo($rightSection).addClass(TOOLBAR_BUTTON_CLASS).addClass(TOOLBAR_MENU_CONTAINER_CLASS)
|
|
},
|
|
_renderDropDown: function(options) {
|
|
if (!this._hasVisibleMenuItems())
|
|
return;
|
|
this._renderMenuButtonContainer();
|
|
this._menu = $("<div>").appendTo(this._$menuButtonContainer).dxDropDownMenu(options).dxDropDownMenu("instance");
|
|
this._renderMenuItems()
|
|
},
|
|
_renderActionSheet: function(options) {
|
|
if (!this._hasVisibleMenuItems())
|
|
return;
|
|
this._renderMenuButton({icon: "overflow"});
|
|
var actionSheetOptions = $.extend({
|
|
target: this._$button,
|
|
showTitle: false
|
|
}, options);
|
|
this._menu = $("<div>").appendTo(this._element()).dxActionSheet(actionSheetOptions).dxActionSheet("instance");
|
|
this._renderMenuItems()
|
|
},
|
|
_renderList: function(options) {
|
|
this._renderMenuButton({
|
|
activeStateEnabled: false,
|
|
text: "..."
|
|
});
|
|
var listOptions = $.extend({width: "100%"}, options);
|
|
this._renderListOverlay();
|
|
this._renderContainerSwipe();
|
|
if (this._hasVisibleMenuItems()) {
|
|
this._menu = $("<div>").appendTo(this._listOverlay.content()).dxList(listOptions).dxList("instance");
|
|
this._renderMenuItems()
|
|
}
|
|
this._changeListVisible(this.option("visible"));
|
|
this._windowResizeCallback = $.proxy(this._toggleMenuVisibility, this);
|
|
utils.windowResizeCallbacks.add(this._windowResizeCallback)
|
|
},
|
|
_renderMenuItems: function() {
|
|
this._menu.addExternalTemplate(this._templates);
|
|
this._menu.option("items", this._getMenuItems())
|
|
},
|
|
_getListHeight: function() {
|
|
var listHeight = this._listOverlay.content().find(".dx-list").height(),
|
|
semiHiddenHeight = this._$toolbarItemsContainer.height() - this._element().height();
|
|
return listHeight + semiHiddenHeight
|
|
},
|
|
_renderListOverlay: function() {
|
|
var element = this._element();
|
|
this._listOverlay = $("<div>").appendTo(element).dxOverlay({
|
|
targetContainer: false,
|
|
deferRendering: false,
|
|
shading: false,
|
|
height: "auto",
|
|
width: "100%",
|
|
showTitle: false,
|
|
closeOnOutsideClick: $.proxy(this._handleListOutsideClick, this),
|
|
position: null,
|
|
animation: null,
|
|
backButtonHandler: null
|
|
}).dxOverlay("instance")
|
|
},
|
|
_backButtonHandler: function() {
|
|
this._toggleMenuVisibility(false, true)
|
|
},
|
|
_toggleBackButtonCallback: function() {
|
|
if (this._closeCallback)
|
|
DX.backButtonCallback.remove(this._closeCallback);
|
|
if (this._menuShown) {
|
|
this._closeCallback = $.proxy(this._backButtonHandler, this);
|
|
DX.backButtonCallback.add(this._closeCallback)
|
|
}
|
|
},
|
|
_renderContainerSwipe: function() {
|
|
this._$toolbarItemsContainer.appendTo(this._listOverlay.content()).dxSwipeable({
|
|
elastic: false,
|
|
startAction: $.proxy(this._handleSwipeStart, this),
|
|
updateAction: $.proxy(this._handleSwipeUpdate, this),
|
|
endAction: $.proxy(this._handleSwipeEnd, this),
|
|
itemSizeFunc: $.proxy(this._getListHeight, this),
|
|
direction: "vertical"
|
|
})
|
|
},
|
|
_handleListOutsideClick: function(e) {
|
|
if (!$(e.target).closest(this._listOverlay.content()).length)
|
|
this._toggleMenuVisibility(false, true)
|
|
},
|
|
_calculatePixelOffset: function(offset) {
|
|
offset = (offset || 0) - 1;
|
|
var maxOffset = this._getListHeight();
|
|
return offset * maxOffset
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
e.jQueryEvent.maxTopOffset = this._menuShown ? 0 : 1;
|
|
e.jQueryEvent.maxBottomOffset = this._menuShown ? 1 : 0
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
var offset = this._menuShown ? e.jQueryEvent.offset : 1 + e.jQueryEvent.offset;
|
|
this._renderMenuPosition(offset, false)
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
var targetOffset = e.jQueryEvent.targetOffset;
|
|
targetOffset -= this._menuShown - 1;
|
|
this._toggleMenuVisibility(targetOffset === 0, true)
|
|
},
|
|
_renderMenuPosition: function(offset, animate) {
|
|
var pos = this._calculatePixelOffset(offset),
|
|
element = this._listOverlay.content();
|
|
if (animate)
|
|
slideSubmenu(element, pos, this._menuShown);
|
|
else
|
|
translator.move(element, {top: pos})
|
|
},
|
|
_handleMenuButtonClick: function() {
|
|
this._toggleMenuVisibility(!this._menuShown, true)
|
|
},
|
|
_toggleMenuVisibility: function(visible, animate) {
|
|
this._menuShown = visible;
|
|
switch (this._menuType) {
|
|
case"dxList":
|
|
this._toggleBackButtonCallback();
|
|
this._renderMenuPosition(this._menuShown ? 0 : 1, animate);
|
|
break;
|
|
case"dxActionSheet":
|
|
this._menu.toggle(this._menuShown);
|
|
this._menuShown = false;
|
|
break
|
|
}
|
|
},
|
|
_renderEmptyMessage: $.noop,
|
|
_clean: function() {
|
|
this._$toolbarItemsContainer.children().empty();
|
|
this._element().empty()
|
|
},
|
|
_changeMenuOption: function(name, value) {
|
|
if (this._menu)
|
|
this._menu.option(name, value)
|
|
},
|
|
_changeListVisible: function(value) {
|
|
if (this._listOverlay) {
|
|
this._listOverlay.option("visible", value);
|
|
this._toggleMenuVisibility(false, false)
|
|
}
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"renderAs":
|
|
case"submenuType":
|
|
this._invalidate();
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
case"visible":
|
|
this._changeListVisible(value);
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
case"menuItemRender":
|
|
this._changeMenuOption("itemRender", value);
|
|
break;
|
|
case"menuItemTemplate":
|
|
this._changeMenuOption("itemTemplate", value);
|
|
break;
|
|
case"itemClickAction":
|
|
this._changeMenuOption(name, value);
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_dispose: function() {
|
|
if (this._windowResizeCallback)
|
|
utils.windowResizeCallbacks.remove(this._windowResizeCallback);
|
|
if (this._windowTitleResizeCallback)
|
|
utils.windowResizeCallbacks.remove(this._windowTitleResizeCallback);
|
|
this.callBase()
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.listEdit.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
translator = DX.translator,
|
|
fx = DX.fx,
|
|
utils = DX.utils;
|
|
var editOptionsRegistry = [];
|
|
var registerOption = function(option) {
|
|
editOptionsRegistry.push(option)
|
|
};
|
|
registerOption("delete");
|
|
registerOption("selection");
|
|
var LIST_ITEM_BAG_CONTAINER_CLASS = "dx-list-item-bag-container",
|
|
LIST_ITEM_CONTENT_CLASS = "dx-list-item-content",
|
|
LIST_ITEM_LEFT_BAG_CLASS = "dx-list-item-left-bag",
|
|
LIST_ITEM_RIGHT_BAG_CLASS = "dx-list-item-right-bag",
|
|
DECORATOR_LEFT_BAG_CREATE_METHOD = "leftBag",
|
|
DECORATOR_RIGHT_BAG_CREATE_METHOD = "rightBag",
|
|
DECORATOR_MODIFY_ELEMENT_METHOD = "modifyElement";
|
|
var ListEditProvider = DX.Class.inherit({
|
|
ctor: function(list, config) {
|
|
this._list = list;
|
|
this._config = config;
|
|
if (this.isModifyingByDecorators())
|
|
this._fetchRequiredDecorators()
|
|
},
|
|
dispose: function() {
|
|
if (this._decorators && this._decorators.length)
|
|
$.each(this._decorators, function(_, decorator) {
|
|
decorator.dispose()
|
|
})
|
|
},
|
|
isModifyingByDecorators: function() {
|
|
return !(this.isRenderingByRenderer() || this.isRenderingByTemplate())
|
|
},
|
|
isRenderingByRenderer: function() {
|
|
return !!this.getItemRenderer()
|
|
},
|
|
getItemRenderer: function() {
|
|
return this._config.itemRender
|
|
},
|
|
isRenderingByTemplate: function() {
|
|
return !!this.getItemTemplateName()
|
|
},
|
|
getItemTemplateName: function() {
|
|
return this._config.itemTemplate
|
|
},
|
|
_fetchRequiredDecorators: function() {
|
|
var self = this;
|
|
this._decorators = [];
|
|
$.each(editOptionsRegistry, function(_, option) {
|
|
var enabledOptionName = option + "Enabled",
|
|
modeOptionName = option + "Mode";
|
|
if (self._config[enabledOptionName]) {
|
|
var decorator = self._createDecorator(option, self._config[modeOptionName]);
|
|
self._decorators.push(decorator)
|
|
}
|
|
})
|
|
},
|
|
_createDecorator: function(option, type) {
|
|
var decoratorClass = this._findDecorator(option, type);
|
|
return new decoratorClass(this._list)
|
|
},
|
|
_findDecorator: function(option, type) {
|
|
var foundDecorator = decoratorsRegistry[option][type];
|
|
if (!foundDecorator)
|
|
throw new Error("Decorator with editing option: \"" + option + "\" and type: \"" + type + "\" not found");
|
|
return foundDecorator
|
|
},
|
|
modifyItemElement: function() {
|
|
var proxyArgs = [this._modifyItemElementImpl, this];
|
|
proxyArgs.push.apply(proxyArgs, arguments);
|
|
utils.executeAsync($.proxy.apply($, proxyArgs))
|
|
},
|
|
_modifyItemElementImpl: function(args) {
|
|
var $itemElement = $(args.itemElement);
|
|
$itemElement.addClass(LIST_ITEM_BAG_CONTAINER_CLASS);
|
|
this._wrapContent($itemElement);
|
|
var config = {$itemElement: $itemElement};
|
|
this._prependLeftBags($itemElement, config);
|
|
this._appendRightBags($itemElement, config);
|
|
this._applyDecorators(DECORATOR_MODIFY_ELEMENT_METHOD, config)
|
|
},
|
|
_wrapContent: function($itemElement) {
|
|
var $contentContainer = $("<div />").addClass(LIST_ITEM_CONTENT_CLASS);
|
|
$itemElement.wrapInner($contentContainer)
|
|
},
|
|
_prependLeftBags: function($itemElement, config) {
|
|
var $leftBags = this._collectDecoratorsMarkup(DECORATOR_LEFT_BAG_CREATE_METHOD, config, LIST_ITEM_LEFT_BAG_CLASS);
|
|
$itemElement.prepend($leftBags)
|
|
},
|
|
_appendRightBags: function($itemElement, config) {
|
|
var $rightBags = this._collectDecoratorsMarkup(DECORATOR_RIGHT_BAG_CREATE_METHOD, config, LIST_ITEM_RIGHT_BAG_CLASS);
|
|
$itemElement.append($rightBags)
|
|
},
|
|
_collectDecoratorsMarkup: function(method, config, containerClass) {
|
|
var $collector = $("<div />");
|
|
$.each(this._decorators, function() {
|
|
var $container = $("<div />").addClass(containerClass);
|
|
this[method]($.extend(config, {$container: $container}));
|
|
if ($container.children().length)
|
|
$collector.append($container)
|
|
});
|
|
return $collector.children()
|
|
},
|
|
_applyDecorators: function(method, config) {
|
|
$.each(this._decorators, function() {
|
|
this[method](config)
|
|
})
|
|
},
|
|
_handlerExists: function(name) {
|
|
if (!this._decorators)
|
|
return false;
|
|
var decorators = this._decorators,
|
|
length = decorators.length;
|
|
for (var i = 0; i < length; i++)
|
|
if (decorators[i][name])
|
|
return true;
|
|
return false
|
|
},
|
|
_handleEvent: function(name, $itemElement) {
|
|
if (!this._decorators)
|
|
return false;
|
|
var response = false,
|
|
decorators = this._decorators,
|
|
length = decorators.length;
|
|
for (var i = 0; i < length; i++) {
|
|
response = decorators[i][name]($itemElement);
|
|
if (response)
|
|
break
|
|
}
|
|
return response
|
|
},
|
|
handleClick: function($itemElement) {
|
|
return this._handleEvent("handleClick", $itemElement)
|
|
},
|
|
holdHandlerExists: function() {
|
|
return this._handlerExists("handleHold")
|
|
},
|
|
handleHold: function($itemElement) {
|
|
return this._handleEvent("handleHold", $itemElement)
|
|
}
|
|
});
|
|
var decoratorsRegistry = {};
|
|
var registerDecorator = function(option, type, decoratorClass) {
|
|
var decoratorConfig = {};
|
|
decoratorConfig[option] = decoratorsRegistry[option] ? decoratorsRegistry[option] : {};
|
|
decoratorConfig[option][type] = decoratorClass;
|
|
decoratorsRegistry = $.extend(decoratorsRegistry, decoratorConfig)
|
|
};
|
|
var DX_LIST_EDIT_DECORATOR = "dxListEditDecorator";
|
|
var ListEditDecorator = DX.Class.inherit({
|
|
ctor: function(list) {
|
|
this._list = list;
|
|
this._init()
|
|
},
|
|
_init: $.noop,
|
|
dispose: $.noop,
|
|
modifyElement: $.noop,
|
|
leftBag: $.noop,
|
|
rightBag: $.noop,
|
|
handleClick: $.noop,
|
|
handleHold: $.noop
|
|
});
|
|
var SWITCHABLE_DELETE_READY_CLASS = "dx-switchable-delete-ready",
|
|
SWITCHABLE_DELETE_BUTTON_CONTAINER_CLASS = "dx-switchable-delete-button-container",
|
|
SWITCHABLE_DELETE_BUTTON_WRAPPER_CLASS = "dx-switchable-delete-button-wrapper",
|
|
SWITCHABLE_DELETE_BUTTON_INNER_WRAPPER_CLASS = "dx-switchable-delete-button-inner-wrapper",
|
|
SWITCHABLE_DELETE_BUTTON_CLASS = "dx-switchable-delete-button";
|
|
var SwitchableDeleteDecorator = ListEditDecorator.inherit({
|
|
handleClick: function() {
|
|
var self = this,
|
|
$readyToDelete = this._list._element().find("." + SWITCHABLE_DELETE_READY_CLASS);
|
|
$.each($readyToDelete, function(_, itemElement) {
|
|
self._cancelDelete($(itemElement))
|
|
});
|
|
return $readyToDelete.length !== 0
|
|
},
|
|
_isReadyToDelete: function($itemElement) {
|
|
return $itemElement.hasClass(SWITCHABLE_DELETE_READY_CLASS)
|
|
},
|
|
_toggleDeleteReady: function($itemElement, readyToDelete) {
|
|
$itemElement.toggleClass(SWITCHABLE_DELETE_READY_CLASS, readyToDelete)
|
|
},
|
|
_cancelDelete: function($itemElement) {
|
|
this._toggleDeleteReady($itemElement, false)
|
|
}
|
|
});
|
|
var SwitchableButtonDeleteDecorator = SwitchableDeleteDecorator.inherit({modifyElement: function(config) {
|
|
var self = this,
|
|
$itemElement = config.$itemElement;
|
|
var $buttonContainer = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_CONTAINER_CLASS),
|
|
$buttonWrapper = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_WRAPPER_CLASS),
|
|
$buttonInnerWrapper = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_INNER_WRAPPER_CLASS),
|
|
$button = $("<div />").addClass(SWITCHABLE_DELETE_BUTTON_CLASS);
|
|
$button.dxButton({
|
|
text: Globalize.localize("dxListEditDecorator-delete"),
|
|
type: "danger",
|
|
clickAction: function(e) {
|
|
self._list.deleteItem($itemElement);
|
|
e.jQueryEvent.stopPropagation()
|
|
}
|
|
});
|
|
$buttonContainer.append($buttonWrapper);
|
|
$buttonWrapper.append($buttonInnerWrapper);
|
|
$buttonInnerWrapper.append($button);
|
|
$itemElement.append($buttonContainer);
|
|
if (!this._bottonContainerWidth)
|
|
this._bottonContainerWidth = $buttonContainer.outerWidth();
|
|
$buttonContainer.css("right", -this._bottonContainerWidth)
|
|
}});
|
|
var TOGGLE_DELETE_SWITCH_CONTAINER_CLASS = "dx-toggle-delete-switch-container",
|
|
TOGGLE_DELETE_SWITCH_CLASS = "dx-toggle-delete-switch";
|
|
registerDecorator("delete", "toggle", SwitchableButtonDeleteDecorator.inherit({leftBag: function(config) {
|
|
var self = this,
|
|
$itemElement = config.$itemElement,
|
|
$container = config.$container;
|
|
var $toggle = $("<div />").dxButton({
|
|
icon: "toggle-delete",
|
|
clickAction: function(e) {
|
|
self._toggleDeleteReady($itemElement);
|
|
e.jQueryEvent.stopPropagation()
|
|
}
|
|
}).addClass(TOGGLE_DELETE_SWITCH_CLASS);
|
|
$container.addClass(TOGGLE_DELETE_SWITCH_CONTAINER_CLASS);
|
|
$container.append($toggle)
|
|
}}));
|
|
registerDecorator("delete", "slideButton", SwitchableButtonDeleteDecorator.inherit({modifyElement: function(config) {
|
|
this.callBase.apply(this, arguments);
|
|
var self = this,
|
|
$itemElement = config.$itemElement;
|
|
$itemElement.on(events.addNamespace("dxswipeend", DX_LIST_EDIT_DECORATOR), function(e) {
|
|
if (e.targetOffset !== 0)
|
|
self._toggleDeleteReady($itemElement)
|
|
})
|
|
}}));
|
|
var SLIDE_ITEM_WRAPPER_CLASS = "dx-slide-item-wrapper",
|
|
SLIDE_ITEM_CONTENT_CLASS = "dx-slide-item-content",
|
|
SLIDE_ITEM_DELETE_BUTTON_CONTAINER_CLASS = "dx-slide-item-delete-button-container",
|
|
SLIDE_ITEM_DELETE_BUTTON_CLASS = "dx-slide-item-delete-button",
|
|
SLIDE_ITEM_DELETE_BUTTON_HIDDEN_CLASS = "dx-slide-item-delete-button-hidden",
|
|
SLIDE_ITEM_DELETE_BUTTON_CONTENT_CLASS = "dx-slide-item-delete-button-content";
|
|
registerDecorator("delete", "slideItem", SwitchableDeleteDecorator.inherit({
|
|
modifyElement: function(config) {
|
|
var self = this,
|
|
$itemElement = config.$itemElement;
|
|
var $buttonContent = $("<div/>").addClass(SLIDE_ITEM_DELETE_BUTTON_CONTENT_CLASS).text(Globalize.localize("dxListEditDecorator-delete")),
|
|
$button = $("<div/>").addClass(SLIDE_ITEM_DELETE_BUTTON_CLASS).append($buttonContent),
|
|
$buttonContainer = $("<div/>").addClass(SLIDE_ITEM_DELETE_BUTTON_CONTAINER_CLASS).append($button);
|
|
$itemElement.wrapInner($("<div/>").addClass(SLIDE_ITEM_CONTENT_CLASS)).append($buttonContainer).addClass(SLIDE_ITEM_WRAPPER_CLASS);
|
|
$button.on(events.addNamespace("dxclick", DX_LIST_EDIT_DECORATOR), function() {
|
|
self._list.deleteItem($itemElement)
|
|
});
|
|
$itemElement.on(events.addNamespace("dxswipestart", DX_LIST_EDIT_DECORATOR), $.proxy(this._handleSwipeStart, this)).on(events.addNamespace("dxswipe", DX_LIST_EDIT_DECORATOR), $.proxy(this._handleSwipe, this)).on(events.addNamespace("dxswipeend", DX_LIST_EDIT_DECORATOR), $.proxy(this._handleSwipeEnd, this))
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
var $itemElement = $(e.currentTarget);
|
|
this._cachedItemWidth = $itemElement.width();
|
|
this._cacheButtonWidth($itemElement)
|
|
},
|
|
_cacheButtonWidth: function($itemElement) {
|
|
this._cachedButtonWidth = this._cachedButtonWidth || $itemElement.find("." + SLIDE_ITEM_DELETE_BUTTON_CLASS).outerWidth()
|
|
},
|
|
_minBottonContainerLeftOffset: function() {
|
|
return this._cachedItemWidth - this._cachedButtonWidth
|
|
},
|
|
_handleSwipe: function(e) {
|
|
var $itemElement = $(e.currentTarget),
|
|
$content = $itemElement.find("." + SLIDE_ITEM_CONTENT_CLASS),
|
|
$buttonContainer = $itemElement.find("." + SLIDE_ITEM_DELETE_BUTTON_CONTAINER_CLASS),
|
|
$botton = $buttonContainer.find("." + SLIDE_ITEM_DELETE_BUTTON_CLASS),
|
|
offset = this._cachedItemWidth * e.offset,
|
|
startOffset = this._isReadyToDelete($itemElement) ? -this._cachedButtonWidth : 0,
|
|
position = offset + startOffset < 0 ? offset + startOffset : 0;
|
|
translator.move($content, {left: position});
|
|
$buttonContainer.css("left", Math.max(this._cachedItemWidth + position, this._minBottonContainerLeftOffset()))
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
var $itemElement = $(e.currentTarget),
|
|
offset = this._cachedItemWidth * e.offset,
|
|
endedAtReadyToDelete = !this._isReadyToDelete($itemElement) && -offset > this._cachedButtonWidth * .8,
|
|
readyToDelete = e.targetOffset === -1 || endedAtReadyToDelete;
|
|
this._toggleDeleteState($itemElement, readyToDelete)
|
|
},
|
|
_toggleDeleteState: function($itemElement, state) {
|
|
if (state)
|
|
this._prepareToDelete($itemElement);
|
|
else
|
|
this._cancelDelete($itemElement)
|
|
},
|
|
_prepareToDelete: function($itemElement) {
|
|
var contentAnimation = fx.animate($itemElement.find("." + SLIDE_ITEM_CONTENT_CLASS), {
|
|
to: {left: -this._cachedButtonWidth},
|
|
type: "slide",
|
|
duration: 200
|
|
});
|
|
var buttonContainerAnimation = fx.animate($itemElement.find("." + SLIDE_ITEM_DELETE_BUTTON_CONTAINER_CLASS), {
|
|
to: {left: this._minBottonContainerLeftOffset()},
|
|
duration: 200
|
|
});
|
|
$.when(contentAnimation, buttonContainerAnimation).done($.proxy(this._toggleDeleteReady, this, $itemElement, true))
|
|
},
|
|
_cancelDelete: function($itemElement) {
|
|
this.callBase.apply(this, arguments);
|
|
fx.animate($itemElement.find("." + SLIDE_ITEM_CONTENT_CLASS), {
|
|
to: {left: 0},
|
|
type: "slide",
|
|
duration: 200
|
|
});
|
|
var $buttonContainer = $itemElement.find("." + SLIDE_ITEM_DELETE_BUTTON_CONTAINER_CLASS);
|
|
fx.animate($buttonContainer, {
|
|
to: {left: this._cachedItemWidth},
|
|
duration: 200,
|
|
complete: function() {
|
|
$buttonContainer.css("left", "100%")
|
|
}
|
|
})
|
|
}
|
|
}));
|
|
registerDecorator("delete", "swipe", ListEditDecorator.inherit({
|
|
modifyElement: function(config) {
|
|
var $itemElement = config.$itemElement;
|
|
$itemElement.on(events.addNamespace("dxswipe", DX_LIST_EDIT_DECORATOR), $.proxy(this._handleSwipe, this)).on(events.addNamespace("dxswipeend", DX_LIST_EDIT_DECORATOR), $.proxy(this._handleSwipeEnd, this))
|
|
},
|
|
_renderItemPosition: function($item, offset, animate) {
|
|
var deferred = $.Deferred(),
|
|
itemWidth = $item.width(),
|
|
itemOffset = offset * itemWidth;
|
|
if (animate)
|
|
fx.animate($item, {
|
|
to: {left: itemOffset},
|
|
type: "slide",
|
|
complete: function() {
|
|
deferred.resolve($item, offset)
|
|
}
|
|
});
|
|
else {
|
|
translator.move($item, {left: itemOffset});
|
|
deferred.resolve()
|
|
}
|
|
return deferred.promise()
|
|
},
|
|
_handleSwipe: function(e) {
|
|
this._renderItemPosition($(e.currentTarget), e.offset)
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
var self = this,
|
|
$item = $(e.currentTarget),
|
|
offset = e.targetOffset;
|
|
this._renderItemPosition($item, offset, true).done(function($item, offset) {
|
|
if (Math.abs(offset))
|
|
self._list.deleteItem($item)
|
|
})
|
|
}
|
|
}));
|
|
var HOLDDELETE_MENU = "dx-holddelete-menu",
|
|
HOLDDELETE_MENUCONTENT = "dx-holddelete-menucontent",
|
|
HOLDDELETE_MENUITEM = "dx-holddelete-menuitem";
|
|
registerDecorator("delete", "hold", ListEditDecorator.inherit({
|
|
_init: function() {
|
|
var $menu = $("<div/>").addClass(HOLDDELETE_MENU);
|
|
this._list._element().append($menu);
|
|
this._overlay = this._renderOverlay($menu)
|
|
},
|
|
_renderOverlay: function($element) {
|
|
var self = this;
|
|
return $element.dxOverlay({
|
|
shading: false,
|
|
closeOnOutsideClick: function(e) {
|
|
return !$(e.target).closest("." + HOLDDELETE_MENU).length
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "custom",
|
|
duration: 300,
|
|
from: {
|
|
height: 0,
|
|
opacity: 1
|
|
},
|
|
to: {
|
|
height: function() {
|
|
return self._$menu.height()
|
|
},
|
|
opacity: 1
|
|
}
|
|
},
|
|
hide: {
|
|
type: "custom",
|
|
duration: 0,
|
|
from: {opacity: 1},
|
|
to: {opacity: 0}
|
|
},
|
|
position: {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: function() {
|
|
return self._$itemWithMenu
|
|
},
|
|
collision: "flip"
|
|
},
|
|
height: "auto"
|
|
},
|
|
contentReadyAction: $.proxy(this._renderMenu, this),
|
|
height: function() {
|
|
return self._$itemWithMenu
|
|
}
|
|
}).dxOverlay("instance")
|
|
},
|
|
_renderMenu: function(e) {
|
|
var $menuContent = $("<div/>").addClass(HOLDDELETE_MENUCONTENT),
|
|
$deleteMenuItem = $("<div/>").addClass(HOLDDELETE_MENUITEM).text(Globalize.localize("dxListEditDecorator-delete"));
|
|
$deleteMenuItem.on(events.addNamespace("dxclick", DX_LIST_EDIT_DECORATOR), $.proxy(this._deleteItem, this));
|
|
this._$menu = $menuContent.append($deleteMenuItem);
|
|
e.component.content().append(this._$menu)
|
|
},
|
|
_deleteItem: function() {
|
|
this._overlay.hide();
|
|
this._list.deleteItem(this._$itemWithMenu)
|
|
},
|
|
dispose: function() {
|
|
this._overlay._element().remove()
|
|
},
|
|
handleHold: function($itemElement) {
|
|
var overlay = this._overlay;
|
|
overlay.beginUpdate();
|
|
overlay.option("position", {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: $itemElement,
|
|
collision: "flip"
|
|
});
|
|
overlay.option("width", function() {
|
|
return $itemElement.width()
|
|
});
|
|
overlay.endUpdate();
|
|
overlay.show();
|
|
this._$itemWithMenu = $itemElement;
|
|
return true
|
|
}
|
|
}));
|
|
var LIST_ITEM_SELECTED_CLASS = "dx-list-item-selected",
|
|
SELECT_CHECKBOX_CONTAINER_CLASS = "dx-select-checkbox-container",
|
|
SELECT_CHECKBOX_CLASS = "dx-select-checkbox";
|
|
registerDecorator("selection", "control", ListEditDecorator.inherit({
|
|
leftBag: function(config) {
|
|
var self = this,
|
|
$itemElement = config.$itemElement,
|
|
$container = config.$container;
|
|
var $checkBox = $("<div />").addClass(SELECT_CHECKBOX_CLASS);
|
|
$checkBox.dxCheckBox({
|
|
checked: this._isSelected($itemElement),
|
|
clickAction: function(e) {
|
|
self._processCheckedState($itemElement, e.component.option("checked"));
|
|
e.jQueryEvent.stopPropagation()
|
|
}
|
|
});
|
|
$container.addClass(SELECT_CHECKBOX_CONTAINER_CLASS);
|
|
$container.append($checkBox)
|
|
},
|
|
modifyElement: function(config) {
|
|
var self = this,
|
|
$itemElement = config.$itemElement,
|
|
checkBox = $itemElement.find("." + SELECT_CHECKBOX_CLASS).dxCheckBox("instance");
|
|
$itemElement.on("stateChanged", function() {
|
|
checkBox.option("checked", self._isSelected($itemElement))
|
|
})
|
|
},
|
|
_isSelected: function($itemElement) {
|
|
return $itemElement.hasClass(LIST_ITEM_SELECTED_CLASS)
|
|
},
|
|
_processCheckedState: function($itemElement, checked) {
|
|
if (!$itemElement.hasClass("dx-list-item"))
|
|
throw new Error("SelectingControlDecorator._processCheckedState called with wrong parametrs");
|
|
if (checked)
|
|
this._list.selectItem($itemElement);
|
|
else
|
|
this._list.unselectItem($itemElement)
|
|
}
|
|
}));
|
|
registerDecorator("selection", "item", decoratorsRegistry.selection.control.inherit({handleClick: function($itemElement) {
|
|
var newCheckBoxState = !$itemElement.find("." + SELECT_CHECKBOX_CLASS).dxCheckBox("instance").option("checked");
|
|
this._processCheckedState($itemElement, newCheckBoxState);
|
|
return true
|
|
}}));
|
|
ui.ListEditProvider = ListEditProvider
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.list.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var DX_PREVENT_ITEM_CLICK_ACTION = "dxPreventItemClickAction";
|
|
var ListEditStrategy = DX.Class.inherit({
|
|
ctor: function(list) {
|
|
this._list = list
|
|
},
|
|
isItemIndex: DX.abstract,
|
|
getItemElementIndex: DX.abstract,
|
|
normalizeItemIndex: DX.abstract,
|
|
deleteItemAtIndex: DX.abstract,
|
|
updateSelectionAfterDelete: DX.abstract,
|
|
fetchSelectedItems: DX.abstract,
|
|
selectedItemIndecies: DX.abstract,
|
|
getItemByIndex: DX.abstract
|
|
});
|
|
var PlainListEditStrategy = ListEditStrategy.inherit({
|
|
isItemIndex: function(index) {
|
|
return $.isNumeric(index)
|
|
},
|
|
getItemElementIndex: function(itemElement) {
|
|
return this._list._itemElements().index(itemElement)
|
|
},
|
|
normalizeItemIndex: function(index) {
|
|
return index
|
|
},
|
|
deleteItemAtIndex: function(index) {
|
|
this._list.option("items").splice(index, 1)
|
|
},
|
|
updateSelectionAfterDelete: function(fromIndex) {
|
|
var selectedItemIndices = this._list._selectedItemIndices;
|
|
$.each(selectedItemIndices, function(i, index) {
|
|
if (index > fromIndex)
|
|
selectedItemIndices[i] -= 1
|
|
})
|
|
},
|
|
fetchSelectedItems: function() {
|
|
var items = this._list.option("items"),
|
|
selectedItems = [];
|
|
$.each(this._list._selectedItemIndices, function(_, index) {
|
|
selectedItems.push(items[index])
|
|
});
|
|
return selectedItems
|
|
},
|
|
selectedItemIndecies: function() {
|
|
var selectedIndices = [],
|
|
items = this._list.option("items"),
|
|
selected = this._list.option("selectedItems");
|
|
$.each(selected, function(_, selectedItem) {
|
|
var index = $.inArray(selectedItem, items);
|
|
if (index !== -1)
|
|
selectedIndices.push(index);
|
|
else
|
|
throw new Error("Item '" + selectedItem + "' you are trying to select does not exist");
|
|
});
|
|
return selectedIndices
|
|
},
|
|
getItemByIndex: function(index) {
|
|
return this._list._itemElements().eq(index)
|
|
}
|
|
});
|
|
var SELECTION_SHIFT = 20,
|
|
SELECTION_MASK = 0x8FF;
|
|
var combineIndex = function(indices) {
|
|
return (indices.group << SELECTION_SHIFT) + indices.item
|
|
};
|
|
var splitIndex = function(combinedIndex) {
|
|
return {
|
|
group: combinedIndex >> SELECTION_SHIFT,
|
|
item: combinedIndex & SELECTION_MASK
|
|
}
|
|
};
|
|
var createGroupSelection = function(group, selectedItems) {
|
|
var groupItems = group.items,
|
|
groupSelection = {
|
|
key: group.key,
|
|
items: []
|
|
};
|
|
$.each(selectedItems, function(_, itemIndex) {
|
|
groupSelection.items.push(groupItems[itemIndex])
|
|
});
|
|
return groupSelection
|
|
};
|
|
var groupByKey = function(groups, key) {
|
|
var length = groups.length;
|
|
for (var i = 0; i < length; i++)
|
|
if (groups[i].key === key)
|
|
return groups[i]
|
|
};
|
|
var GroupedListEditStrategy = ListEditStrategy.inherit({
|
|
_groupElements: function() {
|
|
return this._list._itemContainer().find("." + LIST_GROUP_CLASS)
|
|
},
|
|
_groupItemElements: function($group) {
|
|
return $group.find("." + LIST_ITEM_CLASS)
|
|
},
|
|
isItemIndex: function(index) {
|
|
return $.isNumeric(index.group) && $.isNumeric(index.item)
|
|
},
|
|
getItemElementIndex: function(itemElement) {
|
|
var $item = $(itemElement),
|
|
$group = $item.closest("." + LIST_GROUP_CLASS);
|
|
return combineIndex({
|
|
group: this._groupElements().index($group),
|
|
item: this._groupItemElements($group).index($item)
|
|
})
|
|
},
|
|
normalizeItemIndex: function(index) {
|
|
return combineIndex(index)
|
|
},
|
|
deleteItemAtIndex: function(index) {
|
|
var indices = splitIndex(index),
|
|
itemGroup = this._list.option("items")[indices.group].items;
|
|
itemGroup.splice(indices.item, 1)
|
|
},
|
|
updateSelectionAfterDelete: function(fromIndex) {
|
|
var deletedIndices = splitIndex(fromIndex),
|
|
selectedItemIndices = this._list._selectedItemIndices;
|
|
$.each(selectedItemIndices, function(i, index) {
|
|
var indices = splitIndex(index);
|
|
if (indices.group === deletedIndices.group && indices.item > deletedIndices.item)
|
|
selectedItemIndices[i] -= 1
|
|
})
|
|
},
|
|
fetchSelectedItems: function() {
|
|
var items = this._list.option("items"),
|
|
selectedItemIndices = this._list._selectedItemIndices,
|
|
selectedItems = [];
|
|
selectedItemIndices.sort(function(a, b) {
|
|
return a - b
|
|
});
|
|
var currentGroupIndex = 0,
|
|
groupSelectedIndices = [];
|
|
$.each(selectedItemIndices, function(_, combinedIndex) {
|
|
var index = splitIndex(combinedIndex);
|
|
if (index.group !== currentGroupIndex && groupSelectedIndices.length) {
|
|
selectedItems.push(createGroupSelection(items[currentGroupIndex], groupSelectedIndices));
|
|
groupSelectedIndices.length = 0
|
|
}
|
|
currentGroupIndex = index.group;
|
|
groupSelectedIndices.push(index.item)
|
|
});
|
|
if (groupSelectedIndices.length)
|
|
selectedItems.push(createGroupSelection(items[currentGroupIndex], groupSelectedIndices));
|
|
return selectedItems
|
|
},
|
|
selectedItemIndecies: function() {
|
|
var selectedIndices = [],
|
|
items = this._list.option("items"),
|
|
selected = this._list.option("selectedItems");
|
|
$.each(selected, function(_, selectionInGroup) {
|
|
var group = groupByKey(items, selectionInGroup.key),
|
|
groupIndex = $.inArray(group, items);
|
|
if (!group)
|
|
throw new Error("Group with key '" + selectionInGroup.key + "' in which you are trying to select items does not exist.");
|
|
$.each(selectionInGroup.items, function(_, selectedGroupItem) {
|
|
var itemIndex = $.inArray(selectedGroupItem, group.items);
|
|
if (itemIndex !== -1)
|
|
selectedIndices.push(combineIndex({
|
|
group: groupIndex,
|
|
item: itemIndex
|
|
}));
|
|
else
|
|
throw new Error("Item '" + selectedGroupItem + "' you are trying to select in group '" + selectionInGroup.key + "' does not exist");
|
|
})
|
|
});
|
|
return selectedIndices
|
|
},
|
|
getItemByIndex: function(index) {
|
|
var indices = splitIndex(index),
|
|
$group = this._groupElements().eq(indices.group);
|
|
return this._groupItemElements($group).eq(indices.item)
|
|
}
|
|
});
|
|
var removeDublicates = function(a, b) {
|
|
var c = [];
|
|
$.each(a, function(_, value) {
|
|
var bIndex = $.inArray(value, b);
|
|
if (bIndex === -1)
|
|
c.push(value)
|
|
});
|
|
return c
|
|
};
|
|
var LIST_CLASS = "dx-list",
|
|
LIST_ITEM_CLASS = "dx-list-item",
|
|
LIST_ITEM_SELECTOR = "." + LIST_ITEM_CLASS,
|
|
LIST_GROUP_CLASS = "dx-list-group",
|
|
LIST_GROUP_HEADER_CLASS = "dx-list-group-header",
|
|
LIST_HAS_NEXT_CLASS = "dx-has-next",
|
|
LIST_NEXT_BUTTON_CLASS = "dx-list-next-button",
|
|
LIST_EDITING_CLASS = "dx-list-editing",
|
|
LIST_ITEM_SELECTED_CLASS = "dx-list-item-selected",
|
|
LIST_ITEM_RESPONSE_WAIT_CLASS = "dx-list-item-response-wait",
|
|
LIST_ITEM_DATA_KEY = "dxListItemData",
|
|
LIST_FEEDBACK_SHOW_TIMEOUT = 70;
|
|
ui.registerComponent("dxList", ui.CollectionContainerWidget.inherit({
|
|
_activeStateUnit: LIST_ITEM_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
pullRefreshEnabled: false,
|
|
autoPagingEnabled: true,
|
|
scrollingEnabled: true,
|
|
showScrollbar: true,
|
|
useNativeScrolling: true,
|
|
pullingDownText: Globalize.localize("dxList-pullingDownText"),
|
|
pulledDownText: Globalize.localize("dxList-pulledDownText"),
|
|
refreshingText: Globalize.localize("dxList-refreshingText"),
|
|
pageLoadingText: Globalize.localize("dxList-pageLoadingText"),
|
|
scrollAction: null,
|
|
pullRefreshAction: null,
|
|
pageLoadingAction: null,
|
|
showNextButton: false,
|
|
itemHoldAction: null,
|
|
itemHoldTimeout: 750,
|
|
itemSwipeAction: null,
|
|
grouped: false,
|
|
groupTemplate: "group",
|
|
groupRender: null,
|
|
editEnabled: false,
|
|
editConfig: {
|
|
itemTemplate: null,
|
|
itemRender: null,
|
|
deleteEnabled: false,
|
|
deleteMode: "toggle",
|
|
selectionEnabled: false,
|
|
selectionMode: "item"
|
|
},
|
|
itemDeleteAction: null,
|
|
selectedItems: [],
|
|
itemSelectAction: null,
|
|
itemUnselectAction: null
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return LIST_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return LIST_ITEM_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$container
|
|
},
|
|
_allowDinamicItemsAppend: function() {
|
|
return true
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._$container = this._element();
|
|
this._initScrollView();
|
|
this._initEditProvider();
|
|
this._initEditStrategy(this.option("grouped"));
|
|
this._initSelectedItems();
|
|
this._feedbackShowTimeout = LIST_FEEDBACK_SHOW_TIMEOUT
|
|
},
|
|
_initSelectedItems: function() {
|
|
this._selectedItemIndices = this._editStrategy.selectedItemIndecies()
|
|
},
|
|
_clearSelectedItems: function() {
|
|
this._selectedItemIndices = [];
|
|
this._updateSelectedItems()
|
|
},
|
|
_dataSourceOptions: function() {
|
|
return $.extend(this.callBase(), {paginate: true})
|
|
},
|
|
_initScrollView: function() {
|
|
var scrollingEnabled = this.option("scrollingEnabled"),
|
|
pullRefreshEnabled = scrollingEnabled && this.option("pullRefreshEnabled"),
|
|
autoPagingEnabled = scrollingEnabled && this.option("autoPagingEnabled") && !!this._dataSource;
|
|
var $scrollView = this._element().dxScrollView({
|
|
disabled: this.option("disabled") || !scrollingEnabled,
|
|
scrollAction: $.proxy(this._handleScroll, this),
|
|
pullDownAction: pullRefreshEnabled ? $.proxy(this._handlePullDown, this) : null,
|
|
reachBottomAction: autoPagingEnabled ? $.proxy(this._handleScrollBottom, this) : null,
|
|
showScrollbar: this.option("showScrollbar"),
|
|
useNative: this.option("useNativeScrolling"),
|
|
pullingDownText: this.option("pullingDownText"),
|
|
pulledDownText: this.option("pulledDownText"),
|
|
refreshingText: this.option("refreshingText"),
|
|
reachBottomText: this.option("pageLoadingText")
|
|
});
|
|
this._scrollView = $scrollView.dxScrollView("instance");
|
|
this._scrollView.toggleLoading(autoPagingEnabled);
|
|
this._$container = this._scrollView.content();
|
|
this._createScrollViewActions()
|
|
},
|
|
_createScrollViewActions: function() {
|
|
this._scrollAction = this._createActionByOption("scrollAction", {excludeValidators: ["gesture"]});
|
|
this._pullRefreshAction = this._createActionByOption("pullRefreshAction", {excludeValidators: ["gesture"]});
|
|
this._pageLoadingAction = this._createActionByOption("pageLoadingAction", {excludeValidators: ["gesture"]})
|
|
},
|
|
_handleScroll: function(e) {
|
|
this._scrollAction(e)
|
|
},
|
|
_afterItemsRendered: function(tryLoadMore) {
|
|
var isLastPage = this._isLastPage(),
|
|
allDataLoaded = !tryLoadMore || isLastPage,
|
|
autoPagingEnabled = this.option("autoPagingEnabled"),
|
|
stopLoading = !autoPagingEnabled || allDataLoaded,
|
|
scrollViewIsFull = this._scrollViewIsFull();
|
|
if (stopLoading || scrollViewIsFull) {
|
|
this._scrollView.release(stopLoading);
|
|
if (this._shouldRenderNextButton() && this._dataSource.isLoaded())
|
|
this._toggleNextButton(!allDataLoaded)
|
|
}
|
|
else
|
|
this._infiniteDataLoading()
|
|
},
|
|
_isLastPage: function() {
|
|
return !this._dataSource || this._dataSource.isLastPage()
|
|
},
|
|
_scrollViewIsFull: function() {
|
|
return !this._scrollView || this._scrollView.isFull()
|
|
},
|
|
_handlePullDown: function(e) {
|
|
this._pullRefreshAction(e);
|
|
if (this._dataSource && !this._dataSource.isLoading()) {
|
|
this._dataSource.pageIndex(0);
|
|
this._dataSource.load()
|
|
}
|
|
else
|
|
this._afterItemsRendered()
|
|
},
|
|
_infiniteDataLoading: function() {
|
|
var dataSource = this._dataSource;
|
|
if (!this._scrollViewIsFull() && dataSource && !dataSource.isLoading() && !this._isLastPage())
|
|
DX.utils.executeAsync(this._loadNextPage, this)
|
|
},
|
|
_handleScrollBottom: function(e) {
|
|
this._pageLoadingAction(e);
|
|
var dataSource = this._dataSource;
|
|
if (dataSource && !dataSource.isLoading())
|
|
this._loadNextPage();
|
|
else
|
|
this._afterItemsRendered()
|
|
},
|
|
_loadNextPage: function() {
|
|
var dataSource = this._dataSource;
|
|
this._expectNextPageLoading();
|
|
dataSource.pageIndex(1 + dataSource.pageIndex());
|
|
return dataSource.load()
|
|
},
|
|
_renderItems: function(items) {
|
|
if (this.option("grouped")) {
|
|
$.each(items, $.proxy(this._renderGroup, this));
|
|
this._renderEmptyMessage()
|
|
}
|
|
else
|
|
this.callBase.apply(this, arguments);
|
|
this._afterItemsRendered(true)
|
|
},
|
|
_handleDataSourceLoadError: function() {
|
|
this.callBase.apply(this, arguments);
|
|
if (this._initialized)
|
|
this._afterItemsRendered()
|
|
},
|
|
_initEditProvider: function() {
|
|
if (this._editProvider)
|
|
this._editProvider.dispose();
|
|
this._editProvider = new ui.ListEditProvider(this, this.option("editConfig"))
|
|
},
|
|
_initEditStrategy: function(grouped) {
|
|
var strategy = grouped ? GroupedListEditStrategy : PlainListEditStrategy;
|
|
this._editStrategy = new strategy(this)
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(LIST_CLASS);
|
|
this._renderEditing();
|
|
this.callBase();
|
|
this._attachHoldEvent();
|
|
this._attachSwipeEvent()
|
|
},
|
|
_attachClickEvent: function() {
|
|
var self = this,
|
|
eventName = events.addNamespace("dxclick", this.NAME),
|
|
itemSelector = this._itemSelector();
|
|
this._itemContainer().off(eventName, itemSelector).on(eventName, itemSelector, $.proxy(this._handleItemClick, this))
|
|
},
|
|
_attachHoldEvent: function() {
|
|
var $element = this._element(),
|
|
eventName = events.addNamespace("dxhold", this.NAME),
|
|
itemSelector = this._itemSelector();
|
|
$element.off(eventName, itemSelector);
|
|
if (this.option("itemHoldAction") || this._editProvider.holdHandlerExists())
|
|
$element.on(eventName, itemSelector, {timeout: this.option("itemHoldTimeout")}, $.proxy(this._handleItemHold, this))
|
|
},
|
|
_attachSwipeEvent: function() {
|
|
var $element = this._element(),
|
|
eventName = events.addNamespace("dxswipeend", this.NAME),
|
|
itemSelector = this._itemSelector();
|
|
$element.off(eventName, itemSelector);
|
|
if (this.option("itemSwipeAction"))
|
|
$element.on(eventName, itemSelector, $.proxy(this._handleItemSwipe, this))
|
|
},
|
|
_renderEditing: function() {
|
|
this._element().toggleClass(LIST_EDITING_CLASS, this.option("editEnabled"))
|
|
},
|
|
_shouldRenderNextButton: function() {
|
|
return this.option("showNextButton") && this._dataSource
|
|
},
|
|
_getNextButton: function() {
|
|
if (!this._nextButton)
|
|
this._nextButton = this._createNextButton();
|
|
return this._nextButton
|
|
},
|
|
_createNextButton: function() {
|
|
var $buttonContainer = $("<div/>").addClass(LIST_NEXT_BUTTON_CLASS),
|
|
$button = $("<div/>").dxButton({
|
|
text: "More",
|
|
clickAction: $.proxy(this._handleNextButton, this)
|
|
});
|
|
return $buttonContainer.append($button)
|
|
},
|
|
_handleItemClick: function(e) {
|
|
if (!(this.option("editEnabled") && this._editProvider.handleClick(this._closestItemElement(e.target))))
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
_handleItemHold: function(e) {
|
|
if (!(this.option("editEnabled") && this._editProvider.handleHold(this._closestItemElement(e.target))))
|
|
this._handleItemJQueryEvent(e, "itemHoldAction")
|
|
},
|
|
_handleItemSwipe: function(e) {
|
|
this._handleItemJQueryEvent(e, "itemSwipeAction", {direction: e.offset < 0 ? "left" : "right"}, {excludeValidators: ["gesture"]})
|
|
},
|
|
_getItemRenderer: function() {
|
|
if (this.option("editEnabled") && this._editProvider.isRenderingByRenderer())
|
|
return this._editProvider.getItemRenderer();
|
|
return this.callBase()
|
|
},
|
|
_getItemTemplateName: function() {
|
|
if (this.option("editEnabled") && this._editProvider.isRenderingByTemplate())
|
|
return this._editProvider.getItemTemplateName();
|
|
return this.callBase()
|
|
},
|
|
_postprocessRenderItem: function(args) {
|
|
var $itemElement = $(args.itemElement);
|
|
if (this.option("editEnabled")) {
|
|
if (this._isItemSelected(this._getItemIndex($itemElement)))
|
|
$itemElement.addClass(LIST_ITEM_SELECTED_CLASS);
|
|
if (this._editProvider.isModifyingByDecorators())
|
|
this._editProvider.modifyItemElement(args)
|
|
}
|
|
},
|
|
_handleNextButton: function() {
|
|
var source = this._dataSource;
|
|
if (source && !source.isLoading()) {
|
|
this._scrollView.toggleLoading(true);
|
|
this._expectNextPageLoading();
|
|
source.pageIndex(1 + source.pageIndex());
|
|
source.load();
|
|
this._nextButton.detach()
|
|
}
|
|
},
|
|
_groupRenderDefault: function(group) {
|
|
return String(group.key || group)
|
|
},
|
|
_renderGroup: function(index, group) {
|
|
var self = this;
|
|
var groupElement = $("<div />").addClass(LIST_GROUP_CLASS).appendTo(self._itemContainer());
|
|
var groupRenderer = self.option("groupRender"),
|
|
groupTemplateName = self.option("groupTemplate"),
|
|
groupTemplate = self._getTemplate(group.template || groupTemplateName, index, group),
|
|
groupHeaderElement,
|
|
renderArgs = {
|
|
index: index,
|
|
group: group,
|
|
container: groupElement
|
|
};
|
|
if (groupRenderer)
|
|
groupHeaderElement = self._createGroupByRenderer(groupRenderer, renderArgs);
|
|
else if (groupTemplate)
|
|
groupHeaderElement = self._createGroupByTemplate(groupTemplate, renderArgs);
|
|
else
|
|
groupHeaderElement = self._createGroupByRenderer(self._groupRenderDefault, renderArgs);
|
|
groupHeaderElement.addClass(LIST_GROUP_HEADER_CLASS);
|
|
this._renderingGroupIndex = index;
|
|
$.each(group.items || [], function(index, item) {
|
|
self._renderItem(index, item, groupElement)
|
|
})
|
|
},
|
|
_createGroupByRenderer: function(groupRenderer, renderArgs) {
|
|
var groupElement = $("<div />").appendTo(renderArgs.container);
|
|
var rendererResult = groupRenderer(renderArgs.group, renderArgs.index, groupElement);
|
|
if (rendererResult && groupElement[0] !== rendererResult[0])
|
|
groupElement.append(rendererResult);
|
|
return groupElement
|
|
},
|
|
_createGroupByTemplate: function(groupTemplate, renderArgs) {
|
|
return groupTemplate.render(renderArgs.container, renderArgs.group)
|
|
},
|
|
_clean: function() {
|
|
this._toggleNextButton(false);
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
_dispose: function() {
|
|
clearTimeout(this._holdTimer);
|
|
this.callBase()
|
|
},
|
|
_toggleNextButton: function(value) {
|
|
var dataSource = this._dataSource,
|
|
nextButton = this._getNextButton();
|
|
this._element().toggleClass(LIST_HAS_NEXT_CLASS, value);
|
|
if (value && dataSource && dataSource.isLoaded())
|
|
nextButton.appendTo(this._itemContainer());
|
|
if (!value)
|
|
nextButton.detach()
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"showNextButton":
|
|
this._toggleNextButton(value);
|
|
break;
|
|
case"itemHoldAction":
|
|
case"itemHoldTimeout":
|
|
this._attachHoldEvent();
|
|
break;
|
|
case"dataSource":
|
|
this.callBase.apply(this, arguments);
|
|
this._initScrollView();
|
|
break;
|
|
case"showScrollbar":
|
|
case"scrollingEnabled":
|
|
case"pullRefreshEnabled":
|
|
case"autoPagingEnabled":
|
|
this._initScrollView();
|
|
break;
|
|
case"selectedItems":
|
|
if (!this._selectedItemsInternalChange)
|
|
this._refreshSelectedItems();
|
|
break;
|
|
case"itemSwipeAction":
|
|
this._attachSwipeEvent();
|
|
break;
|
|
case"scrollAction":
|
|
case"pullRefresAction":
|
|
case"pageLoadingAction":
|
|
this._createScrollViewActions();
|
|
this._invalidate();
|
|
break;
|
|
case"grouped":
|
|
this._clearSelectedItems();
|
|
delete this._renderingGroupIndex;
|
|
this._initEditStrategy(value);
|
|
this._invalidate();
|
|
break;
|
|
case"items":
|
|
case"editEnabled":
|
|
this._clearSelectedItems();
|
|
this._invalidate();
|
|
break;
|
|
case"editConfig":
|
|
this._initEditProvider();
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_getItemIndex: function(itemElement) {
|
|
if (this._editStrategy.isItemIndex(itemElement))
|
|
return this._editStrategy.normalizeItemIndex(itemElement);
|
|
return this._editStrategy.getItemElementIndex(itemElement)
|
|
},
|
|
_getItemElement: function(index) {
|
|
if (this._editStrategy.isItemIndex(index))
|
|
return this._editStrategy.getItemByIndex(this._editStrategy.normalizeItemIndex(index));
|
|
return $(index)
|
|
},
|
|
_isItemSelected: function(index) {
|
|
return $.inArray(index, this._selectedItemIndices) > -1
|
|
},
|
|
_updateSelectedItems: function() {
|
|
this._selectedItemsInternalChange = true;
|
|
this.option("selectedItems", this._editStrategy.fetchSelectedItems());
|
|
this._selectedItemsInternalChange = false
|
|
},
|
|
_updateSelectionAfterDelete: function(fromIndex) {
|
|
var self = this,
|
|
itemIndex = $.inArray(fromIndex, this._selectedItemIndices);
|
|
if (itemIndex > -1)
|
|
this._selectedItemIndices.splice(itemIndex, 1);
|
|
this._editStrategy.updateSelectionAfterDelete(fromIndex);
|
|
this._updateSelectedItems()
|
|
},
|
|
_selectItem: function($itemElement) {
|
|
var index = this._getItemIndex($itemElement);
|
|
if (this.option("editEnabled") && index > -1) {
|
|
$itemElement.addClass(LIST_ITEM_SELECTED_CLASS);
|
|
this._selectedItemIndices.push(index);
|
|
$itemElement.trigger("stateChanged");
|
|
this._updateSelectedItems();
|
|
this._handleItemEvent($itemElement, "itemSelectAction")
|
|
}
|
|
},
|
|
_unselectItem: function($itemElement) {
|
|
var itemSelectionIndex = $.inArray(this._getItemIndex($itemElement), this._selectedItemIndices);
|
|
if (this.option("editEnabled") && itemSelectionIndex > -1) {
|
|
$itemElement.removeClass(LIST_ITEM_SELECTED_CLASS);
|
|
this._selectedItemIndices.splice(itemSelectionIndex, 1);
|
|
$itemElement.trigger("stateChanged");
|
|
this._updateSelectedItems();
|
|
this._handleItemEvent($itemElement, "itemUnselectAction")
|
|
}
|
|
},
|
|
_refreshSelectedItems: function() {
|
|
var self = this,
|
|
newSelection = this._editStrategy.selectedItemIndecies();
|
|
var unselected = removeDublicates(this._selectedItemIndices, newSelection);
|
|
$.each(unselected, function(_, index) {
|
|
var $itemElement = self._editStrategy.getItemByIndex(index);
|
|
self._unselectItem($itemElement)
|
|
});
|
|
var selected = removeDublicates(newSelection, this._selectedItemIndices);
|
|
$.each(selected, function(_, index) {
|
|
var $itemElement = self._editStrategy.getItemByIndex(index);
|
|
self._selectItem($itemElement)
|
|
})
|
|
},
|
|
_deleteItemFromDS: function($item) {
|
|
var self = this,
|
|
deferred = $.Deferred(),
|
|
disabledState = this.option("disabled"),
|
|
dataStore = this._dataSource.store();
|
|
this.option("disabled", true);
|
|
if (!dataStore.remove)
|
|
throw new Error("You have to implement 'remove' method in dataStore used by dxList to be able to delete items");
|
|
dataStore.remove(dataStore.keyOf(this._getItemData($item))).done(function(key) {
|
|
if (key !== undefined)
|
|
deferred.resolveWith(self);
|
|
else
|
|
deferred.rejectWith(self)
|
|
}).fail(function() {
|
|
deferred.rejectWith(self)
|
|
});
|
|
deferred.always(function() {
|
|
self.option("disabled", disabledState)
|
|
});
|
|
return deferred
|
|
},
|
|
_refreshLastPage: function() {
|
|
this._expectLastItemLoading();
|
|
return this._dataSource.load()
|
|
},
|
|
deleteItem: function(itemElement) {
|
|
var self = this,
|
|
deferred = $.Deferred(),
|
|
$item = this._getItemElement(itemElement),
|
|
index = this._getItemIndex(itemElement),
|
|
changingOption;
|
|
if (this.option("editEnabled") && index > -1) {
|
|
$item.addClass(LIST_ITEM_RESPONSE_WAIT_CLASS);
|
|
if (this._dataSource) {
|
|
changingOption = "dataSource";
|
|
deferred = this._deleteItemFromDS($item)
|
|
}
|
|
else {
|
|
changingOption = "items";
|
|
deferred.resolveWith(this)
|
|
}
|
|
}
|
|
else
|
|
deferred.rejectWith(this);
|
|
deferred.done(function() {
|
|
$item.detach();
|
|
self._editStrategy.deleteItemAtIndex(index);
|
|
self.optionChanged.fireWith(self, [changingOption, self.option(changingOption)]);
|
|
self._updateSelectionAfterDelete(index);
|
|
self._handleItemEvent($item, "itemDeleteAction", {}, {excludeValidators: ["gesture"]});
|
|
self._renderEmptyMessage()
|
|
}).fail(function() {
|
|
$item.removeClass(LIST_ITEM_RESPONSE_WAIT_CLASS)
|
|
});
|
|
if (this._isLastPage() || this.option("grouped"))
|
|
return deferred.promise();
|
|
var newDeferred = $.Deferred();
|
|
deferred.done(function() {
|
|
self._refreshLastPage().done(function() {
|
|
newDeferred.resolveWith(self)
|
|
})
|
|
});
|
|
deferred.fail(function() {
|
|
newDeferred.rejectWith(self)
|
|
});
|
|
return newDeferred.promise()
|
|
},
|
|
isItemSelected: function(itemElement) {
|
|
return this._isItemSelected(this._getItemIndex(itemElement))
|
|
},
|
|
selectItem: function(itemElement) {
|
|
this._selectItem(this._getItemElement(itemElement))
|
|
},
|
|
unselectItem: function(itemElement) {
|
|
this._unselectItem(this._getItemElement(itemElement))
|
|
},
|
|
update: function() {
|
|
var self = this,
|
|
deferred = $.Deferred();
|
|
if (self._scrollView)
|
|
self._scrollView.update().done(function() {
|
|
deferred.resolveWith(self)
|
|
});
|
|
else
|
|
deferred.resolveWith(self);
|
|
return deferred.promise()
|
|
},
|
|
scrollTop: function() {
|
|
return this._scrollView.scrollOffset().top
|
|
},
|
|
clientHeight: function() {
|
|
return this._scrollView.clientHeight()
|
|
},
|
|
scrollHeight: function() {
|
|
return this._scrollView.scrollHeight()
|
|
},
|
|
scrollBy: function(distance) {
|
|
this._scrollView.scrollBy(distance)
|
|
},
|
|
scrollTo: function(location) {
|
|
this._scrollView.scrollTo(location)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.tileView.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils;
|
|
var TILEVIEW_CLASS = "dx-tileview",
|
|
TILEVIEW_WRAPPER_CLASS = "dx-tiles-wrapper",
|
|
TILEVIEW_ITEM_CLASS = "dx-tile",
|
|
TILEVIEW_ITEM_SELECTOR = "." + TILEVIEW_ITEM_CLASS,
|
|
TILEVIEW_ITEM_DATA_KEY = "dxTileData";
|
|
ui.registerComponent("dxTileView", ui.CollectionContainerWidget.inherit({
|
|
_activeStateUnit: TILEVIEW_ITEM_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
items: null,
|
|
showScrollbar: false,
|
|
listHeight: 500,
|
|
baseItemWidth: 100,
|
|
baseItemHeight: 100,
|
|
itemMargin: 20
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return TILEVIEW_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return TILEVIEW_ITEM_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$wrapper
|
|
},
|
|
_init: function() {
|
|
var self = this;
|
|
self.callBase();
|
|
self._refreshHandler = function() {
|
|
self._renderGeometry()
|
|
};
|
|
utils.windowResizeCallbacks.add(self._refreshHandler)
|
|
},
|
|
_dispose: function() {
|
|
this.callBase();
|
|
utils.windowResizeCallbacks.remove(this._refreshHandler)
|
|
},
|
|
_render: function() {
|
|
this.cellsPerColumn = 1;
|
|
this._element().addClass(TILEVIEW_CLASS);
|
|
this._renderListHeight();
|
|
if (!this._$wrapper)
|
|
this._renderWrapper();
|
|
this._initScrollable();
|
|
this.callBase();
|
|
this._renderGeometry();
|
|
this._fireContentReadyAction()
|
|
},
|
|
_renderListHeight: function() {
|
|
this._element().height(this.option("listHeight"))
|
|
},
|
|
_renderContent: function() {
|
|
this._renderContentImpl()
|
|
},
|
|
_renderWrapper: function() {
|
|
this._$wrapper = $("<div />").addClass(TILEVIEW_WRAPPER_CLASS).appendTo(this._element())
|
|
},
|
|
_initScrollable: function() {
|
|
this._scrollView = this._element().dxScrollable({
|
|
direction: "horizontal",
|
|
showScrollbar: this.option("showScrollbar"),
|
|
disabled: this.option("disabled")
|
|
}).data("dxScrollable")
|
|
},
|
|
_renderGeometry: function() {
|
|
var items = this.option("items") || [],
|
|
maxItemHeight = Math.max.apply(Math, $.map(items || [], function(item) {
|
|
return Math.round(item.heightRatio || 1)
|
|
}));
|
|
this.cellsPerColumn = Math.floor(this._element().height() / (this.option("baseItemHeight") + this.option("itemMargin")));
|
|
this.cellsPerColumn = Math.max(this.cellsPerColumn, maxItemHeight);
|
|
this.cells = [];
|
|
this.cells.push(new Array(this.cellsPerColumn));
|
|
this._arrangeItems(items);
|
|
this._$wrapper.width(this.cells.length * this.option("baseItemWidth") + (this.cells.length + 1) * this.option("itemMargin"))
|
|
},
|
|
_arrangeItems: function(items) {
|
|
var self = this;
|
|
$.each(items, function(index, item) {
|
|
var currentItem = {};
|
|
currentItem.widthRatio = item.widthRatio || 1;
|
|
currentItem.heightRatio = item.heightRatio || 1;
|
|
currentItem.text = item.text || "";
|
|
currentItem.widthRatio = currentItem.widthRatio <= 0 ? 0 : Math.round(currentItem.widthRatio);
|
|
currentItem.heightRatio = currentItem.heightRatio <= 0 ? 0 : Math.round(currentItem.heightRatio);
|
|
var $item = self._itemElements().eq(index),
|
|
itemPosition = self._getItemPosition(currentItem);
|
|
if (itemPosition.x === -1)
|
|
itemPosition.x = self.cells.push(new Array(this.cellsPerColumn)) - 1;
|
|
self._occupyCells(currentItem, itemPosition);
|
|
self._arrangeItem($item, currentItem, itemPosition)
|
|
})
|
|
},
|
|
_getItemPosition: function(item) {
|
|
var position = {
|
|
x: -1,
|
|
y: 0
|
|
};
|
|
for (var col = 0; col < this.cells.length; col++) {
|
|
for (var row = 0; row < this.cellsPerColumn; row++)
|
|
if (this._itemFit(col, row, item)) {
|
|
position.x = col;
|
|
position.y = row;
|
|
break
|
|
}
|
|
if (position.x > -1)
|
|
break
|
|
}
|
|
return position
|
|
},
|
|
_itemFit: function(column, row, item) {
|
|
var result = true;
|
|
if (row + item.heightRatio > this.cellsPerColumn)
|
|
return false;
|
|
for (var columnIndex = column; columnIndex < column + item.widthRatio; columnIndex++)
|
|
for (var rowIndex = row; rowIndex < row + item.heightRatio; rowIndex++)
|
|
if (this.cells.length - 1 < columnIndex)
|
|
this.cells.push(new Array(this.cellsPerColumn));
|
|
else if (this.cells[columnIndex][rowIndex]) {
|
|
result = false;
|
|
break
|
|
}
|
|
return result
|
|
},
|
|
_occupyCells: function(item, itemPosition) {
|
|
for (var i = itemPosition.x; i < itemPosition.x + item.widthRatio; i++)
|
|
for (var j = itemPosition.y; j < itemPosition.y + item.heightRatio; j++)
|
|
this.cells[i][j] = true
|
|
},
|
|
_arrangeItem: function($item, item, itemPosition) {
|
|
var baseItemHeight = this.option("baseItemHeight"),
|
|
baseItemWidth = this.option("baseItemWidth"),
|
|
itemMargin = this.option("itemMargin");
|
|
$item.css({
|
|
height: item.heightRatio * baseItemHeight + (item.heightRatio - 1) * itemMargin,
|
|
width: item.widthRatio * baseItemWidth + (item.widthRatio - 1) * itemMargin,
|
|
top: itemPosition.y * baseItemHeight + (itemPosition.y + 1) * itemMargin,
|
|
left: itemPosition.x * baseItemWidth + (itemPosition.x + 1) * itemMargin,
|
|
display: item.widthRatio <= 0 || item.heightRatio <= 0 ? "none" : ""
|
|
})
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"showScrollbar":
|
|
this._initScrollable();
|
|
break;
|
|
case"disabled":
|
|
this._scrollView.option("disabled", value);
|
|
break;
|
|
case"baseItemWidth":
|
|
case"baseItemHeight":
|
|
case"itemMargin":
|
|
this._renderGeometry();
|
|
break;
|
|
case"listHeight":
|
|
this._renderListHeight();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.gallery.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils,
|
|
events = ui.events,
|
|
fx = DX.fx,
|
|
translator = DX.translator,
|
|
GALLERY_CLASS = "dx-gallery",
|
|
GALLERY_LOOP_CLASS = "dx-gallery-loop",
|
|
GALLERY_ITEM_CONTAINER_CLASS = GALLERY_CLASS + "-wrapper",
|
|
GALLERY_ITEM_CLASS = GALLERY_CLASS + "-item",
|
|
GALLERY_LOOP_ITEM_CLASS = GALLERY_ITEM_CLASS + "-loop",
|
|
GALLERY_ITEM_SELECTOR = "." + GALLERY_ITEM_CLASS,
|
|
GALLERY_ITEM_SELECTED_CLASS = GALLERY_ITEM_CLASS + "-selected",
|
|
GALLERY_INDICATOR_CLASS = GALLERY_CLASS + "-indicator",
|
|
GALLERY_INDICATOR_ITEM_CLASS = GALLERY_INDICATOR_CLASS + "-item",
|
|
GALLERY_INDICATOR_ITEM_SELECTOR = "." + GALLERY_INDICATOR_ITEM_CLASS,
|
|
GALLERY_INDICATOR_ITEM_SELECTED_CLASS = GALLERY_INDICATOR_ITEM_CLASS + "-selected",
|
|
GALLERY_ITEM_DATA_KEY = "dxGalleryItemData";
|
|
ui.registerComponent("dxGalleryNavButton", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {direction: "next"})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(GALLERY_CLASS + "-nav-button-" + this.option("direction"))
|
|
}
|
|
}));
|
|
ui.registerComponent("dxGallery", ui.CollectionContainerWidget.inherit({
|
|
_activeStateUnit: GALLERY_ITEM_SELECTOR,
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
animationDuration: 400,
|
|
loop: false,
|
|
swipeEnabled: true,
|
|
indicatorEnabled: true,
|
|
showIndicator: true,
|
|
selectedIndex: 0,
|
|
slideshowDelay: 0,
|
|
showNavButtons: false
|
|
})
|
|
},
|
|
_dataSourceOptions: function() {
|
|
return {paginate: false}
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$container
|
|
},
|
|
_itemClass: function() {
|
|
return GALLERY_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return GALLERY_ITEM_DATA_KEY
|
|
},
|
|
_itemWidth: function() {
|
|
return this._itemElements().first().outerWidth()
|
|
},
|
|
_itemsCount: function() {
|
|
return (this.option("items") || []).length
|
|
},
|
|
_itemRenderDefault: function(item, index, itemElement) {
|
|
this.callBase(item, index, itemElement);
|
|
if (!$.isPlainObject(item))
|
|
itemElement.append($("<img />").attr("src", String(item)))
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(GALLERY_CLASS);
|
|
this._element().toggleClass(GALLERY_LOOP_CLASS, this.option("loop"));
|
|
this._renderDragHandler();
|
|
this._renderItemContainer();
|
|
this.callBase();
|
|
this._renderContainerPosition();
|
|
this._renderItemPositions();
|
|
this._renderIndicator();
|
|
this._renderSelectedIndicatorItem();
|
|
this._renderUserInteraction();
|
|
this._renderNavButtons();
|
|
this._setupSlideShow();
|
|
this._reviseDimensions();
|
|
this._windowResizeCallback = $.proxy(this._handleResize, this);
|
|
utils.windowResizeCallbacks.add(this._windowResizeCallback)
|
|
},
|
|
_renderDragHandler: function() {
|
|
var eventName = events.addNamespace("dragstart", this.NAME);
|
|
this._element().off(eventName).on(eventName, "img", function() {
|
|
return false
|
|
})
|
|
},
|
|
_renderItems: function(items) {
|
|
this.callBase(items);
|
|
this._renderDuplicateItems()
|
|
},
|
|
_renderItemContainer: function() {
|
|
if (this._$container)
|
|
return;
|
|
this._$container = $("<div />").addClass(GALLERY_ITEM_CONTAINER_CLASS).appendTo(this._element())
|
|
},
|
|
_renderDuplicateItems: function() {
|
|
var items = this.option("items") || [],
|
|
itemsCount = items.length;
|
|
if (!itemsCount)
|
|
return;
|
|
this._element().find("." + GALLERY_LOOP_ITEM_CLASS).remove();
|
|
var itemsPerPage = this._element().width() / this._itemWidth(),
|
|
duplicateCount = Math.min(itemsPerPage, itemsCount);
|
|
for (var i = 0; i < duplicateCount; i++)
|
|
this._renderItem(0, items[i]).addClass(GALLERY_LOOP_ITEM_CLASS);
|
|
this._renderItem(0, items[this._itemsCount() - 1]).addClass(GALLERY_LOOP_ITEM_CLASS)
|
|
},
|
|
_handleResize: function() {
|
|
this._renderDuplicateItems();
|
|
this._renderItemPositions();
|
|
this._renderContainerPosition()
|
|
},
|
|
_renderItemPositions: function() {
|
|
var itemWidth = this._itemWidth(),
|
|
loopItemsCount = this._element().find("." + GALLERY_LOOP_ITEM_CLASS).length,
|
|
lastItemDuplicateIndex = this._itemsCount() + loopItemsCount - 1;
|
|
this._itemElements().each(function(index) {
|
|
var realIndex = index;
|
|
if (index === lastItemDuplicateIndex)
|
|
realIndex = -1;
|
|
translator.move($(this), {left: realIndex * itemWidth})
|
|
})
|
|
},
|
|
_renderContainerPosition: function(offset, animate) {
|
|
offset = offset || 0;
|
|
var self = this,
|
|
itemWidth = this._itemWidth(),
|
|
selectedIndex = this.option("selectedIndex"),
|
|
animationDuration = this.option("animationDuration"),
|
|
targetIndex = offset - selectedIndex,
|
|
d = $.Deferred(),
|
|
animationPromises = [];
|
|
if (animate)
|
|
animationPromises.push(fx.animate(this._$container, {
|
|
type: "slide",
|
|
to: {left: targetIndex * itemWidth},
|
|
duration: animationDuration
|
|
}));
|
|
else
|
|
translator.move(this._$container, {left: targetIndex * itemWidth});
|
|
$.when.apply($, animationPromises).done(function() {
|
|
d.resolveWith(self)
|
|
});
|
|
return d.promise()
|
|
},
|
|
_reviseDimensions: function() {
|
|
var self = this,
|
|
$firstItem = self._itemElements().first();
|
|
if (!$firstItem)
|
|
return;
|
|
if (!self.option("height"))
|
|
self.option("height", $firstItem.outerHeight());
|
|
if (!self.option("width"))
|
|
self.option("width", $firstItem.outerWidth())
|
|
},
|
|
_renderIndicator: function() {
|
|
if (!this.option("showIndicator")) {
|
|
this._cleanIndicators();
|
|
return
|
|
}
|
|
var indicator = this._$indicator = $("<div />").addClass(GALLERY_INDICATOR_CLASS).appendTo(this._element());
|
|
$.each(this.option("items") || [], function() {
|
|
$("<div />").addClass(GALLERY_INDICATOR_ITEM_CLASS).appendTo(indicator)
|
|
})
|
|
},
|
|
_cleanIndicators: function() {
|
|
if (this._$indicator)
|
|
this._$indicator.remove()
|
|
},
|
|
_renderSelectedIndicatorItem: function() {
|
|
var selectedIndex = this.option("selectedIndex");
|
|
this._itemElements().removeClass(GALLERY_ITEM_SELECTED_CLASS).eq(selectedIndex).addClass(GALLERY_ITEM_SELECTED_CLASS);
|
|
this._element().find(GALLERY_INDICATOR_ITEM_SELECTOR).removeClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS).eq(selectedIndex).addClass(GALLERY_INDICATOR_ITEM_SELECTED_CLASS)
|
|
},
|
|
_renderUserInteraction: function() {
|
|
var self = this,
|
|
rootElement = self._element(),
|
|
swipeEnabled = self.option("swipeEnabled") && this._itemsCount() > 1,
|
|
cursor = swipeEnabled ? "pointer" : "default";
|
|
rootElement.dxSwipeable({
|
|
startAction: swipeEnabled ? $.proxy(self._handleSwipeStart, self) : function(e) {
|
|
e.jQueryEvent.cancel = true
|
|
},
|
|
disabled: this.option("disabled"),
|
|
updateAction: $.proxy(self._handleSwipeUpdate, self),
|
|
endAction: $.proxy(self._handleSwipeEnd, self),
|
|
itemWidthFunc: $.proxy(self._itemWidth, self)
|
|
});
|
|
var indicatorSelectAction = this._createAction(this._handleIndicatorSelect);
|
|
rootElement.find(GALLERY_INDICATOR_ITEM_SELECTOR).css({cursor: cursor}).off(events.addNamespace("dxclick", this.NAME)).on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
indicatorSelectAction({jQueryEvent: e})
|
|
})
|
|
},
|
|
_handleIndicatorSelect: function(args) {
|
|
var e = args.jQueryEvent,
|
|
instance = args.component;
|
|
if (events.needSkipEvent(e))
|
|
return;
|
|
if (!instance.option("indicatorEnabled"))
|
|
return;
|
|
var index = $(e.target).index();
|
|
instance._renderContainerPosition(instance.option("selectedIndex") - index, true).done(function() {
|
|
this._suppressRenderItemPositions = true;
|
|
instance.option("selectedIndex", index)
|
|
})
|
|
},
|
|
_renderNavButtons: function() {
|
|
var self = this;
|
|
if (!self.option("showNavButtons")) {
|
|
self._cleanNavButtons();
|
|
return
|
|
}
|
|
self._prevNavButton = $("<div />").dxGalleryNavButton({
|
|
direction: "prev",
|
|
clickAction: function() {
|
|
self.prevItem(true)
|
|
}
|
|
}).appendTo(this._element());
|
|
self._nextNavButton = $("<div />").dxGalleryNavButton({
|
|
direction: "next",
|
|
clickAction: function() {
|
|
self.nextItem(true)
|
|
}
|
|
}).appendTo(this._element());
|
|
this._renderNavButtonsVisibility()
|
|
},
|
|
_cleanNavButtons: function() {
|
|
if (this._prevNavButton)
|
|
this._prevNavButton.remove();
|
|
if (this._prevNavButton)
|
|
this._nextNavButton.remove()
|
|
},
|
|
_renderNavButtonsVisibility: function() {
|
|
if (!this.option("showNavButtons"))
|
|
return;
|
|
var selectedIndex = this.option("selectedIndex"),
|
|
loop = this.option("loop"),
|
|
itemsCount = this._itemsCount();
|
|
if (selectedIndex < itemsCount && selectedIndex > 0 || loop) {
|
|
this._prevNavButton.show();
|
|
this._nextNavButton.show()
|
|
}
|
|
if (this._itemsCount() < 2) {
|
|
this._prevNavButton.hide();
|
|
this._nextNavButton.hide()
|
|
}
|
|
if (!loop) {
|
|
if (selectedIndex < 1)
|
|
this._prevNavButton.hide();
|
|
if (selectedIndex === itemsCount - 1)
|
|
this._nextNavButton.hide()
|
|
}
|
|
},
|
|
_setupSlideShow: function() {
|
|
var self = this,
|
|
slideshowDelay = self.option("slideshowDelay");
|
|
if (!slideshowDelay)
|
|
return;
|
|
clearTimeout(self._slideshowTimer);
|
|
self._slideshowTimer = setTimeout(function() {
|
|
if (self._userInteraction) {
|
|
self._setupSlideShow();
|
|
return
|
|
}
|
|
self.nextItem(true).done(self._setupSlideShow)
|
|
}, slideshowDelay)
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
var itemsCount = this._itemsCount();
|
|
if (!itemsCount) {
|
|
e.jQueryEvent.cancel = true;
|
|
return
|
|
}
|
|
this._stopItemAnimations();
|
|
this._userInteraction = true;
|
|
if (!this.option("loop")) {
|
|
var selectedIndex = this.option("selectedIndex");
|
|
e.jQueryEvent.maxLeftOffset = itemsCount - selectedIndex - 1;
|
|
e.jQueryEvent.maxRightOffset = selectedIndex
|
|
}
|
|
},
|
|
_stopItemAnimations: function() {
|
|
if (fx.animating(this._$container))
|
|
fx.stop(this._$container, true)
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
this._renderContainerPosition(e.jQueryEvent.offset)
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
this._renderContainerPosition(e.jQueryEvent.targetOffset, true).done(function() {
|
|
var selectedIndex = this.option("selectedIndex"),
|
|
newIndex = this._fitIndex(selectedIndex - e.jQueryEvent.targetOffset);
|
|
this._suppressRenderItemPositions = true;
|
|
this.option("selectedIndex", newIndex);
|
|
this._renderContainerPosition();
|
|
this._userInteraction = false;
|
|
this._setupSlideShow()
|
|
})
|
|
},
|
|
_flipIndex: function(index) {
|
|
if (!this.option("loop"))
|
|
return index;
|
|
var itemsCount = this._itemsCount();
|
|
index = index % itemsCount;
|
|
if (index > (itemsCount + 1) / 2)
|
|
index -= itemsCount;
|
|
if (index < -(itemsCount - 1) / 2)
|
|
index += itemsCount;
|
|
return index
|
|
},
|
|
_fitIndex: function(index) {
|
|
if (!this.option("loop"))
|
|
return index;
|
|
var itemsCount = this._itemsCount();
|
|
index = index % itemsCount;
|
|
if (index < 0)
|
|
index += itemsCount;
|
|
return index
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._cleanIndicators();
|
|
this._cleanNavButtons()
|
|
},
|
|
_dispose: function() {
|
|
utils.windowResizeCallbacks.remove(this._windowResizeCallback);
|
|
clearTimeout(this._slideshowTimer);
|
|
this.callBase()
|
|
},
|
|
_handleSelectedIndexChanged: function() {
|
|
if (!this._suppressRenderItemPositions)
|
|
this._renderContainerPosition();
|
|
this._suppressRenderItemPositions = false;
|
|
this._renderSelectedIndicatorItem();
|
|
this._renderNavButtonsVisibility()
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"width":
|
|
this.callBase(name, value, prevValue);
|
|
this._handleResize();
|
|
break;
|
|
case"animationDuration":
|
|
this._renderNavButtonsVisibility();
|
|
break;
|
|
case"loop":
|
|
this._element().toggleClass(GALLERY_LOOP_CLASS, value);
|
|
this._renderNavButtonsVisibility();
|
|
return;
|
|
case"selectedIndex":
|
|
this._handleSelectedIndexChanged();
|
|
return;
|
|
case"showIndicator":
|
|
this._renderIndicator();
|
|
return;
|
|
case"showNavButtons":
|
|
this._renderNavButtons();
|
|
return;
|
|
case"slideshowDelay":
|
|
this._setupSlideShow();
|
|
return;
|
|
case"swipeEnabled":
|
|
case"indicatorEnabled":
|
|
this._renderUserInteraction();
|
|
return;
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
},
|
|
goToItem: function(itemIndex, animation) {
|
|
var d = new $.Deferred,
|
|
selectedIndex = this.option("selectedIndex"),
|
|
itemsCount = this._itemsCount();
|
|
itemIndex = this._fitIndex(itemIndex);
|
|
if (itemIndex > itemsCount - 1 || itemIndex < 0)
|
|
return d.resolveWith(this).promise();
|
|
this._renderContainerPosition(selectedIndex - itemIndex, animation).done(function() {
|
|
this._suppressRenderItemPositions = true;
|
|
this.option("selectedIndex", itemIndex);
|
|
d.resolveWith(this)
|
|
});
|
|
return d.promise()
|
|
},
|
|
prevItem: function(animation) {
|
|
return this.goToItem(this.option("selectedIndex") - 1, animation)
|
|
},
|
|
nextItem: function(animation) {
|
|
return this.goToItem(this.option("selectedIndex") + 1, animation)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.overlay.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils,
|
|
events = ui.events;
|
|
var OVERLAY_CLASS = "dx-overlay",
|
|
OVERLAY_WRAPPER_CLASS = OVERLAY_CLASS + "-wrapper",
|
|
OVERLAY_CONTENT_CLASS = OVERLAY_CLASS + "-content",
|
|
OVERLAY_SHADER_CLASS = OVERLAY_CLASS + "-shader",
|
|
OVERLAY_MODAL_CLASS = OVERLAY_CLASS + "-modal",
|
|
OVERLAY_SHOW_EVENT_TOLERANCE = 500,
|
|
ACTIONS = ["showingAction", "shownAction", "hidingAction", "hiddenAction", "positioningAction", "positionedAction"],
|
|
LAST_Z_INDEX = 1000,
|
|
DISABLED_STATE_CLASS = "dx-state-disabled";
|
|
ui.registerComponent("dxOverlay", ui.ContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
activeStateEnabled: false,
|
|
visible: false,
|
|
shading: true,
|
|
closeOnOutsideClick: false,
|
|
closeOnTargetScroll: false,
|
|
position: {
|
|
my: "center",
|
|
at: "center",
|
|
of: window
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "pop",
|
|
duration: 400
|
|
},
|
|
hide: {
|
|
type: "pop",
|
|
duration: 400,
|
|
to: {
|
|
opacity: 0,
|
|
scale: 0
|
|
},
|
|
from: {
|
|
opacity: 1,
|
|
scale: 1
|
|
}
|
|
}
|
|
},
|
|
showingAction: null,
|
|
shownAction: null,
|
|
hidingAction: null,
|
|
hiddenAction: null,
|
|
width: function() {
|
|
return $(window).width() * 0.8
|
|
},
|
|
height: function() {
|
|
return $(window).height() * 0.8
|
|
},
|
|
deferRendering: true,
|
|
disabled: false,
|
|
targetContainer: undefined,
|
|
positioningAction: null,
|
|
positionedAction: null
|
|
})
|
|
},
|
|
_optionsByReference: function() {
|
|
return $.extend(this.callBase(), {animation: true})
|
|
},
|
|
_wrapper: function() {
|
|
return this._$wrapper
|
|
},
|
|
_clickEventContainer: function() {
|
|
return this._$container
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._actions = {};
|
|
this._deferredAnimate = undefined;
|
|
this._attachCloseOnOutsideClickHandler();
|
|
this._windowResizeCallback = $.proxy(this._repaint, this);
|
|
utils.windowResizeCallbacks.add(this._windowResizeCallback);
|
|
this._$wrapper = $("<div>").addClass(OVERLAY_WRAPPER_CLASS)
|
|
},
|
|
_initOptions: function(options) {
|
|
this._setTargetContainer(options.targetContainer);
|
|
this._backButtonHandler = options.backButtonHandler !== undefined ? this.backButtonHandler : this._defaultBackButtonHandler;
|
|
this.callBase(options)
|
|
},
|
|
_setTargetContainer: function(targetContainer) {
|
|
targetContainer = targetContainer === undefined ? DX.overlayTargetContainer() : targetContainer;
|
|
var $element = this._element(),
|
|
$targetContainer = $element.closest(targetContainer);
|
|
if (!$targetContainer.length)
|
|
$targetContainer = $(targetContainer).first();
|
|
this._$targetContainer = $targetContainer.length ? $targetContainer : $element.parent()
|
|
},
|
|
_closeOnOutsideClickHandler: function(e) {
|
|
var closeOnOutsideClick = this.option("closeOnOutsideClick"),
|
|
visible = this.option("visible");
|
|
if ($.isFunction(closeOnOutsideClick))
|
|
closeOnOutsideClick = closeOnOutsideClick(e);
|
|
if (closeOnOutsideClick && visible) {
|
|
var $container = this._$container,
|
|
outsideClick = !$container.is(e.target) && !$.contains($container.get(0), e.target),
|
|
showingEvent = Math.abs(e.timeStamp - this._showTimestamp) < OVERLAY_SHOW_EVENT_TOLERANCE;
|
|
if (outsideClick && !showingEvent)
|
|
this.hide()
|
|
}
|
|
},
|
|
_attachCloseOnOutsideClickHandler: function() {
|
|
var self = this,
|
|
eventNames = events.addNamespace("dxpointerdown", self.NAME);
|
|
this._myCloseOnOutsideClickHandler = function() {
|
|
return self._closeOnOutsideClickHandler.apply(self, arguments)
|
|
};
|
|
$(document).on(eventNames, this._myCloseOnOutsideClickHandler)
|
|
},
|
|
_detachCloseOnOutsideClickHandler: function() {
|
|
var eventNames = events.addNamespace("dxpointerdown", this.NAME);
|
|
$(document).off(eventNames, this._myCloseOnOutsideClickHandler)
|
|
},
|
|
_render: function() {
|
|
var $element = this._element(),
|
|
deferRendering = this.option("deferRendering");
|
|
this._$container = $("<div>").addClass(OVERLAY_CONTENT_CLASS);
|
|
this._$wrapper.addClass($element.attr("class"));
|
|
this._renderActions();
|
|
this.callBase();
|
|
this._renderStyles();
|
|
$element.addClass(OVERLAY_CLASS)
|
|
},
|
|
_renderStyles: function() {
|
|
this._renderShader();
|
|
this._renderModalState();
|
|
this._renderDimensions();
|
|
this._renderVisibility()
|
|
},
|
|
_renderShader: function() {
|
|
this._$wrapper.toggleClass(OVERLAY_SHADER_CLASS, this.option("shading"))
|
|
},
|
|
_renderModalState: function() {
|
|
this._$wrapper.toggleClass(OVERLAY_MODAL_CLASS, this.option("shading") && !this.option("targetContainer"))
|
|
},
|
|
_renderDimensions: function() {
|
|
this._$container.width(this.option("width")).height(this.option("height"))
|
|
},
|
|
_renderVisibility: function() {
|
|
var visible = this.option("visible");
|
|
DX.fx.stop(this._$container, true);
|
|
if (visible) {
|
|
this._renderContent();
|
|
this._renderPosition()
|
|
}
|
|
this._toggleVisibility(visible)
|
|
},
|
|
_renderActions: function() {
|
|
var self = this;
|
|
$.each(ACTIONS, function(_, itemAction) {
|
|
self._actions[itemAction] = self._createActionByOption(itemAction)
|
|
})
|
|
},
|
|
_renderContent: function() {
|
|
if (this._contentAlreadyRendered || !this.option("visible") && this.option("deferRendering"))
|
|
return;
|
|
this._contentAlreadyRendered = true;
|
|
this._moveFromTargetContainer();
|
|
this.callBase()
|
|
},
|
|
_moveFromTargetContainer: function() {
|
|
this._$container.appendTo(this._element());
|
|
this._detachWrapperToTargetContainer()
|
|
},
|
|
_detachWrapperToTargetContainer: function() {
|
|
this._$wrapper.detach()
|
|
},
|
|
_renderContentImpl: function(template) {
|
|
this._renderInnerContent(template);
|
|
this._moveToTargetContainer()
|
|
},
|
|
_renderInnerContent: function(template) {
|
|
var $element = this._element();
|
|
this._$container.append($element.contents()).appendTo($element);
|
|
(template || this._templates.template).render(this.content())
|
|
},
|
|
_moveToTargetContainer: function() {
|
|
this._attachWrapperToTargetContainer();
|
|
this._$container.appendTo(this._$wrapper)
|
|
},
|
|
_attachWrapperToTargetContainer: function() {
|
|
var $element = this._element();
|
|
if (this._$targetContainer && !(this._$targetContainer[0] === $element.parent()[0]))
|
|
this._$wrapper.appendTo(this._$targetContainer);
|
|
else
|
|
this._$wrapper.appendTo($element)
|
|
},
|
|
_renderPosition: function() {
|
|
var position = this.option("position");
|
|
if (this.option("shading")) {
|
|
var $wrapper = this._$wrapper.show(),
|
|
$positionOf = $(position.of);
|
|
DX.position($wrapper, {
|
|
my: "top left",
|
|
at: "top left",
|
|
of: $positionOf
|
|
});
|
|
$wrapper.css({
|
|
width: $positionOf.outerWidth(),
|
|
height: $positionOf.outerHeight()
|
|
})
|
|
}
|
|
this._$container.css("transform", "none");
|
|
var containerPosition = DX.calculatePosition(this._$container, position);
|
|
this._actions.positioningAction({position: containerPosition});
|
|
var resultPosition = DX.position(this._$container, containerPosition);
|
|
this._actions.positionedAction({position: resultPosition})
|
|
},
|
|
_subscribeParentScroll: function() {
|
|
var self = this,
|
|
closeOnScroll = this.option("closeOnTargetScroll"),
|
|
position = this.option("position");
|
|
if (!closeOnScroll || !position || !position.of)
|
|
return;
|
|
$(position.of).parents().on(events.addNamespace("scroll", self.NAME), function(e) {
|
|
if (e.overlayProcessed)
|
|
return;
|
|
e.overlayProcessed = true;
|
|
self.hide()
|
|
})
|
|
},
|
|
_unsubscribeParentScroll: function() {
|
|
var self = this,
|
|
closeOnScroll = this.option("closeOnTargetScroll"),
|
|
position = this.option("position");
|
|
if (!closeOnScroll || !position || !position.of)
|
|
return;
|
|
$(position.of).parents().off(events.addNamespace("scroll", self.NAME))
|
|
},
|
|
_clean: function() {
|
|
delete this._contentAlreadyRendered
|
|
},
|
|
_refresh: function() {
|
|
this._renderStyles()
|
|
},
|
|
_repaint: function() {
|
|
if (!this.option("visible"))
|
|
return;
|
|
this._renderDimensions();
|
|
this._renderPosition()
|
|
},
|
|
_dispose: function() {
|
|
DX.fx.stop(this._$container);
|
|
utils.windowResizeCallbacks.remove(this._windowResizeCallback);
|
|
if (this.closeCallback)
|
|
DX.backButtonCallback.remove(this.closeCallback);
|
|
this._detachCloseOnOutsideClickHandler();
|
|
this._actions = null;
|
|
this.callBase();
|
|
this._$wrapper.remove();
|
|
this._$container.remove()
|
|
},
|
|
_renderVisibilityAnimate: function() {
|
|
var visible = this.option("visible");
|
|
if (visible)
|
|
this._showTimestamp = $.now();
|
|
DX.fx.stop(this._$container, true);
|
|
if (visible)
|
|
this._makeVisible();
|
|
else
|
|
this._makeHidden()
|
|
},
|
|
_makeVisible: function() {
|
|
var self = this,
|
|
animation = self.option("animation") || {};
|
|
this._$wrapper.css("z-index", ++LAST_Z_INDEX);
|
|
this._actions.showingAction();
|
|
this._toggleVisibility(true);
|
|
this._renderContent();
|
|
this._renderPosition();
|
|
if (animation.show) {
|
|
var animationComplete = animation.show.complete || $.noop;
|
|
self._animate($.extend({}, animation.show, {complete: function() {
|
|
animationComplete.apply(this, arguments);
|
|
self._notifyShowComplete()
|
|
}}))
|
|
}
|
|
else
|
|
self._notifyShowComplete()
|
|
},
|
|
_notifyShowComplete: function() {
|
|
this._actions.shownAction();
|
|
if (this._deferredAnimate)
|
|
this._deferredAnimate.resolveWith(this)
|
|
},
|
|
_makeHidden: function() {
|
|
var self = this,
|
|
animation = this.option("animation") || {};
|
|
this._actions.hidingAction();
|
|
this._$wrapper.toggleClass(OVERLAY_SHADER_CLASS, false);
|
|
if (animation.hide) {
|
|
var animationComplete = animation.hide.complete || $.noop;
|
|
self._animate($.extend({}, animation.hide, {complete: function() {
|
|
self._toggleVisibility(false);
|
|
animationComplete.apply(this, arguments);
|
|
self._notifyHideComplete()
|
|
}}))
|
|
}
|
|
else {
|
|
self._toggleVisibility(false);
|
|
self._notifyHideComplete()
|
|
}
|
|
},
|
|
_notifyHideComplete: function() {
|
|
this._actions.hiddenAction();
|
|
if (this._deferredAnimate)
|
|
this._deferredAnimate.resolveWith(this)
|
|
},
|
|
_animate: function(animation) {
|
|
if ($.isPlainObject(animation))
|
|
DX.fx.animate(this._$container, animation)
|
|
},
|
|
_toggleVisibility: function(visible) {
|
|
if (visible) {
|
|
this._moveToTargetContainer();
|
|
this._subscribeParentScroll()
|
|
}
|
|
this._$container.toggle(visible);
|
|
if (!visible) {
|
|
this._moveFromTargetContainer();
|
|
this._unsubscribeParentScroll()
|
|
}
|
|
this._$wrapper.toggleClass(OVERLAY_SHADER_CLASS, this.option("shading") && visible)
|
|
},
|
|
_defaultBackButtonHandler: function() {
|
|
this.hide()
|
|
},
|
|
_toggleBackButtonCallback: function() {
|
|
if (this._backButtonHandler)
|
|
if (this.option("visible")) {
|
|
this.closeCallback = $.proxy(this._backButtonHandler, this);
|
|
DX.backButtonCallback.add(this.closeCallback)
|
|
}
|
|
else if (this.closeCallback)
|
|
DX.backButtonCallback.remove(this.closeCallback)
|
|
},
|
|
_toggleDisabledState: function(value) {
|
|
this.callBase.apply(this, arguments);
|
|
this._$container.toggleClass(DISABLED_STATE_CLASS, value)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
if ($.inArray(name, ACTIONS) > -1) {
|
|
this._renderActions();
|
|
return
|
|
}
|
|
switch (name) {
|
|
case"position":
|
|
if (this.option("visible"))
|
|
this._renderPosition();
|
|
break;
|
|
case"visible":
|
|
this._toggleBackButtonCallback();
|
|
this._renderVisibilityAnimate();
|
|
break;
|
|
case"targetContainer":
|
|
this._setTargetContainer(value);
|
|
this._moveToTargetContainer();
|
|
this._renderStyles();
|
|
break;
|
|
case"closeOnOutsideClick":
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
toggle: function(showing) {
|
|
showing = showing === undefined ? !this.option("visible") : showing;
|
|
if (showing === this.option("visible"))
|
|
return $.Deferred().resolve().promise();
|
|
this._deferredAnimate = $.Deferred();
|
|
this.option("visible", showing);
|
|
return this._deferredAnimate.promise()
|
|
},
|
|
show: function() {
|
|
return this.toggle(true)
|
|
},
|
|
hide: function() {
|
|
return this.toggle(false)
|
|
},
|
|
content: function() {
|
|
return this._$container
|
|
},
|
|
repaint: function() {
|
|
this._repaint()
|
|
}
|
|
}));
|
|
ui.dxOverlay.__internals = {
|
|
OVERLAY_SHOW_EVENT_TOLERANCE: OVERLAY_SHOW_EVENT_TOLERANCE,
|
|
OVERLAY_CLASS: OVERLAY_CLASS,
|
|
OVERLAY_WRAPPER_CLASS: OVERLAY_WRAPPER_CLASS,
|
|
OVERLAY_CONTENT_CLASS: OVERLAY_CONTENT_CLASS,
|
|
OVERLAY_SHADER_CLASS: OVERLAY_SHADER_CLASS,
|
|
OVERLAY_MODAL_CLASS: OVERLAY_MODAL_CLASS
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.toast.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var TOAST_CLASS = "dx-toast",
|
|
TOAST_CLASS_PREFIX = TOAST_CLASS + "-",
|
|
TOAST_WRAPPER_CLASS = TOAST_CLASS_PREFIX + "wrapper",
|
|
TOAST_CONTENT_CLASS = TOAST_CLASS_PREFIX + "content",
|
|
TOAST_MESSAGE_CLASS = TOAST_CLASS_PREFIX + "message",
|
|
TOAST_ICON_CLASS = TOAST_CLASS_PREFIX + "icon",
|
|
WIDGET_NAME = "dxToast",
|
|
toastTypes = ["info", "warning", "error", "success"];
|
|
ui.registerComponent(WIDGET_NAME, ui.dxOverlay.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
message: "",
|
|
type: "info",
|
|
displayTime: 2000,
|
|
position: {
|
|
my: "bottom center",
|
|
at: "bottom center",
|
|
of: window,
|
|
offset: "0 -20"
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "fade",
|
|
duration: 400,
|
|
from: 0,
|
|
to: 1
|
|
},
|
|
hide: {
|
|
type: "fade",
|
|
duration: 400,
|
|
to: 0
|
|
}
|
|
},
|
|
shading: false,
|
|
disabled: false,
|
|
height: "auto"
|
|
})
|
|
},
|
|
_renderContentImpl: function() {
|
|
if (this.option("message"))
|
|
this._message = $("<div>").addClass(TOAST_MESSAGE_CLASS).text(this.option("message")).appendTo(this.content());
|
|
if ($.inArray(this.option("type").toLowerCase(), toastTypes) > -1)
|
|
this.content().prepend($("<div>").addClass(TOAST_ICON_CLASS));
|
|
this.callBase()
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(TOAST_CLASS);
|
|
this._wrapper().addClass(TOAST_WRAPPER_CLASS);
|
|
this._$container.addClass(TOAST_CLASS_PREFIX + String(this.option("type")).toLowerCase());
|
|
this.content().addClass(TOAST_CONTENT_CLASS)
|
|
},
|
|
_notifyShowComplete: function() {
|
|
this.callBase();
|
|
clearTimeout(this._hideTimeout);
|
|
this._hideTimeout = setTimeout($.proxy(function() {
|
|
this.hide()
|
|
}, this), this.option("displayTime"))
|
|
},
|
|
_dispose: function() {
|
|
clearTimeout(this._hideTimeout);
|
|
this.callBase()
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"type":
|
|
this._$container.removeClass(TOAST_CLASS_PREFIX + prevValue);
|
|
this._$container.addClass(TOAST_CLASS_PREFIX + String(value).toLowerCase());
|
|
break;
|
|
case"message":
|
|
if (this._message)
|
|
this._message.text(value);
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}));
|
|
ui.dxToast.__internals = {
|
|
TOAST_CLASS: TOAST_CLASS,
|
|
TOAST_WRAPPER_CLASS: TOAST_WRAPPER_CLASS,
|
|
TOAST_CONTENT_CLASS: TOAST_CONTENT_CLASS,
|
|
TOAST_MESSAGE_CLASS: TOAST_MESSAGE_CLASS,
|
|
TOAST_ICON_CLASS: TOAST_ICON_CLASS,
|
|
TOAST_CLASS_PREFIX: TOAST_CLASS_PREFIX,
|
|
WIDGET_NAME: WIDGET_NAME
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.popup.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var POPUP_CLASS = "dx-popup",
|
|
POPUP_WRAPPER_CLASS = POPUP_CLASS + "-wrapper",
|
|
POPUP_FULL_SCREEN_CLASS = POPUP_CLASS + "-fullscreen",
|
|
POPUP_CONTENT_CLASS = POPUP_CLASS + "-content",
|
|
POPUP_TITLE_CLASS = POPUP_CLASS + "-title",
|
|
POPUP_TITLE_SELECTOR = "." + POPUP_TITLE_CLASS,
|
|
POPUP_TITLE_CLOSEBUTTON_CLASS = "dx-closebutton",
|
|
POPUP_BOTTOM_CLASS = "dx-popup-bottom",
|
|
TOOLBAR_LEFT_CLASS = "dx-toolbar-left",
|
|
TOOLBAR_RIGHT_CLASS = "dx-toolbar-right",
|
|
OVERLAY_CONTENT_SELECTOR = ".dx-overlay-content";
|
|
var getButtonContainer = function(force) {
|
|
var device = DX.devices.current(force),
|
|
container = {
|
|
cancel: {subclass: "dx-popup-cancel"},
|
|
clear: {subclass: "dx-popup-clear"},
|
|
done: {subclass: "dx-popup-done"}
|
|
};
|
|
if (device.ios) {
|
|
$.extend(container.cancel, {
|
|
parent: POPUP_TITLE_SELECTOR,
|
|
wraperClass: TOOLBAR_LEFT_CLASS
|
|
});
|
|
$.extend(container.clear, {
|
|
parent: POPUP_TITLE_SELECTOR,
|
|
wraperClass: TOOLBAR_RIGHT_CLASS
|
|
});
|
|
$.extend(container.done, {
|
|
parent: OVERLAY_CONTENT_SELECTOR,
|
|
wraperClass: POPUP_BOTTOM_CLASS
|
|
})
|
|
}
|
|
if (device.android || device.platform === "desktop" || device.win8 || device.tizen || device.generic) {
|
|
$.extend(container.cancel, {
|
|
parent: OVERLAY_CONTENT_SELECTOR,
|
|
wraperClass: POPUP_BOTTOM_CLASS
|
|
});
|
|
$.extend(container.clear, {
|
|
parent: OVERLAY_CONTENT_SELECTOR,
|
|
wraperClass: POPUP_BOTTOM_CLASS
|
|
});
|
|
$.extend(container.done, {
|
|
parent: OVERLAY_CONTENT_SELECTOR,
|
|
wraperClass: POPUP_BOTTOM_CLASS
|
|
})
|
|
}
|
|
return container
|
|
};
|
|
ui.registerComponent("dxPopup", ui.dxOverlay.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
title: "",
|
|
showTitle: true,
|
|
fullScreen: false,
|
|
cancelButton: null,
|
|
doneButton: null,
|
|
clearButton: null,
|
|
closeButton: null
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(POPUP_CLASS);
|
|
this._wrapper().addClass(POPUP_WRAPPER_CLASS);
|
|
this._setContentHeight()
|
|
},
|
|
_renderDimensions: function() {
|
|
if (this.option("fullScreen")) {
|
|
this._wrapper().css({
|
|
width: "100%",
|
|
height: "100%"
|
|
});
|
|
this._$container.css({
|
|
width: "100%",
|
|
height: "100%"
|
|
})
|
|
}
|
|
else
|
|
this.callBase()
|
|
},
|
|
_renderPosition: function() {
|
|
if (this.option("fullScreen"))
|
|
this._$container.position(0, 0);
|
|
else
|
|
this.callBase()
|
|
},
|
|
_renderContentImpl: function() {
|
|
this._$container.toggleClass(POPUP_FULL_SCREEN_CLASS, this.option("fullScreen"));
|
|
this._$content = this._$container.wrapInner($("<div />").addClass(POPUP_CONTENT_CLASS)).children().eq(0);
|
|
this.callBase(this._templates.content);
|
|
this._renderTitle();
|
|
this._renderCloseButton();
|
|
this._renderCancelButton();
|
|
this._renderClearButton();
|
|
this._renderDoneButton()
|
|
},
|
|
_renderContent: function() {
|
|
this.callBase();
|
|
this._setContentHeight()
|
|
},
|
|
_setContentHeight: function() {
|
|
if (!this._$content)
|
|
return;
|
|
var contentHeight = this._$container.height(),
|
|
hasBottomButtons = this.option("cancelButton") || this.option("doneButton") || this.option("clearButton"),
|
|
$bottomButtons = this._$wrapper.find(".dx-popup-bottom");
|
|
if (this._$title)
|
|
contentHeight -= this._$title.outerHeight(true) || 0;
|
|
if (hasBottomButtons) {
|
|
var bottomButtonsMargin = $bottomButtons.outerHeight(true) || 0;
|
|
contentHeight -= bottomButtonsMargin;
|
|
this._$content.css("margin-bottom", bottomButtonsMargin)
|
|
}
|
|
if (this.option("height") === "auto")
|
|
this._$content.css("height", "auto");
|
|
else if (contentHeight > 0)
|
|
this._$content.css("height", contentHeight)
|
|
},
|
|
_renderTitle: function() {
|
|
if (this.option("showTitle")) {
|
|
this._$title = this._$title || $("<div />").addClass(POPUP_TITLE_CLASS);
|
|
this._element().append(this._$title);
|
|
var titleTemplate = this._templates.title;
|
|
if (titleTemplate)
|
|
titleTemplate.render(this._$title);
|
|
else
|
|
this._defaultTitleRender();
|
|
this._$title.prependTo(this._$container)
|
|
}
|
|
else if (this._$title)
|
|
this._$title.detach()
|
|
},
|
|
_defaultTitleRender: function() {
|
|
this._$title.text(this.option("title"))
|
|
},
|
|
_renderCloseButton: function() {
|
|
if (!this._templates.title && this.option("closeButton") && this.option("showTitle")) {
|
|
var clickAction = this._createButtonAction();
|
|
$("<div/>").addClass(POPUP_TITLE_CLOSEBUTTON_CLASS).on(ui.events.addNamespace("dxclick", this.NAME + "TitleCloseButton"), function(e) {
|
|
clickAction({jQueryEvent: e})
|
|
}).appendTo(this._$title)
|
|
}
|
|
},
|
|
_renderCancelButton: function() {
|
|
this._renderSpecificButton(this.option("cancelButton"), {
|
|
type: "cancel",
|
|
text: Globalize.localize("Cancel")
|
|
})
|
|
},
|
|
_renderClearButton: function() {
|
|
this._renderSpecificButton(this.option("clearButton"), {
|
|
type: "clear",
|
|
text: Globalize.localize("Clear")
|
|
})
|
|
},
|
|
_renderDoneButton: function() {
|
|
this._renderSpecificButton(this.option("doneButton"), {
|
|
type: "done",
|
|
text: Globalize.localize("Done")
|
|
})
|
|
},
|
|
_renderSpecificButton: function(show, buttonConfig) {
|
|
var renderParams = this._getRenderButtonParams(buttonConfig.type);
|
|
this._removeButton(renderParams);
|
|
this._wrapper().toggleClass(POPUP_CLASS + "-" + buttonConfig.type + "-visible", !!show);
|
|
if (!show)
|
|
return;
|
|
var userButtonOptions = this.option(buttonConfig.type + "Button");
|
|
this._renderButton({
|
|
text: userButtonOptions.text || buttonConfig.text,
|
|
clickAction: this._createButtonAction(userButtonOptions.clickAction)
|
|
}, renderParams)
|
|
},
|
|
_createButtonAction: function(clickAction) {
|
|
return this._createAction(clickAction, {afterExecute: function(e) {
|
|
e.component.hide()
|
|
}})
|
|
},
|
|
_getRenderButtonParams: function(type) {
|
|
return $.extend({parent: this.content()}, getButtonContainer()[type])
|
|
},
|
|
_renderButton: function(buttonParams, renderParams) {
|
|
var $button = $("<div/>").addClass(renderParams.subclass).dxButton(buttonParams),
|
|
$parentContainer = this._wrapper().find(renderParams.parent),
|
|
$buttonContainer = this._wrapper().find("." + renderParams.wraperClass);
|
|
if (!$buttonContainer.length)
|
|
$buttonContainer = $("<div/>").addClass(renderParams.wraperClass).appendTo($parentContainer);
|
|
$button.appendTo($buttonContainer);
|
|
this._wrapper().find("." + POPUP_BOTTOM_CLASS).addClass(renderParams.subclass)
|
|
},
|
|
_removeButton: function(params) {
|
|
var removeSelector = "." + (params.subclass || params.wraperClass);
|
|
if (this.content())
|
|
this.content().removeClass(params.subclass);
|
|
this._wrapper().find(removeSelector).remove()
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"showTitle":
|
|
case"title":
|
|
this._renderTitle();
|
|
this._renderCloseButton();
|
|
this._setContentHeight();
|
|
break;
|
|
case"cancelButton":
|
|
this._renderCancelButton();
|
|
break;
|
|
case"clearButton":
|
|
this._renderClearButton();
|
|
break;
|
|
case"doneButton":
|
|
this._renderDoneButton();
|
|
break;
|
|
case"closeButton":
|
|
this._renderCloseButton();
|
|
break;
|
|
case"height":
|
|
this.callBase.apply(this, arguments);
|
|
this._setContentHeight();
|
|
break;
|
|
case"fullScreen":
|
|
this._$container.toggleClass(POPUP_FULL_SCREEN_CLASS, value);
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
content: function() {
|
|
return this._$content
|
|
}
|
|
}));
|
|
ui.dxPopup.__internals = {
|
|
POPUP_CLASS: POPUP_CLASS,
|
|
POPUP_WRAPPER_CLASS: POPUP_WRAPPER_CLASS,
|
|
POPUP_CONTENT_CLASS: POPUP_CONTENT_CLASS,
|
|
POPUP_FULL_SCREEN_CLASS: POPUP_FULL_SCREEN_CLASS,
|
|
POPUP_TITLE_CLASS: POPUP_TITLE_CLASS,
|
|
POPUP_TITLE_CLOSEBUTTON_CLASS: POPUP_TITLE_CLOSEBUTTON_CLASS
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.popover.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var POPOVER_CLASS = "dx-popover",
|
|
POPOVER_WRAPPER_CLASS = "dx-popover-wrapper",
|
|
ARROW_CLASS = "dx-popover-arrow",
|
|
ARROW_FLIPPED_CLASS = "dx-popover-arrow-flipped",
|
|
POPOVER_WITHOUT_TITLE_CLASS = "dx-popover-without-title";
|
|
ui.registerComponent("dxPopover", ui.dxPopup.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
target: window,
|
|
shading: false,
|
|
position: {
|
|
my: "top center",
|
|
at: "bottom center",
|
|
collision: "fit flip"
|
|
},
|
|
closeOnOutsideClick: $.proxy(this._isOutsideClick, this),
|
|
animation: {
|
|
show: {
|
|
type: "fade",
|
|
to: 1
|
|
},
|
|
hide: {
|
|
type: "fade",
|
|
to: 0
|
|
}
|
|
},
|
|
showTitle: false,
|
|
width: "auto",
|
|
height: "auto"
|
|
})
|
|
},
|
|
_render: function() {
|
|
this._$arrow = $("<div>").addClass(ARROW_CLASS);
|
|
this.callBase();
|
|
this._element().addClass(POPOVER_CLASS);
|
|
this._wrapper().addClass(POPOVER_WRAPPER_CLASS);
|
|
this._renderTarget()
|
|
},
|
|
_renderContentImpl: function() {
|
|
this.callBase();
|
|
this._$arrow.appendTo(this._wrapper());
|
|
this._updateContentSize()
|
|
},
|
|
_updateContentSize: function() {
|
|
if (!this._$content)
|
|
return;
|
|
var containerHeight = this._$container.outerHeight(),
|
|
containerMargin = containerHeight - this._$content.height(),
|
|
targetHeight = $(this.option("target")).outerHeight(),
|
|
maxHeight = ($(window).height() - targetHeight) * 0.5 - this._$arrow.height() - containerMargin;
|
|
if (containerHeight > maxHeight)
|
|
this._$content.height(maxHeight - 0)
|
|
},
|
|
_isOutsideClick: function(e) {
|
|
return !$(e.target).closest(this.option("target")).length
|
|
},
|
|
_animate: function(animation) {
|
|
this.callBase(animation);
|
|
if ($.isPlainObject(animation))
|
|
DX.fx.animate(this._$arrow, animation)
|
|
},
|
|
_renderTitle: function() {
|
|
this._wrapper().toggleClass(POPOVER_WITHOUT_TITLE_CLASS, !this.option("showTitle"));
|
|
this.callBase()
|
|
},
|
|
_renderTarget: function() {
|
|
this.option("position.of", this.option("target"))
|
|
},
|
|
_renderPosition: function() {
|
|
DX.translator.move(this._$arrow, {
|
|
left: 0,
|
|
top: 0
|
|
});
|
|
DX.translator.move(this._$container, {
|
|
left: 0,
|
|
top: 0
|
|
});
|
|
this._updateContentSize();
|
|
var arrowPosition = $.extend({}, this.option("position"));
|
|
var containerPosition = $.extend({}, arrowPosition, {offset: "0 " + this._$arrow.height()}),
|
|
containerLocation = DX.calculatePosition(this._$container, containerPosition),
|
|
isFlipped = containerLocation.v.flip;
|
|
this._$arrow.toggleClass(ARROW_FLIPPED_CLASS, isFlipped);
|
|
if (isFlipped)
|
|
$.extend(arrowPosition, {
|
|
my: arrowPosition.at,
|
|
at: arrowPosition.my
|
|
});
|
|
DX.position(this._$arrow, arrowPosition);
|
|
var contentPosition = {
|
|
my: arrowPosition.my,
|
|
at: arrowPosition.at,
|
|
offset: isFlipped ? "0 1" : "0 -1",
|
|
of: this._$arrow,
|
|
collision: "fit"
|
|
};
|
|
DX.position(this._$container, contentPosition)
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"target":
|
|
this._renderTarget();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}));
|
|
ui.dxPopover.__internals = {
|
|
POPOVER_CLASS: POPOVER_CLASS,
|
|
POPOVER_WRAPPER_CLASS: POPOVER_WRAPPER_CLASS,
|
|
ARROW_CLASS: ARROW_CLASS,
|
|
ARROW_FLIPPED_CLASS: ARROW_FLIPPED_CLASS,
|
|
POPOVER_WITHOUT_TITLE_CLASS: POPOVER_WITHOUT_TITLE_CLASS
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.dateBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
support = DX.support,
|
|
globalize = Globalize;
|
|
var DATEBOX_CLASS = "dx-datebox",
|
|
DATEPICKER_CLASS = "dx-datepicker",
|
|
DATEPICKER_WRAPPER_CLASS = "dx-datepicker-wrapper",
|
|
DATEPICKER_ROLLER_CONTAINER_CLASS = "dx-datepicker-rollers",
|
|
DATEPICKER_ROLLER_CLASS = "dx-datepicker-roller",
|
|
DATEPICKER_ROLLER_ACTIVE_CLASS = "dx-state-active",
|
|
DATEPICKER_ROLLER_CURRENT_CLASS = "dx-datepicker-roller-current",
|
|
DATEPICKER_ROLLER_ITEM_CLASS = "dx-datepicker-item",
|
|
DATEPICKER_ROLLER_ITEM_SELECTED_CLASS = "dx-datepicker-item-selected",
|
|
DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS = "dx-datepicker-item-selected-frame",
|
|
DATEPICKER_ROLLER_BUTTON_UP_CLASS = "dx-datepicker-button-up",
|
|
DATEPICKER_ROLLER_BUTTON_DOWN_CLASS = "dx-datepicker-button-down",
|
|
DATEPICKER_FORMATTER_CONTAINER = "datepicker-formatter-container",
|
|
DATEPICKER_VALUE_FORMATTER = "datepicker-value-formatter",
|
|
DATEPICKER_NAME_FORMATTER = "datepicker-name-formatter",
|
|
SUPPORTED_FORMATS = ["date", "time", "datetime"],
|
|
DEFAULT_FORMATTER = function(value) {
|
|
return value
|
|
},
|
|
DATE_COMPONENT_TEXT_FORMATTER = function(value, name) {
|
|
var $container = $("<div />").addClass(DATEPICKER_FORMATTER_CONTAINER);
|
|
$("<span>").text(value).addClass(DATEPICKER_VALUE_FORMATTER).appendTo($container);
|
|
$("<span>").text(name).addClass(DATEPICKER_NAME_FORMATTER).appendTo($container);
|
|
return $container
|
|
},
|
|
YEAR = "year",
|
|
MONTH = "month",
|
|
DAY = "day",
|
|
HOURS = "hours",
|
|
MINUTES = "minutes",
|
|
SECONDS = "seconds",
|
|
MILLISECONDS = "milliseconds",
|
|
TEN_YEARS = 1000 * 60 * 60 * 24 * 365 * 10;
|
|
var DATE_COMPONENTS_INFO = {};
|
|
DATE_COMPONENTS_INFO[YEAR] = {
|
|
getter: "getFullYear",
|
|
setter: "setFullYear",
|
|
possibleFormats: ["yy", "yyyy"],
|
|
formatter: DEFAULT_FORMATTER,
|
|
startValue: undefined,
|
|
endValue: undefined
|
|
};
|
|
DATE_COMPONENTS_INFO[DAY] = {
|
|
getter: "getDate",
|
|
setter: "setDate",
|
|
possibleFormats: ["d", "dd"],
|
|
formatter: function(value, showNames, date) {
|
|
if (!showNames)
|
|
return value;
|
|
var formatDate = new Date(date.getTime());
|
|
formatDate.setDate(value);
|
|
return DATE_COMPONENT_TEXT_FORMATTER(value, globalize.culture().calendar.days.names[formatDate.getDay()])
|
|
},
|
|
startValue: 1,
|
|
endValue: undefined
|
|
};
|
|
DATE_COMPONENTS_INFO[MONTH] = {
|
|
getter: "getMonth",
|
|
setter: "setMonth",
|
|
possibleFormats: ["M", "MM", "MMM", "MMMM"],
|
|
formatter: function(value, showNames) {
|
|
var monthName = globalize.culture().calendar.months.names[value];
|
|
return showNames ? DATE_COMPONENT_TEXT_FORMATTER(value + 1, monthName) : monthName
|
|
},
|
|
startValue: 0,
|
|
endValue: 11
|
|
};
|
|
DATE_COMPONENTS_INFO[HOURS] = {
|
|
getter: "getHours",
|
|
setter: "setHours",
|
|
possibleFormats: ["H", "HH", "h", "hh"],
|
|
formatter: function(value) {
|
|
return globalize.format(new Date(0, 0, 0, value), "HH")
|
|
},
|
|
startValue: 0,
|
|
endValue: 23
|
|
};
|
|
DATE_COMPONENTS_INFO[MINUTES] = {
|
|
getter: "getMinutes",
|
|
setter: "setMinutes",
|
|
possibleFormats: ["m", "mm"],
|
|
formatter: function(value) {
|
|
return globalize.format(new Date(0, 0, 0, 0, value), "mm")
|
|
},
|
|
startValue: 0,
|
|
endValue: 59
|
|
};
|
|
DATE_COMPONENTS_INFO[SECONDS] = {
|
|
getter: "getSeconds",
|
|
setter: "setSeconds",
|
|
possibleFormats: ["s", "ss"],
|
|
formatter: function(value) {
|
|
return globalize.format(new Date(0, 0, 0, 0, 0, value), "ss")
|
|
},
|
|
startValue: 0,
|
|
endValue: 59
|
|
};
|
|
DATE_COMPONENTS_INFO[MILLISECONDS] = {
|
|
getter: "getMilliseconds",
|
|
setter: "setMilliseconds",
|
|
possibleFormats: ["f", "ff", "fff"],
|
|
formatter: function(value) {
|
|
return globalize.format(new Date(0, 0, 0, 0, 0, 0, value), "fff")
|
|
},
|
|
startValue: 0,
|
|
endValue: 999
|
|
};
|
|
var FORMATS_INFO = {
|
|
date: {
|
|
standardPattern: "yyyy-MM-dd",
|
|
components: [YEAR, DAY, MONTH]
|
|
},
|
|
datetime: {
|
|
standardPattern: "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
|
|
components: [YEAR, DAY, MONTH, HOURS, MINUTES, SECONDS, MILLISECONDS]
|
|
},
|
|
datetimeAndroid: {
|
|
standardPattern: "yyyy'-'MM'-'dd'T'HH':'mm'Z'",
|
|
components: [YEAR, DAY, MONTH, HOURS, MINUTES, SECONDS, MILLISECONDS]
|
|
},
|
|
time: {
|
|
standardPattern: "HH:mm",
|
|
components: [HOURS, MINUTES]
|
|
}
|
|
};
|
|
var toStandardDateFormat = function(date, mode) {
|
|
return Globalize.format(date, FORMATS_INFO[mode].standardPattern)
|
|
};
|
|
var fromStandardDateFormat = function(date) {
|
|
return Globalize.parseDate(date, FORMATS_INFO.datetime.standardPattern) || Globalize.parseDate(date, FORMATS_INFO.datetimeAndroid.standardPattern) || Globalize.parseDate(date, FORMATS_INFO.time.standardPattern) || Globalize.parseDate(date, FORMATS_INFO.date.standardPattern)
|
|
};
|
|
var getMaxMonthDay = function(year, month) {
|
|
return new Date(year, month + 1, 0).getDate()
|
|
};
|
|
var mergeDates = function(target, source, format) {
|
|
if (!source)
|
|
return undefined;
|
|
var formatInfo = FORMATS_INFO[format];
|
|
$.each(formatInfo.components, function() {
|
|
var componentInfo = DATE_COMPONENTS_INFO[this];
|
|
target[componentInfo.setter](source[componentInfo.getter]())
|
|
});
|
|
return target
|
|
};
|
|
ui.registerComponent("dxDatePickerRoller", ui.dxScrollable.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
showScrollbar: false,
|
|
useNative: false,
|
|
selectedIndex: 0,
|
|
items: []
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._renderSelectedItemFrame();
|
|
this._renderControlButtons()
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(DATEPICKER_ROLLER_CLASS);
|
|
this._renderItems();
|
|
this._renderSelectedValue()
|
|
},
|
|
_renderItems: function() {
|
|
var items = this.option("items") || [],
|
|
$items = $();
|
|
this._$content.empty();
|
|
$.each(items, function() {
|
|
$items = $items.add($("<div>").addClass(DATEPICKER_ROLLER_ITEM_CLASS).append(this))
|
|
});
|
|
this._$content.append($items);
|
|
this._$items = $items;
|
|
this.update()
|
|
},
|
|
_renderSelectedItemFrame: function() {
|
|
$("<div>").addClass(DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS).insertAfter(this._$container)
|
|
},
|
|
_renderControlButtons: function() {
|
|
$("<div>").addClass(DATEPICKER_ROLLER_BUTTON_UP_CLASS).insertAfter(this._$container).dxButton({clickAction: $.proxy(this._handleUpButtonClick, this)});
|
|
$("<div>").addClass(DATEPICKER_ROLLER_BUTTON_DOWN_CLASS).insertAfter(this._$container).dxButton({clickAction: $.proxy(this._handleDownButtonClick, this)})
|
|
},
|
|
_renderSelectedValue: function(selectedIndex) {
|
|
if (selectedIndex === undefined)
|
|
selectedIndex = this.option("selectedIndex");
|
|
selectedIndex = this._fitIndex(selectedIndex);
|
|
var correctedPosition = this._getItemPosition(selectedIndex);
|
|
this.option().selectedIndex = selectedIndex;
|
|
this._moveTo({y: correctedPosition});
|
|
this._renderActiveStateItem()
|
|
},
|
|
_fitIndex: function(index) {
|
|
var items = this.option("items") || [],
|
|
itemCount = items.length;
|
|
if (index >= itemCount)
|
|
return itemCount - 1;
|
|
if (index < 0)
|
|
return 0;
|
|
return index
|
|
},
|
|
_renderActiveStateItem: function() {
|
|
var selectedIndex = this.option("selectedIndex");
|
|
$.each(this._$items, function(index) {
|
|
$(this).toggleClass(DATEPICKER_ROLLER_ITEM_SELECTED_CLASS, selectedIndex === index)
|
|
})
|
|
},
|
|
_handleUpButtonClick: function() {
|
|
this._animation = true;
|
|
this.option("selectedIndex", this.option("selectedIndex") - 1)
|
|
},
|
|
_handleDownButtonClick: function() {
|
|
this._animation = true;
|
|
this.option("selectedIndex", this.option("selectedIndex") + 1)
|
|
},
|
|
_getItemPosition: function(index) {
|
|
return this._itemHeight() * index
|
|
},
|
|
_moveTo: function(targetLocation) {
|
|
targetLocation = this._normalizeLocation(targetLocation);
|
|
var location = this._location(),
|
|
moveComplete,
|
|
delta = {
|
|
x: -(location.left - targetLocation.x),
|
|
y: -(location.top - targetLocation.y)
|
|
};
|
|
if (this._isVisible() && (delta.x || delta.y)) {
|
|
if (this._animation) {
|
|
moveComplete = DX.fx.animate(this._$content, {
|
|
duration: 200,
|
|
type: "slide",
|
|
to: {top: targetLocation.y}
|
|
});
|
|
delete this._animation
|
|
}
|
|
else {
|
|
moveComplete = $.Deferred().resolve().promise();
|
|
this._strategy._handleMove(delta)
|
|
}
|
|
moveComplete.done($.proxy(function() {
|
|
this._strategy.update();
|
|
this._strategy._handleMoveEnd({
|
|
x: 0,
|
|
y: 0
|
|
})
|
|
}, this))
|
|
}
|
|
},
|
|
_handleEndAction: function() {
|
|
var ratio = -this._location().top / this._itemHeight(),
|
|
selectedIndex = Math.round(ratio);
|
|
this._renderSelectedValue(selectedIndex)
|
|
},
|
|
_itemHeight: function() {
|
|
var $item = this._$items.first(),
|
|
height = $item.outerHeight() + parseFloat($item.css("margin-top"));
|
|
return height
|
|
},
|
|
_toggleActive: function(state) {
|
|
this._element().toggleClass(DATEPICKER_ROLLER_ACTIVE_CLASS, state)
|
|
},
|
|
_isVisible: function() {
|
|
return this._$container.is(":visible")
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"selectedIndex":
|
|
this._renderSelectedValue();
|
|
break;
|
|
case"items":
|
|
this._renderItems();
|
|
this._renderSelectedValue();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}));
|
|
ui.registerComponent("dxDatePicker", ui.dxPopup.inherit({
|
|
_valueOption: function() {
|
|
return new Date(this.option("value")) == "Invalid Date" ? new Date : new Date(this.option("value"))
|
|
},
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
minDate: new Date(1990, 1, 1),
|
|
maxDate: new Date($.now() + TEN_YEARS),
|
|
format: "date",
|
|
value: new Date,
|
|
culture: Globalize.culture().name,
|
|
showNames: false,
|
|
cancelButton: {
|
|
text: "Cancel",
|
|
icon: "close",
|
|
clickAction: $.proxy(function() {
|
|
this._value = this._valueOption()
|
|
}, this)
|
|
},
|
|
doneButton: {
|
|
text: "Done",
|
|
icon: "save",
|
|
clickAction: $.proxy(function() {
|
|
this.option("value", new Date(this._value));
|
|
this.hide()
|
|
}, this)
|
|
}
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(DATEPICKER_CLASS);
|
|
this._wrapper().addClass(DATEPICKER_WRAPPER_CLASS);
|
|
this._value = this._valueOption()
|
|
},
|
|
_renderContentImpl: function() {
|
|
this.callBase();
|
|
this._value = this._valueOption();
|
|
this._renderRollers()
|
|
},
|
|
_renderRollers: function() {
|
|
var self = this;
|
|
if (!self._$rollersContainer)
|
|
self._$rollersContainer = $("<div>").appendTo(self.content()).addClass(DATEPICKER_ROLLER_CONTAINER_CLASS);
|
|
self._$rollersContainer.empty();
|
|
self._createRollerConfigs();
|
|
self._rollers = {};
|
|
$.each(self._rollerConfigs, function() {
|
|
var rollerItem = this,
|
|
roller = $("<div>").appendTo(self._$rollersContainer).dxDatePickerRoller({
|
|
items: rollerItem.displayItems,
|
|
selectedIndex: rollerItem.selectedIndex,
|
|
startAction: function(e) {
|
|
var roller = e.component;
|
|
roller._toggleActive.call(roller, true);
|
|
self._setActiveRoller.call(self, rollerItem, roller.option("selectedIndex"))
|
|
},
|
|
endAction: function(e) {
|
|
var roller = e.component;
|
|
roller._animation = true;
|
|
roller._handleEndAction.apply(roller, arguments);
|
|
self._setRollerState.call(self, rollerItem, roller.option("selectedIndex"));
|
|
roller._toggleActive.call(roller, false)
|
|
}
|
|
});
|
|
self._rollers[rollerItem.type] = roller.dxDatePickerRoller("instance")
|
|
})
|
|
},
|
|
_setActiveRoller: function(currentRoller) {
|
|
var activeRoller = this._rollers[currentRoller.type];
|
|
$.each(this._rollers, function() {
|
|
this._$element.toggleClass(DATEPICKER_ROLLER_CURRENT_CLASS, this === activeRoller)
|
|
})
|
|
},
|
|
_refreshRollers: function() {
|
|
var self = this;
|
|
$.each(this._rollers, function(type) {
|
|
var correctIndex = self._rollerConfigs[type].getIndex(self._value);
|
|
this.update();
|
|
this._renderSelectedValue(correctIndex)
|
|
})
|
|
},
|
|
_setRollerState: function(roller, selectedIndex) {
|
|
if (selectedIndex !== roller.selectedIndex) {
|
|
var value = roller.valueItems[selectedIndex],
|
|
setValue = roller.setValue,
|
|
currentDate = this._value.getDate();
|
|
if (roller.type === MONTH) {
|
|
currentDate = Math.min(currentDate, getMaxMonthDay(this._value.getFullYear(), value));
|
|
this._value.setDate(currentDate)
|
|
}
|
|
else if (roller.type === YEAR) {
|
|
currentDate = Math.min(currentDate, getMaxMonthDay(value, this._value.getMonth()));
|
|
this._value.setDate(currentDate)
|
|
}
|
|
this._value[setValue](value);
|
|
roller.selectedIndex = selectedIndex
|
|
}
|
|
var dayRoller = this._rollers[DAY];
|
|
if ((roller.type === MONTH || roller.type === YEAR) && dayRoller) {
|
|
this._createRollerConfig(DAY);
|
|
var dayRollerConfig = this._rollerConfigs[DAY];
|
|
window.setTimeout(function() {
|
|
dayRoller.option("items", dayRollerConfig.displayItems)
|
|
}, 100)
|
|
}
|
|
},
|
|
_createRollerConfigs: function(format) {
|
|
var self = this;
|
|
format = format || self.option("format");
|
|
self._rollerConfigs = {};
|
|
$.each(self._getFormatPattern(format).split(/\W+/), function(_, formatPart) {
|
|
$.each(DATE_COMPONENTS_INFO, function(componentName, componentInfo) {
|
|
if ($.inArray(formatPart, componentInfo.possibleFormats) > -1)
|
|
self._createRollerConfig(componentName)
|
|
})
|
|
})
|
|
},
|
|
_getFormatPattern: function(format) {
|
|
var culture = Globalize.culture(this.option("culture")),
|
|
result = "";
|
|
if (format === "date")
|
|
result = culture.calendar.patterns.d;
|
|
else if (format === "time")
|
|
result = culture.calendar.patterns.t;
|
|
else if (format === "datetime")
|
|
result = [culture.calendar.patterns.d, culture.calendar.patterns.t].join(" ");
|
|
return result
|
|
},
|
|
_createRollerConfig: function(componentName) {
|
|
var componentInfo = DATE_COMPONENTS_INFO[componentName],
|
|
startValue = componentInfo.startValue,
|
|
endValue = componentInfo.endValue,
|
|
formatter = componentInfo.formatter,
|
|
showNames = this.option("showNames");
|
|
if (componentName === YEAR) {
|
|
startValue = this.option("minDate").getFullYear();
|
|
endValue = this.option("maxDate").getFullYear()
|
|
}
|
|
if (componentName === DAY)
|
|
endValue = getMaxMonthDay(this._value.getFullYear(), this._value.getMonth());
|
|
var config = {
|
|
type: componentName,
|
|
setValue: componentInfo.setter,
|
|
valueItems: [],
|
|
displayItems: [],
|
|
getIndex: function(value) {
|
|
return value[componentInfo.getter]() - startValue
|
|
}
|
|
};
|
|
for (var i = startValue; i <= endValue; i++) {
|
|
config.valueItems.push(i);
|
|
config.displayItems.push(formatter(i, showNames, this._value))
|
|
}
|
|
config.selectedIndex = config.getIndex(this._value);
|
|
this._rollerConfigs[componentName] = config
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"minDate":
|
|
case"maxDate":
|
|
case"culture":
|
|
case"format":
|
|
this._renderRollers();
|
|
break;
|
|
case"visible":
|
|
this.callBase(name, value, prevValue);
|
|
if (value)
|
|
this._refreshRollers();
|
|
break;
|
|
case"value":
|
|
this._clean();
|
|
this._invalidate();
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
}
|
|
}));
|
|
ui.registerComponent("dxDateBox", ui.dxEditBox.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
format: "date",
|
|
value: new Date,
|
|
useNativePicker: true
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
if ($.inArray(this.option("format"), SUPPORTED_FORMATS) === -1)
|
|
this.option("format", "date");
|
|
this.option("mode", this.option("format"))
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(DATEBOX_CLASS);
|
|
this._renderDatePicker()
|
|
},
|
|
_renderDatePicker: function() {
|
|
if (this._usingNativeDatePicker() || this.option("readOnly"))
|
|
return;
|
|
var datePickerOptions = {
|
|
value: this.option("value"),
|
|
format: this.option("format")
|
|
};
|
|
if (this._datePicker)
|
|
this._datePicker.option(datePickerOptions);
|
|
else {
|
|
this._datePicker = $("<div>").appendTo(this._element()).dxDatePicker($.extend(datePickerOptions, {hidingAction: $.proxy(function(e) {
|
|
this.option("value", e.component.option("value"))
|
|
}, this)})).dxDatePicker("instance");
|
|
var inputClickAction = this._createAction(function(e) {
|
|
e.component._datePicker.show()
|
|
});
|
|
this._input().on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
return inputClickAction({jQuery: e})
|
|
})
|
|
}
|
|
},
|
|
_usingNativeDatePicker: function() {
|
|
return support.inputType(this.option("format")) || this.option("useNativePicker")
|
|
},
|
|
_readOnlyPropValue: function() {
|
|
if (this._usingNativeDatePicker())
|
|
return this.callBase();
|
|
return true
|
|
},
|
|
_handleValueChange: function() {
|
|
var value = fromStandardDateFormat(this._input().val()),
|
|
modelValue = new Date(this.option("value") && this.option("value").valueOf()),
|
|
newValue = mergeDates(modelValue, value, this.option("format"));
|
|
this.option({value: newValue});
|
|
if (newValue !== modelValue)
|
|
this._renderValue()
|
|
},
|
|
_renderValue: function() {
|
|
this._input().val(toStandardDateFormat(this.option("value"), this.option("format")))
|
|
},
|
|
_renderProps: function() {
|
|
this.callBase();
|
|
this._input().attr("autocomplete", "off")
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"value":
|
|
this._renderValue();
|
|
this._changeAction(value);
|
|
this._renderDatePicker();
|
|
break;
|
|
case"format":
|
|
this.option("mode", value);
|
|
this._renderValue();
|
|
this._renderDatePicker();
|
|
break;
|
|
case"readOnly":
|
|
case"useNativePicker":
|
|
this._invalidate();
|
|
break;
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
}
|
|
}));
|
|
ui.dxDatePicker.__internals = {
|
|
DATEPICKER_CLASS: DATEPICKER_CLASS,
|
|
DATEPICKER_WRAPPER_CLASS: DATEPICKER_WRAPPER_CLASS,
|
|
DATEPICKER_ROLLER_CONTAINER_CLASS: DATEPICKER_ROLLER_CONTAINER_CLASS,
|
|
DATEPICKER_ROLLER_CLASS: DATEPICKER_ROLLER_CLASS,
|
|
DATEPICKER_ROLLER_ACTIVE_CLASS: DATEPICKER_ROLLER_ACTIVE_CLASS,
|
|
DATEPICKER_ROLLER_ITEM_CLASS: DATEPICKER_ROLLER_ITEM_CLASS,
|
|
DATEPICKER_ROLLER_ITEM_SELECTED_CLASS: DATEPICKER_ROLLER_ITEM_SELECTED_CLASS,
|
|
DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS: DATEPICKER_ROLLER_ITEM_SELECTED_FRAME_CLASS,
|
|
DATEPICKER_ROLLER_BUTTON_UP_CLASS: DATEPICKER_ROLLER_BUTTON_UP_CLASS,
|
|
DATEPICKER_ROLLER_BUTTON_DOWN_CLASS: DATEPICKER_ROLLER_BUTTON_DOWN_CLASS,
|
|
DATEPICKER_ROLLER_CURRENT_CLASS: DATEPICKER_ROLLER_CURRENT_CLASS
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.loadIndicator.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var LOADINDICATOR_CLASS = "dx-loadindicator",
|
|
LOADINDICATOR_WRAPPER = LOADINDICATOR_CLASS + "-wrapper",
|
|
LOADINDICATOR_ICON = LOADINDICATOR_CLASS + "-icon",
|
|
LOADINDICATOR_SEGMENT = LOADINDICATOR_CLASS + "-segment",
|
|
LOADINDICATOR_SEGMENT_N = LOADINDICATOR_CLASS + "-segment",
|
|
LOADINDICATOR_SEGMENT_WIN8 = LOADINDICATOR_CLASS + "-win8-segment",
|
|
LOADINDICATOR_SEGMENT_N_WIN8 = LOADINDICATOR_CLASS + "-win8-segment",
|
|
LOADINDICATOR_INNER_SEGMENT_WIN8 = LOADINDICATOR_CLASS + "-win8-inner-segment",
|
|
LOADINDICATOR_IMAGE = LOADINDICATOR_CLASS + "-image",
|
|
LOADINDICATOR_SIZES = ["small", "medium", "large"];
|
|
ui.registerComponent("dxLoadIndicator", ui.Widget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
disabled: false,
|
|
visible: true,
|
|
size: ""
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(LOADINDICATOR_CLASS);
|
|
this._setSize();
|
|
if (DX.support.animation && !this.option("viaImage"))
|
|
this._renderMarkupForAnimation();
|
|
else
|
|
this._renderMarkupForImage()
|
|
},
|
|
_renderMarkupForAnimation: function() {
|
|
var indicator = $("<div>").addClass(LOADINDICATOR_ICON);
|
|
indicator.append($("<div>").addClass(LOADINDICATOR_SEGMENT).addClass(LOADINDICATOR_SEGMENT_N + "0"));
|
|
for (var i = 15; i > 0; --i)
|
|
indicator.append($("<div>").addClass(LOADINDICATOR_SEGMENT).addClass(LOADINDICATOR_SEGMENT_N + i));
|
|
for (var i = 1; i <= 5; ++i)
|
|
indicator.append($("<div>").addClass(LOADINDICATOR_SEGMENT_WIN8).addClass(LOADINDICATOR_SEGMENT_N_WIN8 + i).append($("<div>").addClass(LOADINDICATOR_INNER_SEGMENT_WIN8)));
|
|
$("<div>").addClass(LOADINDICATOR_WRAPPER).append(indicator).appendTo(this._element())
|
|
},
|
|
_renderMarkupForImage: function() {
|
|
var size = this.option("size");
|
|
if (size === "small" || size === "large")
|
|
this._element().addClass(LOADINDICATOR_IMAGE + "-" + size);
|
|
else
|
|
this._element().addClass(LOADINDICATOR_IMAGE)
|
|
},
|
|
_setSize: function() {
|
|
var size = this.option("size");
|
|
if (size && $.inArray(size, LOADINDICATOR_SIZES) !== -1)
|
|
this._element().addClass(LOADINDICATOR_CLASS + "-" + size)
|
|
},
|
|
_optionChanged: function(name) {
|
|
switch (name) {
|
|
case"size":
|
|
this._setSize();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.loadPanel.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var LOADPANEL_CLASS = "dx-loadpanel",
|
|
LOADPANEL_WRAPPER_CLASS = LOADPANEL_CLASS + "-wrapper",
|
|
LOADPANEL_INDICATOR_CLASS = LOADPANEL_CLASS + "-indicator",
|
|
LOADPANEL_MESSAGE_CLASS = LOADPANEL_CLASS + "-message",
|
|
LOADPANEL_CONTENT_CLASS = LOADPANEL_CLASS + "-content",
|
|
LOADPANEL_HAS_INDICATOR_CLASS = LOADPANEL_CLASS + "-has-indicator";
|
|
ui.registerComponent("dxLoadPanel", ui.dxOverlay.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
message: Globalize.localize("Loading"),
|
|
width: 200,
|
|
height: 70,
|
|
animation: null,
|
|
disabled: false,
|
|
showIndicator: true
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(LOADPANEL_CLASS);
|
|
this._wrapper().addClass(LOADPANEL_WRAPPER_CLASS)
|
|
},
|
|
_renderContentImpl: function() {
|
|
this.callBase();
|
|
this.content().addClass(LOADPANEL_CONTENT_CLASS);
|
|
this._cleanPreviousContent();
|
|
this._renderLoadIndicator();
|
|
this._renderMessage()
|
|
},
|
|
_cleanPreviousContent: function() {
|
|
this.content().find("." + LOADPANEL_MESSAGE_CLASS).remove();
|
|
this.content().find("." + LOADPANEL_INDICATOR_CLASS).remove()
|
|
},
|
|
_renderMessage: function() {
|
|
var $message = $("<div>").addClass(LOADPANEL_MESSAGE_CLASS).toggleClass(LOADPANEL_HAS_INDICATOR_CLASS, this.option("showIndicator")).text(this.option("message"));
|
|
this.content().append($message)
|
|
},
|
|
_renderLoadIndicator: function() {
|
|
if (!this.option("showIndicator"))
|
|
return;
|
|
var $indicator = $("<div>").addClass(LOADPANEL_INDICATOR_CLASS);
|
|
this.content().append($indicator);
|
|
$indicator.dxLoadIndicator()
|
|
},
|
|
_clean: function() {
|
|
this.callBase.apply(this, arguments);
|
|
this.content().empty()
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"message":
|
|
case"showIndicator":
|
|
this._clean();
|
|
this._render();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_defaultBackButtonHandler: $.noop
|
|
}));
|
|
ui.dxLoadPanel.__internals = {
|
|
LOADPANEL_CLASS: LOADPANEL_CLASS,
|
|
LOADPANEL_WRAPPER_CLASS: LOADPANEL_WRAPPER_CLASS,
|
|
LOADPANEL_MESSAGE_CLASS: LOADPANEL_MESSAGE_CLASS,
|
|
LOADPANEL_CONTENT_CLASS: LOADPANEL_CONTENT_CLASS
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.lookup.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils,
|
|
events = ui.events;
|
|
var LOOKUP_CLASS = "dx-lookup",
|
|
LOOKUP_SELECTED_CLASS = LOOKUP_CLASS + "-selected",
|
|
LOOKUP_SEARCH_CLASS = LOOKUP_CLASS + "-search",
|
|
LOOKUP_FIELD_CLASS = LOOKUP_CLASS + "-field",
|
|
LOOKUP_POPUP_CLASS = LOOKUP_CLASS + "-popup",
|
|
LOOKUP_POPUP_WRAPPER_CLASS = LOOKUP_POPUP_CLASS + "-wrapper",
|
|
LOOKUP_POPUP_SEARCH_CLASS = LOOKUP_POPUP_CLASS + "-search",
|
|
LOOKUP_POPOVER_MODE = LOOKUP_CLASS + "-popover-mode",
|
|
LIST_ITEM_SELECTOR = ".dx-list-item",
|
|
LIST_ITEM_DATA_KEY = "dxListItemData",
|
|
POPUP_HIDE_TIMEOUT = 200;
|
|
ui.registerComponent("dxLookup", ui.ContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
dataSource: null,
|
|
value: undefined,
|
|
displayValue: undefined,
|
|
title: "",
|
|
valueExpr: null,
|
|
displayExpr: "this",
|
|
placeholder: Globalize.localize("Select"),
|
|
searchPlaceholder: Globalize.localize("Search"),
|
|
searchEnabled: true,
|
|
noDataText: Globalize.localize("dxCollectionContainerWidget-noDataText"),
|
|
searchTimeout: 1000,
|
|
minFilterLength: 0,
|
|
fullScreen: false,
|
|
valueChangeAction: null,
|
|
itemTemplate: null,
|
|
itemRender: null,
|
|
showCancelButton: true,
|
|
cancelButtonText: Globalize.localize("Cancel"),
|
|
showClearButton: false,
|
|
clearButtonText: Globalize.localize("Clear"),
|
|
showDoneButton: false,
|
|
doneButtonText: Globalize.localize("Done"),
|
|
contentReadyAction: null,
|
|
shownAction: null,
|
|
hiddenAction: null,
|
|
popupWidth: function() {
|
|
return $(window).width() * 0.8
|
|
},
|
|
popupHeight: function() {
|
|
return $(window).height() * 0.8
|
|
},
|
|
usePopover: false
|
|
})
|
|
},
|
|
_optionsByReference: function() {
|
|
return $.extend(this.callBase(), {value: true})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initDataSource();
|
|
this._checkExceptions();
|
|
this._searchTimer = null;
|
|
this._compileValueGetter();
|
|
this._compileDisplayGetter();
|
|
this._createEventActions();
|
|
if (!this._dataSource)
|
|
this._itemsToDataSource()
|
|
},
|
|
_checkExceptions: function() {
|
|
if (this._dataSource && this._dataSource._mapFunc)
|
|
throw Error("Data source with enabled map is not allowed in the lookup");
|
|
},
|
|
_compileValueGetter: function() {
|
|
this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
|
|
},
|
|
_valueGetterExpr: function() {
|
|
return this.option("valueExpr") || this._dataSource && this._dataSource._store._key || "this"
|
|
},
|
|
_compileDisplayGetter: function() {
|
|
this._displayGetter = DX.data.utils.compileGetter(this.option("displayExpr"))
|
|
},
|
|
_createEventActions: function() {
|
|
this._valueChangeAction = this._createActionByOption("valueChangeAction")
|
|
},
|
|
_itemsToDataSource: function() {
|
|
this._dataSource = new DevExpress.data.DataSource(this.option("items"))
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(LOOKUP_CLASS).toggleClass(LOOKUP_POPOVER_MODE, this.option("usePopover"));
|
|
this._renderField();
|
|
this._needRenderContent = true;
|
|
this._calcSelectedItem($.proxy(this._setFieldText, this))
|
|
},
|
|
_renderContent: $.noop,
|
|
_renderField: function() {
|
|
var fieldClickAction = this._createAction(this._handleFieldClick);
|
|
this._$field = $("<div/>").addClass(LOOKUP_FIELD_CLASS).appendTo(this._element()).on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
fieldClickAction({jQueryEvent: e})
|
|
})
|
|
},
|
|
_handleFieldClick: function(args) {
|
|
var self = args.component;
|
|
self._renderContentIfNeed();
|
|
self._setListDataSource();
|
|
self._refreshSelected();
|
|
self._popup.show();
|
|
self._popup.content().on("MSPointerDown", function(e){});
|
|
self._lastSelectedItem = self._selectedItem
|
|
},
|
|
_renderContentIfNeed: function() {
|
|
if (this._needRenderContent) {
|
|
this._renderPopup();
|
|
this._needRenderContent = false
|
|
}
|
|
},
|
|
_renderPopup: function() {
|
|
var $popup = $("<div />").addClass(LOOKUP_POPUP_CLASS).appendTo(this._element());
|
|
var popupOptions = {
|
|
title: this.option("title"),
|
|
contentReadyAction: $.proxy(this._popupContentReadyAction, this),
|
|
width: this.option("popupWidth"),
|
|
height: this.option("popupHeight"),
|
|
cancelButton: this._getCancelButtonConfig(),
|
|
doneButton: this._getDoneButtonConfig(),
|
|
clearButton: this._getClearButtonConfig(),
|
|
shownAction: this._createActionByOption("shownAction"),
|
|
hiddenAction: this._createActionByOption("hiddenAction")
|
|
};
|
|
this._popup = this.option("usePopover") ? this._createPopover($popup, popupOptions) : this._createPopup($popup, popupOptions);
|
|
this._popup._wrapper().addClass(LOOKUP_POPUP_WRAPPER_CLASS).toggleClass(LOOKUP_POPUP_SEARCH_CLASS, this.option("searchEnabled"))
|
|
},
|
|
_createPopover: function($element, options) {
|
|
return $element.dxPopover($.extend(options, {
|
|
showTitle: true,
|
|
target: this._element()
|
|
})).dxPopover("instance")
|
|
},
|
|
_createPopup: function($element, options) {
|
|
return $element.dxPopup($.extend(options, {
|
|
fullScreen: this.option("fullScreen"),
|
|
shading: !this.option("fullScreen")
|
|
})).dxPopup("instance")
|
|
},
|
|
_getCancelButtonConfig: function() {
|
|
return this.option("showCancelButton") ? {text: this.option("cancelButtonText")} : null
|
|
},
|
|
_getDoneButtonConfig: function() {
|
|
return this.option("showDoneButton") ? {
|
|
text: this.option("doneButtonText"),
|
|
clickAction: $.proxy(function() {
|
|
this.option("value", this._valueGetter(this._lastSelectedItem))
|
|
}, this)
|
|
} : null
|
|
},
|
|
_getClearButtonConfig: function() {
|
|
return this.option("showClearButton") ? {
|
|
text: this.option("clearButtonText"),
|
|
clickAction: $.proxy(function() {
|
|
this.option("value", "")
|
|
}, this)
|
|
} : null
|
|
},
|
|
_renderCancelButton: function() {
|
|
this._popup && this._popup.option("cancelButton", this._getCancelButtonConfig())
|
|
},
|
|
_renderDoneButton: function() {
|
|
this._popup && this._popup.option("doneButton", this._getDoneButtonConfig())
|
|
},
|
|
_renderClearButton: function() {
|
|
this._popup && this._popup.option("clearButton", this._getClearButtonConfig())
|
|
},
|
|
_popupContentReadyAction: function() {
|
|
this._renderSearch();
|
|
this._renderList();
|
|
this._setListDataSource()
|
|
},
|
|
_renderSearch: function() {
|
|
this._$search = $("<div/>").addClass(LOOKUP_SEARCH_CLASS).dxTextBox({
|
|
mode: "search",
|
|
placeholder: this._getSearchPlaceholder(),
|
|
valueUpdateEvent: "change input",
|
|
valueUpdateAction: $.proxy(this._searchChangedHandler, this)
|
|
}).toggle(this.option("searchEnabled")).appendTo(this._popup.content());
|
|
this._search = this._$search.dxTextBox("instance")
|
|
},
|
|
_getSearchPlaceholder: function() {
|
|
var minFilterLength = this.option("minFilterLength"),
|
|
placeholder = this.option("searchPlaceholder");
|
|
if (minFilterLength && placeholder === Globalize.localize("Search"))
|
|
return utils.stringFormat(Globalize.localize("dxLookup-searchPlaceholder"), minFilterLength);
|
|
return placeholder
|
|
},
|
|
_renderList: function() {
|
|
this._list = $("<div/>").appendTo(this._popup.content()).dxList({
|
|
dataSource: null,
|
|
itemClickAction: $.proxy(function(e) {
|
|
this._toggleSelectedClass(e.jQueryEvent);
|
|
this._updateOptions(e)
|
|
}, this),
|
|
itemRenderedAction: $.proxy(function(e) {
|
|
this._setSelectedClass(e.itemElement, e.itemData)
|
|
}, this),
|
|
contentReadyAction: this.option("contentReadyAction"),
|
|
itemRender: this._getItemRender(),
|
|
itemTemplate: this.option("itemTemplate"),
|
|
noDataText: this.option("noDataText")
|
|
}).data("dxList");
|
|
this._list.addExternalTemplate(this._templates);
|
|
if (this._needSetItemRenderToList) {
|
|
this._updateListItemRender();
|
|
this._needSetItemRenderToList = false
|
|
}
|
|
},
|
|
_setListDataSource: function(force) {
|
|
if (!this._list)
|
|
return;
|
|
var needsToLoad = this._search.option("value").length >= this.option("minFilterLength"),
|
|
dataSourceLoaded = !!this._list.option("dataSource"),
|
|
skip = needsToLoad === dataSourceLoaded;
|
|
if (!force && skip)
|
|
return;
|
|
this._list.option("dataSource", needsToLoad ? this._dataSource : null);
|
|
if (!needsToLoad)
|
|
this._list.option("items", undefined)
|
|
},
|
|
_refreshSelected: function() {
|
|
var self = this;
|
|
if (!self._list)
|
|
return;
|
|
$.each(this._list._element().find(LIST_ITEM_SELECTOR), function() {
|
|
var item = $(this);
|
|
self._setSelectedClass(item, item.data(LIST_ITEM_DATA_KEY))
|
|
})
|
|
},
|
|
_calcSelectedItem: function(callback) {
|
|
var ds = this._dataSource,
|
|
store,
|
|
valueExpr,
|
|
thisWidget = this,
|
|
value = this.option("value");
|
|
function handleLoadSuccess(result) {
|
|
thisWidget._selectedItem = result;
|
|
callback()
|
|
}
|
|
if (!ds || value === undefined) {
|
|
this._selectedItem = undefined;
|
|
callback();
|
|
return
|
|
}
|
|
store = ds.store();
|
|
valueExpr = this._valueGetterExpr();
|
|
if (valueExpr === store.key() || store instanceof DX.data.CustomStore)
|
|
store.byKey(value).done(handleLoadSuccess);
|
|
else
|
|
store.load({filter: [valueExpr, value]}).done(function(result) {
|
|
handleLoadSuccess(result[0])
|
|
})
|
|
},
|
|
_setFieldText: function(text) {
|
|
if (!arguments.length)
|
|
text = this._getDisplayText();
|
|
this._$field.text(text);
|
|
this.option("displayValue", text)
|
|
},
|
|
_getDisplayText: function() {
|
|
if (this.option("value") === undefined || !this._dataSource)
|
|
return this.option("placeholder");
|
|
return this._displayGetter(this._selectedItem) || this.option("placeholder")
|
|
},
|
|
_searchChangedHandler: function() {
|
|
if (!this._search)
|
|
return;
|
|
var searchValue = this._search.option("value"),
|
|
needsToLoad = searchValue.length >= this.option("minFilterLength");
|
|
clearTimeout(this._$searchTimer);
|
|
this._search.option("placeholder", this._getSearchPlaceholder());
|
|
if (!needsToLoad) {
|
|
this._setListDataSource();
|
|
return
|
|
}
|
|
if (this.option("searchTimeout"))
|
|
this._searchTimer = setTimeout($.proxy(this._doSearch, this, searchValue), this.option("searchTimeout"));
|
|
else
|
|
this._doSearch(searchValue)
|
|
},
|
|
_doSearch: function(searchValue) {
|
|
if (!this._dataSource)
|
|
return;
|
|
if (!arguments.length)
|
|
searchValue = this.option("searchEnabled") ? this._search.option("value") : "";
|
|
this._filterStore(searchValue);
|
|
this._setListDataSource()
|
|
},
|
|
_filterStore: function(searchValue) {
|
|
if (!this._dataSource.searchExpr())
|
|
this._dataSource.searchExpr(this.option("displayExpr"));
|
|
this._dataSource.searchValue(searchValue);
|
|
this._dataSource.pageIndex(0);
|
|
this._dataSource.load()
|
|
},
|
|
_updateOptions: function(e) {
|
|
if (this._lastSelectedItem === e.itemData)
|
|
this._updateAndHidePopup();
|
|
this._lastSelectedItem = e.itemData;
|
|
if (!this.option("showDoneButton"))
|
|
this._updateAndHidePopup()
|
|
},
|
|
_setSelectedClass: function(item, itemData) {
|
|
var selected = this._valueGetter(itemData) === this.option("value");
|
|
item.toggleClass(LOOKUP_SELECTED_CLASS, selected)
|
|
},
|
|
_getItemRender: function() {
|
|
if (!this.option("itemTemplate"))
|
|
return this.option("itemRender") || $.proxy(this._displayGetter, this)
|
|
},
|
|
_toggleSelectedClass: function(e) {
|
|
var $selectedItem = this._list._element().find("." + LOOKUP_SELECTED_CLASS);
|
|
if ($selectedItem.length)
|
|
$selectedItem.removeClass(LOOKUP_SELECTED_CLASS);
|
|
$(e.target).closest(LIST_ITEM_SELECTOR).addClass(LOOKUP_SELECTED_CLASS)
|
|
},
|
|
_hidePopup: function() {
|
|
this._popup.content().off("MSPointerDown");
|
|
this._popup.hide()
|
|
},
|
|
_updateAndHidePopup: function() {
|
|
this.option("value", this._valueGetter(this._lastSelectedItem));
|
|
clearTimeout(this._hidePopupTimer);
|
|
this._hidePopupTimer = setTimeout($.proxy(this._hidePopup, this), POPUP_HIDE_TIMEOUT);
|
|
this._setFieldText(this._displayGetter(this._lastSelectedItem))
|
|
},
|
|
_updateListItemRender: function() {
|
|
if (this._list)
|
|
this._list.option("itemRender", this._getItemRender());
|
|
else
|
|
this._needSetItemRenderToList = true
|
|
},
|
|
_updateListItemTemplate: function() {
|
|
if (this._list)
|
|
this._list.option("itemTemplate", this.option("itemTemplate"))
|
|
},
|
|
_handleDataSourceChanged: function(items) {
|
|
this._calcSelectedItem($.proxy(this._setFieldText, this))
|
|
},
|
|
_clean: function() {
|
|
if (this._popup)
|
|
this._popup._element().remove();
|
|
if (this._$field)
|
|
this._$field.remove();
|
|
this.callBase()
|
|
},
|
|
_dispose: function() {
|
|
clearTimeout(this._searchTimer);
|
|
clearTimeout(this._hidePopupTimer);
|
|
$(window).off(events.addNamespace("popstate", this.NAME));
|
|
this.callBase()
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"valueExpr":
|
|
case"value":
|
|
this._calcSelectedItem($.proxy(function() {
|
|
if (name === "value")
|
|
this._valueChangeAction({selectedItem: this._selectedItem});
|
|
this._compileValueGetter();
|
|
this._compileDisplayGetter();
|
|
this._refreshSelected();
|
|
this._setFieldText()
|
|
}, this));
|
|
break;
|
|
case"displayExpr":
|
|
this._compileDisplayGetter();
|
|
this._updateListItemRender();
|
|
this._refreshSelected();
|
|
this._setFieldText();
|
|
break;
|
|
case"displayValue":
|
|
break;
|
|
case"itemRender":
|
|
this._updateListItemRender();
|
|
case"itemTemplate":
|
|
this._updateListItemTemplate();
|
|
break;
|
|
case"items":
|
|
case"dataSource":
|
|
if (name === "items")
|
|
this._itemsToDataSource();
|
|
else
|
|
this._initDataSource();
|
|
this._setListDataSource(true);
|
|
this._compileValueGetter();
|
|
this._calcSelectedItem($.proxy(this._setFieldText, this));
|
|
break;
|
|
case"searchEnabled":
|
|
this._$search.toggle(value);
|
|
if (this._popup)
|
|
this._popup._wrapper().toggleClass(LOOKUP_POPUP_SEARCH_CLASS, value);
|
|
break;
|
|
case"minFilterLength":
|
|
this._setListDataSource();
|
|
this._setFieldText();
|
|
this._searchChangedHandler();
|
|
break;
|
|
case"placeholder":
|
|
this._setFieldText();
|
|
break;
|
|
case"searchPlaceholder":
|
|
if (this._$search)
|
|
this._$search.dxTextBox("instance").option("placeholder", value);
|
|
break;
|
|
case"title":
|
|
case"fullScreen":
|
|
if (this._popup)
|
|
this._popup.option(name, value);
|
|
break;
|
|
case"valueChangeAction":
|
|
this._createEventActions();
|
|
break;
|
|
case"showClearButton":
|
|
this._renderClearButton();
|
|
break;
|
|
case"showCancelButton":
|
|
this._renderCancelButton();
|
|
break;
|
|
case"showDoneButton":
|
|
this._renderDoneButton();
|
|
break;
|
|
case"contentReadyAction":
|
|
this._list.option("contentReadyAction", value);
|
|
break;
|
|
case"popupWidth":
|
|
if (this._popup)
|
|
this._popup.option("width", value);
|
|
break;
|
|
case"popupHeight":
|
|
if (this._popup)
|
|
this._popup.option("height", value);
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
this._checkExceptions()
|
|
}
|
|
}).include(ui.DataHelperMixin))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.actionSheet.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui;
|
|
var ACTION_SHEET_CLASS = "dx-action-sheet",
|
|
ACTION_SHEET_CONTAINER_CLASS = "dx-action-sheet-container",
|
|
ACTION_SHEET_POPUP_WRAPPER_CLASS = "dx-action-sheet-popup-wrapper",
|
|
ACTION_SHEET_POPOVER_WRAPPER_CLASS = "dx-action-sheet-popover-wrapper",
|
|
ACTION_SHEET_CANCEL_BUTTON_CLASS = "dx-action-sheet-cancel",
|
|
ACTION_SHEET_ITEM_CLASS = "dx-action-sheet-item",
|
|
ACTION_SHEET_ITEM_DATA_KEY = "dxActionSheetItemData",
|
|
ACTION_SHEET_WITHOUT_TITLE_CLASS = "dx-action-sheet-without-title";
|
|
ui.registerComponent("dxActionSheet", ui.CollectionContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
usePopover: false,
|
|
target: null,
|
|
title: "",
|
|
showTitle: true,
|
|
cancelText: Globalize.localize("Cancel"),
|
|
noDataText: "",
|
|
visible: false
|
|
})
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(ACTION_SHEET_CLASS);
|
|
this._createItemContainer();
|
|
this._renderPopup()
|
|
},
|
|
_createItemContainer: function() {
|
|
this._$itemContainer = $("<div/>").addClass(ACTION_SHEET_CONTAINER_CLASS);
|
|
this._toggleDisabled(this.option("disabled"))
|
|
},
|
|
_renderClick: function() {
|
|
this._popup.option("clickAction", this.option("clickAction"))
|
|
},
|
|
_renderPopup: function() {
|
|
this._$popup = $("<div/>").appendTo(this._element());
|
|
this._popup = this._isPopoverMode() ? this._createPopover(this._$popup) : this._createPopup(this._$popup);
|
|
this._togglePopupTitle(this.option("showTitle"));
|
|
this._popup.option("visible", this.option("visible"))
|
|
},
|
|
_clean: function() {
|
|
if (this._$popup)
|
|
this._$popup.remove();
|
|
this.callBase()
|
|
},
|
|
_togglePopupTitle: function(visible) {
|
|
this._popup.option("showTitle", visible);
|
|
this._popup._wrapper().toggleClass(ACTION_SHEET_WITHOUT_TITLE_CLASS, !visible)
|
|
},
|
|
_isPopoverMode: function() {
|
|
return this.option("usePopover") && this.option("target")
|
|
},
|
|
_createPopover: function($element) {
|
|
var popover = $element.dxPopover({
|
|
showTitle: true,
|
|
title: this.option("title"),
|
|
width: 200,
|
|
height: "auto",
|
|
target: this.option("target"),
|
|
hiddenAction: $.proxy(this.hide, this),
|
|
contentReadyAction: $.proxy(this._popupContentReadyAction, this)
|
|
}).dxPopover("instance");
|
|
popover._wrapper().addClass(ACTION_SHEET_POPOVER_WRAPPER_CLASS);
|
|
return popover
|
|
},
|
|
_createPopup: function($element) {
|
|
var popup = $element.dxPopup({
|
|
title: this.option("title"),
|
|
width: "100%",
|
|
height: "auto",
|
|
contentReadyAction: $.proxy(this._popupContentReadyAction, this),
|
|
position: {
|
|
my: "bottom",
|
|
at: "bottom",
|
|
of: window
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "slide",
|
|
duration: 400,
|
|
from: {position: {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: window
|
|
}},
|
|
to: {position: {
|
|
my: "bottom",
|
|
at: "bottom",
|
|
of: window
|
|
}}
|
|
},
|
|
hide: {
|
|
type: "slide",
|
|
duration: 400,
|
|
from: {position: {
|
|
my: "bottom",
|
|
at: "bottom",
|
|
of: window
|
|
}},
|
|
to: {position: {
|
|
my: "top",
|
|
at: "bottom",
|
|
of: window
|
|
}}
|
|
}
|
|
}
|
|
}).dxPopup("instance");
|
|
popup._wrapper().addClass(ACTION_SHEET_POPUP_WRAPPER_CLASS);
|
|
return popup
|
|
},
|
|
_popupContentReadyAction: function() {
|
|
this._popup.content().append(this._$itemContainer);
|
|
this._attachClickEvent();
|
|
this._renderContent();
|
|
this._renderCancel()
|
|
},
|
|
_renderCancel: function() {
|
|
if (this._isPopoverMode())
|
|
return;
|
|
this._cancelButton = $("<div/>").addClass(ACTION_SHEET_CANCEL_BUTTON_CLASS).appendTo(this._popup.content()).dxButton({
|
|
text: this.option("cancelText"),
|
|
clickAction: $.proxy(this.hide, this)
|
|
}).dxButton("instance")
|
|
},
|
|
_handleItemClick: function(e) {
|
|
this.callBase(e);
|
|
var clickedButton = $(e.target).closest(this._itemSelector()).data("dxButton");
|
|
if (!clickedButton.option("disabled") && !this.option("disabled"))
|
|
this.hide()
|
|
},
|
|
_itemRenderDefault: function(item, index, itemElement) {
|
|
itemElement.dxButton(item)
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$itemContainer
|
|
},
|
|
_itemClass: function() {
|
|
return ACTION_SHEET_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return ACTION_SHEET_ITEM_DATA_KEY
|
|
},
|
|
_toggleVisibility: $.noop,
|
|
_toggleDisabled: function(disabled) {
|
|
this._$itemContainer.toggleClass("dx-state-disabled", disabled)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"disabled":
|
|
this._toggleDisabled(value);
|
|
break;
|
|
case"visible":
|
|
case"title":
|
|
this._popup.option(name, value);
|
|
break;
|
|
case"showTitle":
|
|
this._togglePopupTitle(value);
|
|
break;
|
|
case"cancelText":
|
|
this._cancelButton.option("text", value);
|
|
break;
|
|
case"items":
|
|
this._attachClickEvent();
|
|
this._$itemContainer.empty();
|
|
this._renderContent();
|
|
this._popup.repaint();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
toggle: function(showing) {
|
|
var self = this,
|
|
d = $.Deferred();
|
|
self._popup.toggle(showing).done(function() {
|
|
self.option("visible", showing);
|
|
d.resolveWith(self)
|
|
});
|
|
return d.promise()
|
|
},
|
|
show: function() {
|
|
return this.toggle(true)
|
|
},
|
|
hide: function() {
|
|
return this.toggle(false)
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.autocomplete.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
utils = DX.utils;
|
|
var KEY_DOWN = 40,
|
|
KEY_UP = 38,
|
|
KEY_ENTER = 13,
|
|
KEY_ESC = 27,
|
|
KEY_RIGHT = 39,
|
|
KEY_TAB = 9,
|
|
AUTOCOMPLETE_CLASS = "dx-autocomplete",
|
|
AUTOCOMPLETE_POPUP_WRAPPER_CLASS = AUTOCOMPLETE_CLASS + "-popup-wrapper",
|
|
SELECTED_ITEM_CLASS = "dx-autocomplete-selected",
|
|
SELECTED_ITEM_SELECTOR = "." + SELECTED_ITEM_CLASS,
|
|
LIST_SELECTOR = ".dx-list",
|
|
EDITBOX_INPUT_SELECTOR = ".dx-editbox-input",
|
|
LIST_ITEM_SELECTOR = ".dx-list-item",
|
|
LIST_ITEM_DATA_KEY = "dxListItemData",
|
|
SEARCH_OPERATORS = ["startswith", "contains", "endwith", "notcontains"];
|
|
ui.registerComponent("dxAutocomplete", ui.ContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
value: "",
|
|
items: [],
|
|
dataSource: null,
|
|
itemTemplate: null,
|
|
itemRender: null,
|
|
minSearchLength: 1,
|
|
searchTimeout: 0,
|
|
placeholder: "",
|
|
filterOperator: "contains",
|
|
displayExpr: "this",
|
|
valueUpdateAction: null,
|
|
valueUpdateEvent: "change",
|
|
maxLength: null
|
|
})
|
|
},
|
|
_listElement: function() {
|
|
return this._popup.content().find(LIST_SELECTOR)
|
|
},
|
|
_listItemElement: function() {
|
|
return this._popup.content().find(LIST_ITEM_SELECTOR)
|
|
},
|
|
_listSelectedItemElement: function() {
|
|
return this._popup.content().find(SELECTED_ITEM_SELECTOR)
|
|
},
|
|
_inputElement: function() {
|
|
return this._element().find(EDITBOX_INPUT_SELECTOR)
|
|
},
|
|
_textboxElement: function() {
|
|
return this._textbox._element()
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._validateFilterOperator();
|
|
this._compileDisplayGetter();
|
|
this._initDataSource();
|
|
this._fillDataSourceFromItemsIfNeeded()
|
|
},
|
|
_fillDataSourceFromItemsIfNeeded: function() {
|
|
if (!this.option("dataSource") && this.option("items"))
|
|
this._itemsToDataSource()
|
|
},
|
|
_validateFilterOperator: function() {
|
|
var filterOperator = this.option("filterOperator"),
|
|
normalizedFilterOperator = filterOperator.toLowerCase();
|
|
if ($.inArray(normalizedFilterOperator, SEARCH_OPERATORS) > -1)
|
|
return;
|
|
throw Error(DX.utils.stringFormat("Filter operator \"{0}\" is unavailable", filterOperator));
|
|
},
|
|
_compileDisplayGetter: function() {
|
|
this._displayGetter = DX.data.utils.compileGetter(this.option("displayExpr"))
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass(AUTOCOMPLETE_CLASS);
|
|
this._checkExceptions()
|
|
},
|
|
_renderContentImpl: function() {
|
|
this._renderTextbox();
|
|
this._renderPopup();
|
|
this._renderValueUpdateEvent()
|
|
},
|
|
_renderTextbox: function() {
|
|
this._textbox = $("<div />").dxTextBox({
|
|
value: this.option("value"),
|
|
placeholder: this.option("placeholder"),
|
|
disabled: this.option("disabled"),
|
|
maxLength: this.option("maxLength"),
|
|
keyDownAction: $.proxy(this._handleTextboxKeyDown, this),
|
|
keyUpAction: $.proxy(this._handleTextboxKeyUp, this),
|
|
valueUpdateAction: $.proxy(this._updateValue, this),
|
|
focusOutAction: $.proxy(function() {
|
|
this._popup.hide()
|
|
}, this)
|
|
}).appendTo(this._element()).data("dxTextBox");
|
|
this._caretPosition = {
|
|
start: 0,
|
|
end: 0
|
|
}
|
|
},
|
|
_renderValueUpdateEvent: function() {
|
|
this._changeAction = this._createActionByOption("valueUpdateAction");
|
|
this._textboxOptionChange("valueUpdateEvent", this._getValueUpdateEvent())
|
|
},
|
|
_getValueUpdateEvent: function() {
|
|
var result = this.option("valueUpdateEvent");
|
|
if (!this._hasUpdateEvent("keyup"))
|
|
result += " keyup";
|
|
if (!this._hasUpdateEvent("change"))
|
|
result += " change";
|
|
return result
|
|
},
|
|
_hasUpdateEvent: function(eventName) {
|
|
return eventName && this.option("valueUpdateEvent").indexOf(eventName) !== -1
|
|
},
|
|
_handleTextboxKeyDown: function(e) {
|
|
var $list = this._listElement(),
|
|
preventedKeys = [KEY_TAB, KEY_UP, KEY_DOWN],
|
|
key = e.jQueryEvent.which;
|
|
if ($list.is(":hidden"))
|
|
return;
|
|
if ($.inArray(key, preventedKeys) > -1)
|
|
e.jQueryEvent.preventDefault()
|
|
},
|
|
_updateValue: function(e) {
|
|
var inputElement = this._inputElement();
|
|
this.option("value", this._textbox.option("value"));
|
|
inputElement.prop("selectionStart", this._caretPosition.start);
|
|
inputElement.prop("selectionEnd", this._caretPosition.end);
|
|
var hasUpdateEvent = e.jQueryEvent && this._hasUpdateEvent(e.jQueryEvent.type);
|
|
if (!e.jQueryEvent || hasUpdateEvent)
|
|
this._changeAction(this.option("value"))
|
|
},
|
|
_handleTextboxKeyUp: function(e) {
|
|
var key = e.jQueryEvent.which;
|
|
this._caretPosition = {
|
|
start: this._inputElement().prop("selectionStart"),
|
|
end: this._inputElement().prop("selectionEnd")
|
|
};
|
|
switch (key) {
|
|
case KEY_DOWN:
|
|
this._handleTextboxDownKey();
|
|
break;
|
|
case KEY_UP:
|
|
this._handleTextboxUpKey();
|
|
break;
|
|
case KEY_ENTER:
|
|
this._handleTextboxEnterKey();
|
|
break;
|
|
case KEY_RIGHT:
|
|
case KEY_TAB:
|
|
this._handleTextboxCompleteKeys();
|
|
break;
|
|
case KEY_ESC:
|
|
this._handleTextboxEscKey();
|
|
break;
|
|
default:
|
|
return
|
|
}
|
|
},
|
|
_handleTextboxDownKey: function() {
|
|
var $selectedItem = this._listSelectedItemElement(),
|
|
$nextItem;
|
|
if ($selectedItem.length) {
|
|
$nextItem = $selectedItem.next();
|
|
$nextItem.addClass(SELECTED_ITEM_CLASS);
|
|
$selectedItem.removeClass(SELECTED_ITEM_CLASS)
|
|
}
|
|
else
|
|
this._listItemElement().first().addClass(SELECTED_ITEM_CLASS)
|
|
},
|
|
_handleTextboxUpKey: function() {
|
|
var $selectedItem = this._listSelectedItemElement(),
|
|
$prevItem,
|
|
$list = this._listElement();
|
|
if ($list.is(":hidden"))
|
|
return;
|
|
if (!$selectedItem.length) {
|
|
this._listItemElement().last().addClass(SELECTED_ITEM_CLASS);
|
|
return
|
|
}
|
|
$selectedItem.removeClass(SELECTED_ITEM_CLASS);
|
|
$prevItem = $selectedItem.prev();
|
|
if ($prevItem.length)
|
|
$prevItem.addClass(SELECTED_ITEM_CLASS)
|
|
},
|
|
_handleTextboxEnterKey: function() {
|
|
var $selectedItem = this._listSelectedItemElement(),
|
|
receivedValue;
|
|
if (!$selectedItem.length) {
|
|
this._popup.hide();
|
|
return
|
|
}
|
|
receivedValue = this._selectedItemDataGetter();
|
|
this._caretPosition = {
|
|
start: receivedValue.length,
|
|
end: receivedValue.length
|
|
};
|
|
this.option("value", receivedValue);
|
|
this._popup.hide();
|
|
this._inputElement().blur()
|
|
},
|
|
_handleTextboxCompleteKeys: function() {
|
|
var $list = this._listElement(),
|
|
newValue,
|
|
receivedValue;
|
|
if ($list.is(":hidden"))
|
|
return;
|
|
receivedValue = this._selectedItemDataGetter();
|
|
newValue = receivedValue.length ? receivedValue : this._dataSource.items()[0];
|
|
this._caretPosition = {
|
|
start: newValue.length,
|
|
end: newValue.length
|
|
};
|
|
newValue = this._displayGetter(newValue);
|
|
this.option("value", newValue);
|
|
this._popup.hide()
|
|
},
|
|
_selectedItemDataGetter: function() {
|
|
var $selectedItem = this._listSelectedItemElement();
|
|
if (!$selectedItem.length)
|
|
return [];
|
|
return this._displayGetter($selectedItem.data(LIST_ITEM_DATA_KEY))
|
|
},
|
|
_handleTextboxEscKey: function() {
|
|
this._popup.hide()
|
|
},
|
|
_renderPopup: function() {
|
|
var $textbox = this._textboxElement(),
|
|
textWidth = $textbox.width(),
|
|
$input = this._textbox._input(),
|
|
vOffset = 0,
|
|
hOffset = 0;
|
|
if (DX.devices.current().win8)
|
|
vOffset = -2;
|
|
else if (DX.devices.current().platform === "desktop" || DX.devices.current().tizen)
|
|
vOffset = -1;
|
|
if (DX.devices.current().platform === "desktop")
|
|
hOffset = -1;
|
|
this._popup = $("<div/>").appendTo(this._element()).dxPopup({
|
|
shading: false,
|
|
closeOnOutsideClick: true,
|
|
closeOnTargetScroll: true,
|
|
showTitle: false,
|
|
width: textWidth,
|
|
shownAction: $.proxy(this._handlePopupShown, this),
|
|
showingAction: $.proxy(this._handlePopupShowing, this),
|
|
height: "auto",
|
|
deferRendering: false,
|
|
position: {
|
|
my: "left top",
|
|
at: "left bottom",
|
|
of: $input,
|
|
offset: {
|
|
h: hOffset,
|
|
v: vOffset
|
|
},
|
|
collision: "flip"
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "fade",
|
|
duration: 400,
|
|
from: 0,
|
|
to: 1
|
|
},
|
|
hide: {
|
|
type: "fade",
|
|
duration: 400,
|
|
from: 1,
|
|
to: 0
|
|
}
|
|
}
|
|
}).data("dxPopup");
|
|
this._popup._wrapper().addClass(AUTOCOMPLETE_POPUP_WRAPPER_CLASS);
|
|
this._renderList();
|
|
this._autocompleteResizeCallback = $.proxy(this._calculatePopupWidth, this);
|
|
utils.windowResizeCallbacks.add(this._autocompleteResizeCallback)
|
|
},
|
|
_handlePopupShown: function() {
|
|
var maxHeight = $(window).height() * 0.5;
|
|
if (this._popup.content().height() > maxHeight)
|
|
this._popup.option("height", maxHeight)
|
|
},
|
|
_handlePopupShowing: function() {
|
|
this._calculatePopupWidth()
|
|
},
|
|
_calculatePopupWidth: function() {
|
|
var $textbox = this._textboxElement(),
|
|
textWidth = $textbox.width();
|
|
this._popup.option("width", textWidth)
|
|
},
|
|
_renderList: function() {
|
|
this._list = $("<div />").appendTo(this._popup.content()).dxList({
|
|
itemClickAction: $.proxy(this._handleListItemClick, this),
|
|
itemTemplate: this.option("itemTemplate"),
|
|
itemRender: this._getItemRender(),
|
|
noDataText: "",
|
|
showNextButton: false,
|
|
autoPagingEnabled: false,
|
|
dataSource: this._dataSource
|
|
}).data("dxList");
|
|
this._list.addExternalTemplate(this._templates)
|
|
},
|
|
_getItemRender: function() {
|
|
if (!this.option("itemTemplate"))
|
|
return this.option("itemRender") || $.proxy(this._displayGetter, this)
|
|
},
|
|
_handleListItemClick: function(e) {
|
|
var value = this._displayGetter(e.itemData);
|
|
this._caretPosition = {
|
|
start: value.length,
|
|
end: value.length
|
|
};
|
|
this.option("value", value);
|
|
this._popup.hide();
|
|
this._inputElement().blur()
|
|
},
|
|
_itemsToDataSource: function() {
|
|
this._dataSource = new DevExpress.data.DataSource(this.option("items"));
|
|
return this._dataSource
|
|
},
|
|
_filterDataSource: function() {
|
|
var searchValue = this._textbox.option("value");
|
|
this._reloadDataSource(searchValue);
|
|
this._clearSearchTimer()
|
|
},
|
|
_reloadDataSource: function(searchValue, searchMethod) {
|
|
var self = this,
|
|
ds = self._dataSource;
|
|
ds.searchExpr(self.option("displayExpr"));
|
|
ds.searchOperation(searchMethod || self.option("filterOperator"));
|
|
ds.searchValue(searchValue);
|
|
self._dataSource.pageIndex(0);
|
|
self._dataSource.load().done(function() {
|
|
self._refreshVisibility()
|
|
})
|
|
},
|
|
_refreshVisibility: function() {
|
|
var canFilter = this._textbox.option("value").length >= this.option("minSearchLength"),
|
|
dataSource = this._dataSource,
|
|
items = dataSource && dataSource.items(),
|
|
hasResults = items.length;
|
|
if (canFilter && hasResults)
|
|
if (items.length === 1 && this._displayGetter(items[0]) === this.option("value"))
|
|
this._popup.hide();
|
|
else if (this._displayGetter(items[0]).length < this.option("value").length)
|
|
this._popup.hide();
|
|
else {
|
|
this._popup._refresh();
|
|
this._popup.show()
|
|
}
|
|
else
|
|
this._popup.hide()
|
|
},
|
|
_dispose: function() {
|
|
this._clearSearchTimer();
|
|
utils.windowResizeCallbacks.remove(this._autocompleteResizeCallback);
|
|
this.callBase()
|
|
},
|
|
_textboxOptionChange: function(name, value) {
|
|
this._textbox.option(name, value)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"disabled":
|
|
this.callBase(name, value);
|
|
this._textboxOptionChange(name, value);
|
|
break;
|
|
case"value":
|
|
this._checkExceptions();
|
|
this._textboxOptionChange(name, value);
|
|
this._applyFilter();
|
|
break;
|
|
case"maxLength":
|
|
case"placeholder":
|
|
this._textboxOptionChange(name, value);
|
|
break;
|
|
case"items":
|
|
case"dataSource":
|
|
if (name === "items")
|
|
this._itemsToDataSource();
|
|
else
|
|
this._initDataSource();
|
|
case"itemTemplate":
|
|
case"itemRender":
|
|
this._list.option(name, value);
|
|
break;
|
|
case"filterOperator":
|
|
this._validateFilterOperator();
|
|
break;
|
|
case"displayExpr":
|
|
this._compileDisplayGetter();
|
|
this._list.option("itemRender", this._getItemRender());
|
|
break;
|
|
case"minSearchLength":
|
|
case"searchTimeout":
|
|
break;
|
|
case"valueUpdateEvent":
|
|
case"valueUpdateAction":
|
|
this._renderValueUpdateEvent();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_applyFilter: function() {
|
|
var searchValue = this._textbox.option("value"),
|
|
canFilter = searchValue.length >= this.option("minSearchLength");
|
|
if (!canFilter) {
|
|
this._clearSearchTimer();
|
|
this._popup.hide();
|
|
return
|
|
}
|
|
if (this.option("searchTimeout") > 0) {
|
|
if (!this._searchTimer)
|
|
this._searchTimer = setTimeout($.proxy(this._filterDataSource, this), this.option("searchTimeout"))
|
|
}
|
|
else
|
|
this._filterDataSource()
|
|
},
|
|
_clearSearchTimer: function() {
|
|
clearTimeout(this._searchTimer);
|
|
delete this._searchTimer
|
|
},
|
|
_checkExceptions: function() {
|
|
if (this.option("value") === undefined)
|
|
throw Error("Value option should not be undefined");
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._element().empty()
|
|
}
|
|
}).include(ui.DataHelperMixin))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.dropDownMenu.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events;
|
|
var DROP_DOWN_MENU_CLASS = "dx-dropdownmenu",
|
|
DROP_DOWN_MENU_POPUP_WRAPPER_CLASS = DROP_DOWN_MENU_CLASS + "-popup-wrapper",
|
|
DROP_DOWN_MENU_LIST_CLASS = "dx-dropdownmenu-list",
|
|
DROP_DOWN_MENU_BUTTON_CLASS = "dx-dropdownmenu-button";
|
|
ui.registerComponent("dxDropDownMenu", ui.ContainerWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
items: [],
|
|
itemClickAction: null,
|
|
dataSource: null,
|
|
itemTemplate: "item",
|
|
itemRender: null,
|
|
buttonText: "",
|
|
buttonIcon: null,
|
|
buttonIconSrc: null,
|
|
buttonClickAction: null,
|
|
usePopover: false
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initDataSource();
|
|
this._initItemClickAction()
|
|
},
|
|
_initItemClickAction: function() {
|
|
this._itemClickAction = this._createActionByOption("itemClickAction")
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(DROP_DOWN_MENU_CLASS);
|
|
this._renderButton();
|
|
this.callBase()
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._popup._element().remove()
|
|
},
|
|
_renderContentImpl: function() {
|
|
this._renderPopup()
|
|
},
|
|
_renderButton: function() {
|
|
var buttonIconSrc = this.option("buttonIconSrc"),
|
|
buttonIcon = this.option("buttonIcon");
|
|
if (!buttonIconSrc && !buttonIcon)
|
|
buttonIcon = "overflow";
|
|
this._button = this._element().addClass(DROP_DOWN_MENU_BUTTON_CLASS).dxButton({
|
|
text: this.option("buttonText"),
|
|
icon: buttonIcon,
|
|
iconSrc: buttonIconSrc,
|
|
clickAction: this.option("buttonClickAction")
|
|
}).dxButton("instance")
|
|
},
|
|
_renderClick: function() {
|
|
this.callBase();
|
|
var action = this._createAction(this._handleButtonClick);
|
|
this._element().on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
action({jQueryEvent: e})
|
|
});
|
|
if (this._popup)
|
|
this._popup.option("clickAction", this.option("clickAction"))
|
|
},
|
|
_handleButtonClick: function(e) {
|
|
e.component._popup.toggle()
|
|
},
|
|
_renderList: function(instance) {
|
|
var $content = instance.content(),
|
|
self = this;
|
|
self._list = $content.addClass(DROP_DOWN_MENU_LIST_CLASS).dxList({
|
|
autoPagingEnabled: false,
|
|
noDataText: "",
|
|
itemRender: self.option("itemRender"),
|
|
itemTemplate: self.option("itemTemplate"),
|
|
itemClickAction: function(e) {
|
|
self._popup.hide();
|
|
self._itemClickAction(e)
|
|
}
|
|
}).data("dxList");
|
|
self._list.addExternalTemplate(self._templates);
|
|
self._setListDataSource();
|
|
self._attachListClick();
|
|
var listMaxHeight = $(window).height() * 0.5;
|
|
if ($content.height() > listMaxHeight)
|
|
$content.height(listMaxHeight)
|
|
},
|
|
_toggleVisibility: function(visible) {
|
|
this.callBase(visible);
|
|
this._button.option("visible", visible)
|
|
},
|
|
_attachListClick: function() {
|
|
var action = this._createAction(this._handleListClick);
|
|
this._list._element().off("." + this.NAME).on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
action({jQueryEvent: e})
|
|
})
|
|
},
|
|
_handleListClick: function(e) {
|
|
e.component._popup.hide()
|
|
},
|
|
_renderPopup: function() {
|
|
var $popup = this._$popup = $("<div />").appendTo(this._element());
|
|
var popupOptions = {
|
|
clickAction: this.option("clickAction"),
|
|
contentReadyAction: $.proxy(this._popupContentReadyHandler, this),
|
|
deferRendering: false
|
|
};
|
|
this._popup = this.option("usePopover") ? this._createPopover($popup, popupOptions) : this._createPopup($popup, popupOptions);
|
|
this._popup._wrapper().addClass(DROP_DOWN_MENU_POPUP_WRAPPER_CLASS)
|
|
},
|
|
_popupContentReadyHandler: function() {
|
|
var popup = this._$popup[this.option("usePopover") ? "dxPopover" : "dxPopup"]("instance");
|
|
this._renderList(popup)
|
|
},
|
|
_createPopover: function($element, popupOptions) {
|
|
return $element.dxPopover($.extend(popupOptions, {target: this._element()})).dxPopover("instance")
|
|
},
|
|
_createPopup: function($element, popupOptions) {
|
|
return $element.dxPopup($.extend(popupOptions, {
|
|
showTitle: false,
|
|
width: "auto",
|
|
height: "auto",
|
|
shading: false,
|
|
closeOnOutsideClick: $.proxy(function(e) {
|
|
return !$(e.target).closest(this._button._element()).length
|
|
}, this),
|
|
closeOnTargetScroll: true,
|
|
position: {
|
|
my: "right top",
|
|
at: "right bottom",
|
|
of: this._element(),
|
|
collision: "fit flip"
|
|
},
|
|
animation: {
|
|
show: {
|
|
type: "fade",
|
|
to: 1
|
|
},
|
|
hide: {
|
|
type: "fade",
|
|
to: 0
|
|
}
|
|
}
|
|
})).dxPopup("instance")
|
|
},
|
|
_setListDataSource: function() {
|
|
if (this._list)
|
|
this._list.option("dataSource", this._dataSource || this.option("items"))
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
if (/^button/.test(name)) {
|
|
this._renderButton();
|
|
return
|
|
}
|
|
switch (name) {
|
|
case"items":
|
|
case"dataSource":
|
|
this._refreshDataSource();
|
|
this._setListDataSource();
|
|
break;
|
|
case"itemRender":
|
|
case"itemTemplate":
|
|
if (this._list)
|
|
this._list.option(name, value);
|
|
break;
|
|
case"itemClickAction":
|
|
this._initItemClickAction();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}).include(ui.DataHelperMixin))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.selectBox.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
WIDGET_CLASS = "dx-selectbox",
|
|
POPUP_CLASS = "dx-selectbox-popup",
|
|
SELECTBOX_ARROW_CONTAINER_CLASS = "dx-selectbox-arrow-container",
|
|
SELECTBOX_ARROW_CLASS = "dx-selectbox-arrow";
|
|
ui.registerComponent("dxSelectBox", ui.dxAutocomplete.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
items: [],
|
|
value: undefined,
|
|
valueChangeAction: null,
|
|
placeholder: Globalize.localize("Select"),
|
|
valueExpr: null,
|
|
tooltipEnabled: false
|
|
})
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
if (!this._dataSource)
|
|
this._itemsToDataSource()
|
|
},
|
|
_itemsToDataSource: function() {
|
|
this._dataSource = new DevExpress.data.DataSource(this.option("items"))
|
|
},
|
|
_getValueWidth: function(value) {
|
|
var $div = $("<div />").html(value).css({
|
|
width: "auto",
|
|
position: "fixed",
|
|
top: "-3000px",
|
|
left: "-3000px"
|
|
}).appendTo("body");
|
|
return $div.width()
|
|
},
|
|
_setTooltip: function(value) {
|
|
if (!this.option("tooltipEnabled"))
|
|
return;
|
|
if (this._$element.context.scrollWidth <= this._getValueWidth(value))
|
|
this._$element.context.title = value;
|
|
else
|
|
this._$element.context.title = ""
|
|
},
|
|
_render: function() {
|
|
this._compileValueGetter();
|
|
this.callBase();
|
|
this._setTooltip(this.option("value"));
|
|
this._setWidgetClasses();
|
|
this._renderArrowDown()
|
|
},
|
|
_renderPopup: function() {
|
|
this.callBase();
|
|
if (DX.devices.current().win8) {
|
|
var popupPosition = this._popup.option("position");
|
|
$.extend(popupPosition, {
|
|
at: "left top",
|
|
offset: {
|
|
h: 0,
|
|
v: 2
|
|
}
|
|
});
|
|
this._popup.option("position", popupPosition)
|
|
}
|
|
},
|
|
_renderValueUpdateEvent: function() {
|
|
this._changeAction = this._createActionByOption("valueChangeAction")
|
|
},
|
|
_setWidgetClasses: function() {
|
|
var $selectbox = this._element(),
|
|
$popup = this._popup._element();
|
|
$selectbox.addClass(WIDGET_CLASS);
|
|
$popup.addClass(POPUP_CLASS)
|
|
},
|
|
_renderArrowDown: function() {
|
|
var clickActionHandler = this._createAction(function(e) {
|
|
e.component._popup.toggle()
|
|
});
|
|
$("<div />").addClass(SELECTBOX_ARROW_CONTAINER_CLASS).appendTo(this._element()).on(events.addNamespace("dxclick", this.NAME), function(e) {
|
|
clickActionHandler({jQueryEvent: e})
|
|
});
|
|
$("<div />").addClass(SELECTBOX_ARROW_CLASS).appendTo(this._element().find("." + SELECTBOX_ARROW_CONTAINER_CLASS))
|
|
},
|
|
_applyFilter: $.noop,
|
|
_updateValue: $.noop,
|
|
_renderTextbox: function() {
|
|
this.callBase();
|
|
this._searchValue(this.option("value")).done($.proxy(this._updateTextBox, this))
|
|
},
|
|
_updateTextBox: function(result) {
|
|
this._selectedItem = result;
|
|
this._textbox.option({
|
|
readOnly: true,
|
|
value: this._displayGetter(this._selectedItem),
|
|
clickAction: $.proxy(function() {
|
|
this._popup.toggle()
|
|
}, this)
|
|
})
|
|
},
|
|
_compileValueGetter: function() {
|
|
this._valueGetter = DX.data.utils.compileGetter(this._valueGetterExpr())
|
|
},
|
|
_valueGetterExpr: function() {
|
|
return this.option("valueExpr") || this._dataSource && this._dataSource._store._key || "this"
|
|
},
|
|
_handleListItemClick: function(e) {
|
|
this.option("value", this._valueGetter(e.itemData));
|
|
this._popup.hide()
|
|
},
|
|
_searchValue: function(value) {
|
|
var self = this,
|
|
store = this._dataSource.store(),
|
|
valueExpr = this._valueGetterExpr();
|
|
var deffered = $.Deferred();
|
|
if (valueExpr === store.key() || store instanceof DX.data.CustomStore)
|
|
store.byKey(value).done(function(result) {
|
|
deffered.resolveWith(self, [result])
|
|
});
|
|
else
|
|
store.load({filter: [valueExpr, value]}).done(function(result) {
|
|
deffered.resolveWith(self, result)
|
|
});
|
|
return deffered.promise()
|
|
},
|
|
_changeValueExpr: function() {
|
|
this._compileValueGetter();
|
|
this.option("value", this._valueGetter(this._selectedItem))
|
|
},
|
|
_changeValue: function(value) {
|
|
this._searchValue(value).done($.proxy(this._handleSearchComplete, this));
|
|
this._setTooltip(value)
|
|
},
|
|
_handleSearchComplete: function(result) {
|
|
this._selectedItem = result;
|
|
this._textboxOptionChange("value", this._displayGetter(result));
|
|
this._changeAction(this.option("value"))
|
|
},
|
|
_renderList: function() {
|
|
this.callBase();
|
|
this._list.option("autoPagingEnabled", true)
|
|
},
|
|
_optionChanged: function(name, value) {
|
|
switch (name) {
|
|
case"valueExpr":
|
|
this._changeValueExpr();
|
|
break;
|
|
case"displayExpr":
|
|
this._compileDisplayGetter();
|
|
this._refresh();
|
|
break;
|
|
case"value":
|
|
this._changeValue(value);
|
|
break;
|
|
case"valueChangeAction":
|
|
this._renderValueUpdateEvent();
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.panorama.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
fx = DX.fx,
|
|
translator = DX.translator,
|
|
utils = DX.utils;
|
|
var PANORAMA_CLASS = "dx-panorama",
|
|
PANORAMA_TITLE_CLASS = "dx-panorama-title",
|
|
PANORAMA_GHOST_TITLE_CLASS = "dx-panorama-ghosttitle",
|
|
PANORAMA_ITEMS_CONTAINER_CLASS = "dx-panorama-itemscontainer",
|
|
PANORAMA_ITEM_CLASS = "dx-panorama-item",
|
|
PANORAMA_GHOST_ITEM_CLASS = "dx-panorama-ghostitem",
|
|
PANORAMA_ITEM_HEADER_CLASS = "dx-panorama-item-header",
|
|
PANORAMA_ITEM_DATA_KEY = "dxPanoramaItemData",
|
|
PANORAMA_ITEM_MARGIN_SCALE = .02,
|
|
PANORAMA_TITLE_MARGIN_SCALE = .02,
|
|
PANORAMA_BACKGROUND_MOVE_DURATION = 300,
|
|
PANORAMA_BACKGROUND_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)",
|
|
PANORAMA_TITLE_MOVE_DURATION = 300,
|
|
PANORAMA_TITLE_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)",
|
|
PANORAMA_ITEM_MOVE_DURATION = 300,
|
|
PANORAMA_ITEM_MOVE_EASING = "cubic-bezier(.40, .80, .60, 1)";
|
|
var moveBackground = function($element, position) {
|
|
$element.css("background-position", position + "px 0%")
|
|
};
|
|
var position = function($element) {
|
|
return translator.locate($element).left
|
|
};
|
|
var move = function($element, position) {
|
|
translator.move($element, {left: position})
|
|
};
|
|
var animation = {
|
|
backgroundMove: function($element, position, completeAction) {
|
|
return fx.animate($element, {
|
|
to: {"background-position": position + "px 0%"},
|
|
duration: PANORAMA_BACKGROUND_MOVE_DURATION,
|
|
easing: PANORAMA_BACKGROUND_MOVE_EASING,
|
|
complete: completeAction
|
|
})
|
|
},
|
|
titleMove: function($title, position, completeAction) {
|
|
return fx.animate($title, {
|
|
type: "slide",
|
|
to: {left: position},
|
|
duration: PANORAMA_TITLE_MOVE_DURATION,
|
|
easing: PANORAMA_TITLE_MOVE_EASING,
|
|
complete: completeAction
|
|
})
|
|
},
|
|
itemMove: function($item, position, completeAction) {
|
|
return fx.animate($item, {
|
|
type: "slide",
|
|
to: {left: position},
|
|
duration: PANORAMA_ITEM_MOVE_DURATION,
|
|
easing: PANORAMA_ITEM_MOVE_EASING,
|
|
complete: completeAction
|
|
})
|
|
}
|
|
};
|
|
var endAnimation = function(elements) {
|
|
if (!elements)
|
|
return;
|
|
$.each(elements, function(_, element) {
|
|
fx.stop(element, true)
|
|
})
|
|
};
|
|
var PanoramaItemsRenderStrategy = DX.Class.inherit({
|
|
ctor: function(panorama) {
|
|
this._panorama = panorama
|
|
},
|
|
init: $.noop,
|
|
render: $.noop,
|
|
allItemElements: function() {
|
|
return this._panorama._itemElements()
|
|
},
|
|
updatePositions: DX.abstract,
|
|
animateRollback: DX.abstract,
|
|
detectBoundsTransition: DX.abstract,
|
|
animateComplete: DX.abstract,
|
|
_itemMargin: function() {
|
|
return this._panorama._$itemsContainer.width() * PANORAMA_ITEM_MARGIN_SCALE
|
|
},
|
|
_indexBoundary: function() {
|
|
return this._panorama._indexBoundary()
|
|
},
|
|
_normalizeIndex: function(index) {
|
|
return this._panorama._normalizeIndex(index)
|
|
}
|
|
});
|
|
var PanoramaOneAndLessItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
|
|
updatePositions: function() {
|
|
var $items = this._panorama._itemElements(),
|
|
itemMargin = this._itemMargin();
|
|
$items.each(function() {
|
|
move($(this), itemMargin)
|
|
})
|
|
},
|
|
animateRollback: $.noop,
|
|
detectBoundsTransition: $.noop,
|
|
animateComplete: $.noop
|
|
});
|
|
var PanoramaTwoItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
|
|
init: function() {
|
|
this._initGhostItem()
|
|
},
|
|
render: function() {
|
|
this._renderGhostItem()
|
|
},
|
|
_initGhostItem: function() {
|
|
this._$ghostItem = $("<div>").addClass(PANORAMA_GHOST_ITEM_CLASS)
|
|
},
|
|
_renderGhostItem: function() {
|
|
this._panorama._itemContainer().append(this._$ghostItem);
|
|
this._toggleGhostItem(false)
|
|
},
|
|
_toggleGhostItem: function(visible) {
|
|
var $ghostItem = this._$ghostItem;
|
|
if (visible)
|
|
$ghostItem.css("opacity", 1);
|
|
else
|
|
$ghostItem.css("opacity", 0)
|
|
},
|
|
_updateGhostItemContent: function(index) {
|
|
if (index !== false && index !== this._prevGhostIndex) {
|
|
this._$ghostItem.html(this._panorama._itemElements().eq(index).html());
|
|
this._prevGhostIndex = index
|
|
}
|
|
},
|
|
_isGhostItemVisible: function() {
|
|
return this._$ghostItem.css("opacity") == 1
|
|
},
|
|
_swapGhostWithItem: function($item) {
|
|
var $ghostItem = this._$ghostItem,
|
|
lastItemPosition = position($item);
|
|
move($item, position($ghostItem));
|
|
move($ghostItem, lastItemPosition)
|
|
},
|
|
allItemElements: function() {
|
|
return this._panorama._itemContainer().find("." + PANORAMA_ITEM_CLASS + ", ." + PANORAMA_GHOST_ITEM_CLASS)
|
|
},
|
|
updatePositions: function(offset) {
|
|
var $items = this.allItemElements(),
|
|
selectedIndex = this._panorama.option("selectedIndex"),
|
|
isGhostReplaceLast = offset > 0 && selectedIndex === 0 || offset < 0 && selectedIndex === 1,
|
|
isGhostReplaceFirst = offset < 0 && selectedIndex === 0 || offset > 0 && selectedIndex === 1,
|
|
ghostPosition = isGhostReplaceLast && "replaceLast" || isGhostReplaceFirst && "replaceFirst",
|
|
ghostContentIndex = isGhostReplaceLast && 1 || isGhostReplaceFirst && 0,
|
|
positions = this._calculateItemPositions(selectedIndex, ghostPosition);
|
|
this._updateGhostItemContent(ghostContentIndex);
|
|
this._toggleGhostItem(isGhostReplaceLast || isGhostReplaceFirst);
|
|
$items.each(function(index) {
|
|
move($(this), positions[index] + offset)
|
|
})
|
|
},
|
|
animateRollback: function(currentIndex) {
|
|
var self = this,
|
|
$items = this._panorama._itemElements(),
|
|
itemMargin = this._itemMargin(),
|
|
offset = position($items.eq(currentIndex)) - itemMargin,
|
|
ghostOffset = position(this._$ghostItem) - itemMargin,
|
|
positions = this._calculateItemPositions(currentIndex, ghostOffset > 0 ? "prepend" : "append"),
|
|
isLastReplasedByGhost = currentIndex === 0 && offset > 0 && ghostOffset > 0 || currentIndex === 1 && ghostOffset < 0;
|
|
if (isLastReplasedByGhost)
|
|
this._swapGhostWithItem($items.eq(1));
|
|
else
|
|
this._swapGhostWithItem($items.eq(0));
|
|
$items.each(function(index) {
|
|
animation.itemMove($(this), positions[index])
|
|
});
|
|
animation.itemMove(this._$ghostItem, positions[2], function() {
|
|
self._toggleGhostItem(false)
|
|
})
|
|
},
|
|
detectBoundsTransition: function(newIndex, currentIndex) {
|
|
var ghostLocation = position(this._$ghostItem),
|
|
itemMargin = this._itemMargin();
|
|
if (newIndex === 0 && ghostLocation < itemMargin)
|
|
return "left";
|
|
if (currentIndex === 0 && ghostLocation > itemMargin)
|
|
return "right"
|
|
},
|
|
animateComplete: function(boundCross, newIndex, currentIndex) {
|
|
var self = this,
|
|
ghostPosition = !boundCross ^ !(currentIndex === 0) ? "prepend" : "append",
|
|
$items = this._panorama._itemElements(),
|
|
positions = this._calculateItemPositions(newIndex, ghostPosition),
|
|
animations = [];
|
|
$items.each(function(index) {
|
|
animations.push(animation.itemMove($(this), positions[index]))
|
|
});
|
|
animations.push(animation.itemMove(this._$ghostItem, positions[2], function() {
|
|
self._toggleGhostItem(false)
|
|
}));
|
|
return $.when.apply($, animations)
|
|
},
|
|
_calculateItemPositions: function(atIndex, ghostPosition) {
|
|
var positions = [],
|
|
$items = this._panorama._itemElements(),
|
|
itemMargin = this._itemMargin(),
|
|
itemWidth = $items.eq(0).outerWidth(),
|
|
itemPositionOffset = itemWidth + itemMargin,
|
|
normalFlow = atIndex === 0,
|
|
nextNegativePosition = -itemWidth,
|
|
nextPositivePosition = itemMargin;
|
|
positions.push(nextPositivePosition);
|
|
nextPositivePosition += itemPositionOffset;
|
|
if (normalFlow)
|
|
positions.push(nextPositivePosition);
|
|
else
|
|
positions.splice(0, 0, nextPositivePosition);
|
|
nextPositivePosition += itemPositionOffset;
|
|
switch (ghostPosition) {
|
|
case"replaceFirst":
|
|
positions.push(positions[0]);
|
|
if (normalFlow)
|
|
positions[0] = nextPositivePosition;
|
|
else
|
|
positions[0] = nextNegativePosition;
|
|
break;
|
|
case"replaceLast":
|
|
if (normalFlow)
|
|
positions.splice(1, 0, nextNegativePosition);
|
|
else
|
|
positions.splice(1, 0, nextPositivePosition);
|
|
break;
|
|
case"prepend":
|
|
positions.push(nextNegativePosition);
|
|
break;
|
|
case"append":
|
|
positions.push(nextPositivePosition);
|
|
break
|
|
}
|
|
return positions
|
|
}
|
|
});
|
|
var PanoramaThreeAndMoreItemsRenderStrategy = PanoramaItemsRenderStrategy.inherit({
|
|
updatePositions: function(offset) {
|
|
var $items = this._panorama._itemElements(),
|
|
positions = this._calculateItemPositions(this._panorama.option("selectedIndex"), offset < 0);
|
|
$items.each(function(index) {
|
|
move($(this), positions[index] + offset)
|
|
})
|
|
},
|
|
animateRollback: function() {
|
|
var $items = this._panorama._itemElements(),
|
|
selectedIndex = this._panorama.option("selectedIndex"),
|
|
positions = this._calculateItemPositions(selectedIndex),
|
|
animatingItems = [selectedIndex, this._normalizeIndex(selectedIndex + 1)];
|
|
if (position($items.eq(selectedIndex)) > this._itemMargin())
|
|
animatingItems.push(this._normalizeIndex(selectedIndex - 1));
|
|
$items.each(function(index) {
|
|
var $item = $(this);
|
|
if ($.inArray(index, animatingItems) !== -1)
|
|
animation.itemMove($item, positions[index]);
|
|
else
|
|
move($item, positions[index])
|
|
})
|
|
},
|
|
detectBoundsTransition: function(newIndex, currentIndex) {
|
|
var lastIndex = this._indexBoundary() - 1;
|
|
if (currentIndex === lastIndex && newIndex === 0)
|
|
return "left";
|
|
if (currentIndex === 0 && newIndex === lastIndex)
|
|
return "right"
|
|
},
|
|
animateComplete: function(boundCross, newIndex, currentIndex) {
|
|
var animations = [],
|
|
$items = this._panorama._itemElements(),
|
|
positions = this._calculateItemPositions(newIndex);
|
|
var transitionToRight = this._normalizeIndex(currentIndex - 1) === newIndex,
|
|
cyclingItemIndex = $items.length === 3 && transitionToRight ? this._normalizeIndex(currentIndex + 1) : null,
|
|
cyclingItemPosition = positions[this._indexBoundary()];
|
|
var animatingItems = [newIndex, currentIndex],
|
|
rightAnimatedItemIndex = transitionToRight ? currentIndex : newIndex;
|
|
if (!transitionToRight)
|
|
animatingItems.push(this._normalizeIndex(rightAnimatedItemIndex + 1));
|
|
$items.each(function(index) {
|
|
var $item = $(this);
|
|
if ($.inArray(index, animatingItems) === -1) {
|
|
move($item, positions[index]);
|
|
return
|
|
}
|
|
animations.push(index !== cyclingItemIndex ? animation.itemMove($item, positions[index]) : animation.itemMove($item, cyclingItemPosition, function() {
|
|
move($item, positions[index])
|
|
}))
|
|
});
|
|
return $.when.apply($, animations)
|
|
},
|
|
_calculateItemPositions: function(atIndex, preferRight) {
|
|
var previousIndex = this._normalizeIndex(atIndex - 1),
|
|
$items = this._panorama._itemElements(),
|
|
itemMargin = this._itemMargin(),
|
|
itemWidth = $items.eq(0).outerWidth(),
|
|
itemPositionOffset = itemWidth + itemMargin,
|
|
positions = [],
|
|
nextNegativePosition = -itemWidth,
|
|
nextPositivePosition = itemMargin;
|
|
for (var i = atIndex; i !== previousIndex; i = this._normalizeIndex(i + 1)) {
|
|
positions[i] = nextPositivePosition;
|
|
nextPositivePosition += itemPositionOffset
|
|
}
|
|
if (preferRight) {
|
|
positions[previousIndex] = nextPositivePosition;
|
|
nextPositivePosition += itemPositionOffset
|
|
}
|
|
else
|
|
positions[previousIndex] = nextNegativePosition;
|
|
positions.push(nextPositivePosition);
|
|
return positions
|
|
}
|
|
});
|
|
ui.registerComponent("dxPanorama", ui.SelectableCollectionWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
selectedIndex: 0,
|
|
title: "panorama",
|
|
backgroundImage: {
|
|
url: null,
|
|
width: 0,
|
|
height: 0
|
|
}
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return PANORAMA_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return PANORAMA_ITEM_DATA_KEY
|
|
},
|
|
_itemContainer: function() {
|
|
return this._$itemsContainer
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._initItemsRenderStrategy();
|
|
this._initBackgroundImage();
|
|
this._initTitle();
|
|
this._initItemsContainer();
|
|
utils.windowResizeCallbacks.add(this._windowResizeCallBack = $.proxy(this._handleWindowResize, this));
|
|
this._initSwipeHandlers()
|
|
},
|
|
_dispose: function() {
|
|
this.callBase.apply(this, arguments);
|
|
utils.windowResizeCallbacks.remove(this._windowResizeCallBack)
|
|
},
|
|
_initItemsRenderStrategy: function() {
|
|
var itemsRenderStrategy;
|
|
switch (this.option("items").length) {
|
|
case 0:
|
|
case 1:
|
|
itemsRenderStrategy = PanoramaOneAndLessItemsRenderStrategy;
|
|
break;
|
|
case 2:
|
|
itemsRenderStrategy = PanoramaTwoItemsRenderStrategy;
|
|
break;
|
|
default:
|
|
itemsRenderStrategy = PanoramaThreeAndMoreItemsRenderStrategy
|
|
}
|
|
this._itemsRenderStrategy = new itemsRenderStrategy(this);
|
|
this._itemsRenderStrategy.init()
|
|
},
|
|
_initBackgroundImage: function() {
|
|
var bgUrl = this.option("backgroundImage.url");
|
|
if (bgUrl)
|
|
this._element().css("background-image", "url(" + bgUrl + ")")
|
|
},
|
|
_initTitle: function() {
|
|
this._$title = $("<div>").addClass(PANORAMA_TITLE_CLASS);
|
|
this._$ghostTitle = $("<div>").addClass(PANORAMA_GHOST_TITLE_CLASS);
|
|
this._element().append(this._$title);
|
|
this._element().append(this._$ghostTitle);
|
|
this._updateTitle()
|
|
},
|
|
_updateTitle: function() {
|
|
var title = this.option("title");
|
|
this._$title.text(title);
|
|
this._$ghostTitle.text(title);
|
|
this._toggleGhostTitle(false)
|
|
},
|
|
_toggleGhostTitle: function(visible) {
|
|
var $ghostTitle = this._$ghostTitle;
|
|
if (visible)
|
|
$ghostTitle.css("opacity", 1);
|
|
else
|
|
$ghostTitle.css("opacity", 0)
|
|
},
|
|
_initItemsContainer: function() {
|
|
this._$itemsContainer = $("<div>").addClass(PANORAMA_ITEMS_CONTAINER_CLASS);
|
|
this._element().append(this._$itemsContainer)
|
|
},
|
|
_handleWindowResize: function() {
|
|
this._updatePositions()
|
|
},
|
|
_render: function() {
|
|
this._element().addClass(PANORAMA_CLASS);
|
|
this.callBase();
|
|
this._itemsRenderStrategy.render()
|
|
},
|
|
_updatePositions: function(offset) {
|
|
offset = offset || 0;
|
|
this._updateBackgroundPosition(offset * this._calculateBackgroundStep());
|
|
this._updateTitlePosition(offset * this._calculateTitleStep());
|
|
this._itemsRenderStrategy.updatePositions(offset * this._$itemsContainer.width())
|
|
},
|
|
_updateBackgroundPosition: function(offset) {
|
|
moveBackground(this._element(), this._calculateBackgroundPosition(this.option("selectedIndex")) + offset)
|
|
},
|
|
_updateTitlePosition: function(offset) {
|
|
move(this._$title, this._calculateTitlePosition(this.option("selectedIndex")) + offset)
|
|
},
|
|
_animateRollback: function(currentIndex) {
|
|
this._animateBackgroundMove(currentIndex);
|
|
this._animateTitleMove(currentIndex);
|
|
this._itemsRenderStrategy.animateRollback(currentIndex)
|
|
},
|
|
_animateBackgroundMove: function(toIndex) {
|
|
return animation.backgroundMove(this._element(), this._calculateBackgroundPosition(toIndex))
|
|
},
|
|
_animateTitleMove: function(toIndex) {
|
|
return animation.titleMove(this._$title, this._calculateTitlePosition(toIndex))
|
|
},
|
|
_animateComplete: function(newIndex, currentIndex) {
|
|
var self = this,
|
|
boundCross = this._itemsRenderStrategy.detectBoundsTransition(newIndex, currentIndex);
|
|
var backgroundAnimation = this._performBackgroundAnimation(boundCross, newIndex);
|
|
var titleAnimation = this._performTitleAnimation(boundCross, newIndex);
|
|
var itemsAnimation = this._itemsRenderStrategy.animateComplete(boundCross, newIndex, currentIndex);
|
|
$.when(backgroundAnimation, titleAnimation, itemsAnimation).done(function() {
|
|
self._indexChangeOnAnimation = true;
|
|
self.option("selectedIndex", newIndex);
|
|
self._indexChangeOnAnimation = false
|
|
})
|
|
},
|
|
_performBackgroundAnimation: function(boundCross, newIndex) {
|
|
if (boundCross)
|
|
return this._animateBackgroundBoundsTransition(boundCross, newIndex);
|
|
return this._animateBackgroundMove(newIndex)
|
|
},
|
|
_animateBackgroundBoundsTransition: function(bound, newIndex) {
|
|
var self = this,
|
|
isLeft = bound === "left",
|
|
afterAnimationPosition = this._calculateBackgroundPosition(newIndex),
|
|
animationEndPositionShift = isLeft ? -this._calculateBackgroundScaledWidth() : this._calculateBackgroundScaledWidth(),
|
|
animationEndPosition = afterAnimationPosition + animationEndPositionShift;
|
|
return animation.backgroundMove(this._element(), animationEndPosition, function() {
|
|
moveBackground(self._element(), afterAnimationPosition)
|
|
})
|
|
},
|
|
_performTitleAnimation: function(boundCross, newIndex) {
|
|
if (boundCross)
|
|
return this._animateTitleBoundsTransition(boundCross, newIndex);
|
|
return this._animateTitleMove(newIndex)
|
|
},
|
|
_animateTitleBoundsTransition: function(bound, newIndex) {
|
|
var self = this,
|
|
$ghostTitle = this._$ghostTitle,
|
|
ghostWidth = $ghostTitle.outerWidth(),
|
|
panoramaWidth = this._element().width(),
|
|
isLeft = bound === "left",
|
|
ghostTitleStartPosition = isLeft ? panoramaWidth : -ghostWidth,
|
|
ghostTitleEndPosition = isLeft ? -(panoramaWidth + ghostWidth) : panoramaWidth;
|
|
move($ghostTitle, ghostTitleStartPosition);
|
|
this._toggleGhostTitle(true);
|
|
this._swapGhostWithTitle();
|
|
var ghostAnimation = animation.titleMove($ghostTitle, ghostTitleEndPosition, function() {
|
|
self._toggleGhostTitle(false)
|
|
});
|
|
var titleAnimation = animation.titleMove(this._$title, this._calculateTitlePosition(newIndex));
|
|
return $.when(ghostAnimation, titleAnimation)
|
|
},
|
|
_swapGhostWithTitle: function() {
|
|
var $ghostTitle = this._$ghostTitle,
|
|
$title = this._$title,
|
|
lastTitlePosition = position($title);
|
|
move($title, position($ghostTitle));
|
|
move($ghostTitle, lastTitlePosition)
|
|
},
|
|
_calculateTitlePosition: function(atIndex) {
|
|
var panoramaWidth = this._element().width(),
|
|
titleMargin = panoramaWidth * PANORAMA_TITLE_MARGIN_SCALE;
|
|
return titleMargin - atIndex * this._calculateTitleStep()
|
|
},
|
|
_calculateTitleStep: function() {
|
|
var panoramaWidth = this._element().width(),
|
|
titleWidth = this._$title.outerWidth(),
|
|
indexBoundary = this._indexBoundary() || 1;
|
|
return Math.max((titleWidth - panoramaWidth) / indexBoundary, titleWidth / indexBoundary)
|
|
},
|
|
_calculateBackgroundPosition: function(atIndex) {
|
|
return -(atIndex * this._calculateBackgroundStep())
|
|
},
|
|
_calculateBackgroundStep: function() {
|
|
var itemWidth = this._itemElements().eq(0).outerWidth(),
|
|
backgroundScaledWidth = this._calculateBackgroundScaledWidth();
|
|
return Math.max((backgroundScaledWidth - itemWidth) / (this._indexBoundary() || 1), 0)
|
|
},
|
|
_calculateBackgroundScaledWidth: function() {
|
|
return this._element().height() * this.option("backgroundImage.width") / (this.option("backgroundImage.height") || 1)
|
|
},
|
|
_initSwipeHandlers: function() {
|
|
this._element().on(events.addNamespace("dxswipestart", this.NAME), $.proxy(this._swipeStartHandler, this)).on(events.addNamespace("dxswipe", this.NAME), $.proxy(this._swipeUpdateHandler, this)).on(events.addNamespace("dxswipeend", this.NAME), $.proxy(this._swipeEndHandler, this))
|
|
},
|
|
_swipeStartHandler: function(e) {
|
|
this._stopAnimations();
|
|
if (this.option("disabled") || this._indexBoundary() <= 1)
|
|
e.cancel = true
|
|
},
|
|
_stopAnimations: function() {
|
|
endAnimation([this._element(), this._$ghostTitle, this._$title]);
|
|
endAnimation(this._itemsRenderStrategy.allItemElements())
|
|
},
|
|
_swipeUpdateHandler: function(e) {
|
|
this._updatePositions(e.offset)
|
|
},
|
|
_swipeEndHandler: function(e) {
|
|
var currentIndex = this.option("selectedIndex"),
|
|
targetOffset = e.targetOffset;
|
|
if (targetOffset === 0)
|
|
this._animateRollback(currentIndex);
|
|
else
|
|
this._animateComplete(this._normalizeIndex(currentIndex - targetOffset), currentIndex)
|
|
},
|
|
_renderSelectedIndex: function(current, previous) {
|
|
if (!this._indexChangeOnAnimation)
|
|
this._updatePositions()
|
|
},
|
|
_normalizeIndex: function(index) {
|
|
var boundary = this._indexBoundary();
|
|
if (index < 0)
|
|
index = boundary + index;
|
|
if (index >= boundary)
|
|
index = index - boundary;
|
|
return index
|
|
},
|
|
_indexBoundary: function() {
|
|
return this.option("items").length
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"title":
|
|
this._updateTitle();
|
|
break;
|
|
case"items":
|
|
this._initItemsRenderStrategy();
|
|
this.callBase.apply(this, arguments);
|
|
break;
|
|
default:
|
|
this.callBase.apply(this, arguments)
|
|
}
|
|
},
|
|
_itemRenderDefault: function(item, index, $itemElement) {
|
|
this.callBase(item, index, $itemElement);
|
|
if (!item.header)
|
|
return;
|
|
var $itemHeader = $("<div>").addClass(PANORAMA_ITEM_HEADER_CLASS).text(item.header);
|
|
$itemElement.prepend($itemHeader)
|
|
}
|
|
}));
|
|
ui.dxPanorama.__internals = {animation: animation}
|
|
})(jQuery, DevExpress);
|
|
/*! Module widgets, file ui.slideout.js */
|
|
(function($, DX, undefined) {
|
|
var ui = DX.ui,
|
|
events = ui.events,
|
|
fx = DX.fx,
|
|
utils = DX.utils,
|
|
translator = DX.translator;
|
|
var SLIDEOUT_CLASS = "dx-slideout",
|
|
SLIDEOUT_ITEM_CONTAINER_CLASS = "dx-slideout-item-container",
|
|
SLIDEOUT_MENU = "dx-slideout-menu",
|
|
SLIDEOUT_ITEM_CLASS = "dx-slideout-item",
|
|
SLIDEOUT_ITEM_DATA_KEY = "dxSlideoutItemData",
|
|
CONTENT_OFFSET = 45,
|
|
ANIMATION_DURATION = 400;
|
|
ui.registerComponent("dxSlideOut", ui.SelectableCollectionWidget.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
menuItemRender: null,
|
|
menuItemTemplate: "menuItem",
|
|
swipeEnabled: true,
|
|
menuVisible: false
|
|
})
|
|
},
|
|
_itemClass: function() {
|
|
return SLIDEOUT_ITEM_CLASS
|
|
},
|
|
_itemDataKey: function() {
|
|
return SLIDEOUT_ITEM_DATA_KEY
|
|
},
|
|
_init: function() {
|
|
this.callBase();
|
|
this._deferredAnimate = undefined
|
|
},
|
|
_render: function() {
|
|
this._$shield = $("<div />").addClass("dx-slideout-shield");
|
|
this._renderItemsContainer();
|
|
this._renderList();
|
|
this._initSwipeHandlers();
|
|
this._element().addClass(SLIDEOUT_CLASS);
|
|
this.callBase();
|
|
this._initWindowResizeCallback();
|
|
this._renderPosition(this.option("menuVisible") ? 1 : 0, false)
|
|
},
|
|
_initWindowResizeCallback: function() {
|
|
var self = this;
|
|
this._windowResizeCallback = function() {
|
|
self._renderPosition(self.option("menuVisible") ? 1 : 0, false)
|
|
};
|
|
utils.windowResizeCallbacks.add(this._windowResizeCallback)
|
|
},
|
|
_renderItemsContainer: function() {
|
|
this._$container = $("<div />").addClass(SLIDEOUT_ITEM_CONTAINER_CLASS).appendTo(this._element());
|
|
this._$container.on("MSPointerDown", function(e){})
|
|
},
|
|
_renderContentImpl: function(template) {
|
|
var items = this.option("items"),
|
|
selectedIndex = this.option("selectedIndex");
|
|
if (items.length && selectedIndex > -1)
|
|
this._renderItems([items[selectedIndex]])
|
|
},
|
|
_renderList: function() {
|
|
this._$list = $("<div />").addClass(SLIDEOUT_MENU).prependTo(this._element());
|
|
this._renderItemClickAction();
|
|
var list = this._$list.dxList().dxList("instance");
|
|
list.addExternalTemplate(this._templates);
|
|
this._$list.dxList({
|
|
height: "100%",
|
|
itemClickAction: $.proxy(this._handleListItemClick, this),
|
|
items: this.option("items"),
|
|
dataSource: this.option("dataSource"),
|
|
itemRender: this.option("menuItemRender"),
|
|
itemTemplate: this.option("menuItemTemplate")
|
|
})
|
|
},
|
|
_handleListItemClick: function(e) {
|
|
var selectedIndex = this._$list.find(".dx-list-item").index(e.itemElement);
|
|
this.option("selectedIndex", selectedIndex);
|
|
this._itemClickAction(e)
|
|
},
|
|
_renderItemClickAction: function() {
|
|
this._itemClickAction = this._createActionByOption("itemClickAction")
|
|
},
|
|
_renderItem: function(index, item, container) {
|
|
this._$container.find("." + SLIDEOUT_ITEM_CLASS).remove();
|
|
this.callBase(index, item, this._$container)
|
|
},
|
|
_renderSelectedIndex: function() {
|
|
this._renderContent()
|
|
},
|
|
_initSwipeHandlers: function() {
|
|
this._$container.dxSwipeable({
|
|
elastic: false,
|
|
itemSizeFunc: $.proxy(this._getListWidth, this),
|
|
startAction: $.proxy(this.option("swipeEnabled") ? this._handleSwipeStart : function(e) {
|
|
e.jQueryEvent.cancel = true
|
|
}, this),
|
|
updateAction: $.proxy(this._handleSwipeUpdate, this),
|
|
endAction: $.proxy(this._handleSwipeEnd, this)
|
|
})
|
|
},
|
|
_handleSwipeStart: function(e) {
|
|
this._$shield.detach();
|
|
e.jQueryEvent.maxLeftOffset = this.option("menuVisible") ? 1 : 0;
|
|
e.jQueryEvent.maxRightOffset = this.option("menuVisible") ? 0 : 1
|
|
},
|
|
_handleSwipeUpdate: function(e) {
|
|
var offset = this.option("menuVisible") ? e.jQueryEvent.offset + 1 : e.jQueryEvent.offset;
|
|
this._renderPosition(offset, false)
|
|
},
|
|
_handleSwipeEnd: function(e) {
|
|
var targetOffset = e.jQueryEvent.targetOffset + this.option("menuVisible"),
|
|
menuVisible = targetOffset !== 0;
|
|
if (this.option("menuVisible") === menuVisible)
|
|
this._renderPosition(this.option("menuVisible") ? 1 : 0, true);
|
|
else
|
|
this.option("menuVisible", targetOffset !== 0)
|
|
},
|
|
_handleMenuButtonClick: function() {
|
|
this.option("menuVisible", !this.option("menuVisible"))
|
|
},
|
|
_toggleMenuVisibility: function(visible, animate) {
|
|
this.option("menuVisible", visible)
|
|
},
|
|
_renderPosition: function(offset, animate) {
|
|
var pos = this._calculatePixelOffset(offset);
|
|
if (animate) {
|
|
this._$shield.detach();
|
|
fx.animate(this._$container, {
|
|
type: "slide",
|
|
to: {left: pos},
|
|
duration: ANIMATION_DURATION,
|
|
complete: $.proxy(this._handleAnimationComplete, this)
|
|
})
|
|
}
|
|
else
|
|
translator.move(this._$container, {left: pos})
|
|
},
|
|
_calculatePixelOffset: function(offset) {
|
|
var offset = offset || 0,
|
|
maxOffset = this._getListWidth();
|
|
return offset * maxOffset
|
|
},
|
|
_getListWidth: function() {
|
|
var listWidth = this._$list.width(),
|
|
elementWidth = this._element().width() - CONTENT_OFFSET;
|
|
return Math.min(elementWidth, listWidth)
|
|
},
|
|
_changeMenuOption: function(name, value) {
|
|
this._$list.dxList("instance").option(name, value)
|
|
},
|
|
_optionChanged: function(name, value, prevValue) {
|
|
switch (name) {
|
|
case"menuVisible":
|
|
this._renderPosition(value ? 1 : 0, true);
|
|
break;
|
|
case"swipeEnabled":
|
|
this._initSwipeHandlers();
|
|
break;
|
|
case"menuItemRender":
|
|
this._changeMenuOption("itemRender", value);
|
|
break;
|
|
case"menuItemTemplate":
|
|
this._changeMenuOption("itemTemplate", value);
|
|
break;
|
|
case"items":
|
|
case"dataSource":
|
|
this._changeMenuOption(name, value);
|
|
break;
|
|
case"itemClickAction":
|
|
this._renderItemClickAction();
|
|
break;
|
|
default:
|
|
this.callBase(name, value, prevValue)
|
|
}
|
|
},
|
|
_handleAnimationComplete: function() {
|
|
this._$shield.appendTo(this._$container);
|
|
if (this._deferredAnimate)
|
|
this._deferredAnimate.resolveWith(this)
|
|
},
|
|
_dispose: function() {
|
|
utils.windowResizeCallbacks.remove(this._windowResizeCallback);
|
|
this.callBase()
|
|
},
|
|
showMenu: function() {
|
|
return this.toggleMenuVisibility(true)
|
|
},
|
|
hideMenu: function() {
|
|
return this.toggleMenuVisibility(false)
|
|
},
|
|
toggleMenuVisibility: function(showing) {
|
|
showing = showing === undefined ? !this.option("menuVisible") : showing;
|
|
this._deferredAnimate = $.Deferred();
|
|
this.option("menuVisible", showing);
|
|
return this._deferredAnimate.promise()
|
|
}
|
|
}))
|
|
})(jQuery, DevExpress);
|
|
DevExpress.MOD_WIDGETS = true
|
|
}
|
|
if (!DevExpress.MOD_FRAMEWORK) {
|
|
if (!window.DevExpress)
|
|
throw Error('Required module is not referenced: core');
|
|
/*! Module framework, file framework.js */
|
|
(function($, DX, undefined) {
|
|
var mergeWithReplace = function(destination, source, needReplaceFn) {
|
|
var result = [];
|
|
for (var i = 0, destinationLength = destination.length; i < destinationLength; i++)
|
|
if (!needReplaceFn(destination[i], source))
|
|
result.push(destination[i]);
|
|
result.push.apply(result, source);
|
|
return result
|
|
};
|
|
var getMergeCommands = function() {
|
|
return function(destination, source) {
|
|
return mergeWithReplace(destination, source, function(destObject, source) {
|
|
return $.grep(source, function(srcObject) {
|
|
return destObject.option("id") === srcObject.option("id") && srcObject.option("id") || destObject.option("behavior") === srcObject.option("behavior") && destObject.option("behavior")
|
|
}).length
|
|
})
|
|
}
|
|
};
|
|
DX.framework = {utils: {mergeCommands: getMergeCommands()}}
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.routing.js */
|
|
(function($, DX) {
|
|
var Class = DX.Class;
|
|
DX.framework.Route = Class.inherit({
|
|
_trimSeparators: function(str) {
|
|
return str.replace(/^[\/.]+|\/+$/g, "")
|
|
},
|
|
_escapeRe: function(str) {
|
|
return str.replace(/\W/g, "\\$1")
|
|
},
|
|
_checkConstraint: function(param, constraint) {
|
|
param = String(param);
|
|
if (typeof constraint === "string")
|
|
constraint = new RegExp(constraint);
|
|
var match = constraint.exec(param);
|
|
if (!match || match[0] !== param)
|
|
return false;
|
|
return true
|
|
},
|
|
_ensureReady: function() {
|
|
var self = this;
|
|
if (this._patternRe)
|
|
return false;
|
|
this._pattern = this._trimSeparators(this._pattern);
|
|
this._patternRe = "";
|
|
this._params = [];
|
|
this._segments = [];
|
|
this._separators = [];
|
|
this._pattern.replace(/[^\/]+/g, function(segment, index) {
|
|
self._segments.push(segment);
|
|
if (index)
|
|
self._separators.push(self._pattern.substr(index - 1, 1))
|
|
});
|
|
$.each(this._segments, function(index) {
|
|
var isStatic = true,
|
|
segment = this,
|
|
separator = index ? self._separators[index - 1] : "";
|
|
if (segment.charAt(0) === ":") {
|
|
isStatic = false;
|
|
segment = segment.substr(1);
|
|
self._params.push(segment);
|
|
self._patternRe += "(?:" + separator + "([^/]+))";
|
|
if (segment in self._defaults)
|
|
self._patternRe += "?"
|
|
}
|
|
else
|
|
self._patternRe += separator + self._escapeRe(segment)
|
|
});
|
|
this._patternRe = new RegExp("^" + this._patternRe + "$")
|
|
},
|
|
ctor: function(pattern, defaults, constraints) {
|
|
this._pattern = pattern || "";
|
|
this._defaults = defaults || {};
|
|
this._constraints = constraints || {}
|
|
},
|
|
parse: function(uri) {
|
|
var self = this;
|
|
this._ensureReady();
|
|
var matches = this._patternRe.exec(uri);
|
|
if (!matches)
|
|
return false;
|
|
var result = $.extend({}, this._defaults);
|
|
$.each(this._params, function(i) {
|
|
var index = i + 1;
|
|
if (matches.length >= index && matches[index])
|
|
result[this] = self.parseSegment(matches[index])
|
|
});
|
|
$.each(this._constraints, function(key) {
|
|
if (!self._checkConstraint(result[key], self._constraints[key])) {
|
|
result = false;
|
|
return false
|
|
}
|
|
});
|
|
return result
|
|
},
|
|
format: function(routeValues) {
|
|
var self = this,
|
|
query = "";
|
|
this._ensureReady();
|
|
var mergeValues = $.extend({}, this._defaults),
|
|
useStatic = 0,
|
|
ret = [],
|
|
dels = [],
|
|
unusedRouteValues = {};
|
|
$.each(routeValues, function(paramName, paramValue) {
|
|
routeValues[paramName] = self.formatSegment(paramValue);
|
|
if (!(paramName in mergeValues))
|
|
unusedRouteValues[paramName] = true
|
|
});
|
|
$.each(this._segments, function(index, segment) {
|
|
ret[index] = index ? self._separators[index - 1] : '';
|
|
if (segment.charAt(0) === ':') {
|
|
var paramName = segment.substr(1);
|
|
if (!(paramName in routeValues) && !(paramName in self._defaults)) {
|
|
ret = null;
|
|
return false
|
|
}
|
|
if (paramName in self._constraints && !self._checkConstraint(routeValues[paramName], self._constraints[paramName])) {
|
|
ret = null;
|
|
return false
|
|
}
|
|
if (paramName in routeValues) {
|
|
if (routeValues[paramName] !== undefined) {
|
|
mergeValues[paramName] = routeValues[paramName];
|
|
ret[index] += routeValues[paramName];
|
|
useStatic = index
|
|
}
|
|
delete unusedRouteValues[paramName]
|
|
}
|
|
else if (paramName in mergeValues) {
|
|
ret[index] += mergeValues[paramName];
|
|
dels.push(index)
|
|
}
|
|
}
|
|
else {
|
|
ret[index] += segment;
|
|
useStatic = index
|
|
}
|
|
});
|
|
$.each(mergeValues, function(key, value) {
|
|
if (!!value && $.inArray(":" + key, self._segments) === -1 && routeValues[key] !== value) {
|
|
ret = null;
|
|
return false
|
|
}
|
|
});
|
|
var unusedCount = 0;
|
|
if (!$.isEmptyObject(unusedRouteValues)) {
|
|
query = "?";
|
|
$.each(unusedRouteValues, function(key) {
|
|
query += key + "=" + routeValues[key] + "&";
|
|
unusedCount++
|
|
});
|
|
query = query.substr(0, query.length - 1)
|
|
}
|
|
$.each(routeValues, function(i) {
|
|
if (!this in mergeValues) {
|
|
ret = null;
|
|
return false
|
|
}
|
|
});
|
|
if (ret === null)
|
|
return false;
|
|
if (dels.length)
|
|
$.map(dels, function(i) {
|
|
if (i >= useStatic)
|
|
ret[i] = ''
|
|
});
|
|
var path = ret.join('');
|
|
path = path.replace(/\/+$/, "");
|
|
return {
|
|
uri: path + query,
|
|
unusedCount: unusedCount
|
|
}
|
|
},
|
|
formatSegment: function(value) {
|
|
if ($.isArray(value) || $.isPlainObject(value))
|
|
return "json:" + encodeURIComponent(JSON.stringify(value));
|
|
return encodeURIComponent(value)
|
|
},
|
|
parseSegment: function(value) {
|
|
if (value.substr(0, 5) === "json:")
|
|
try {
|
|
return $.parseJSON(decodeURIComponent(value.substr(5)))
|
|
}
|
|
catch(x) {}
|
|
return decodeURIComponent(value)
|
|
}
|
|
});
|
|
DX.framework.MvcRouter = DX.Class.inherit({
|
|
ctor: function() {
|
|
this._registry = []
|
|
},
|
|
_trimSeparators: function(str) {
|
|
return str.replace(/^[\/.]+|\/+$/g, "")
|
|
},
|
|
_createRoute: function(pattern, defaults, constraints) {
|
|
return new DX.framework.Route(pattern, defaults, constraints)
|
|
},
|
|
register: function(pattern, defaults, constraints) {
|
|
this._registry.push(this._createRoute(pattern, defaults, constraints))
|
|
},
|
|
_parseQuery: function(query) {
|
|
var result = {},
|
|
values = query.split("&");
|
|
$.each(values, function(index, value) {
|
|
var keyValuePair = value.split("=");
|
|
result[keyValuePair[0]] = keyValuePair[1]
|
|
});
|
|
return result
|
|
},
|
|
parse: function(uri) {
|
|
var self = this,
|
|
ret;
|
|
uri = this._trimSeparators(uri);
|
|
var parts = uri.split("?", 2),
|
|
path = parts[0],
|
|
query = parts[1];
|
|
$.each(this._registry, function() {
|
|
var result = this.parse(path);
|
|
if (result !== false) {
|
|
ret = result;
|
|
if (query)
|
|
ret = $.extend(ret, self._parseQuery(query));
|
|
return false
|
|
}
|
|
});
|
|
return ret ? ret : false
|
|
},
|
|
format: function(obj) {
|
|
var ret = false,
|
|
minUnusedCount = 99999;
|
|
obj = obj || {};
|
|
$.each(this._registry, function() {
|
|
var toFormat = $.extend(true, {}, obj);
|
|
var result = this.format(toFormat);
|
|
if (result !== false)
|
|
if (minUnusedCount > result.unusedCount) {
|
|
minUnusedCount = result.unusedCount;
|
|
ret = result.uri
|
|
}
|
|
});
|
|
return ret
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.command.js */
|
|
(function($, DX) {
|
|
var ui = DX.ui;
|
|
DX.framework.dxCommand = ui.Component.inherit({
|
|
ctor: function(element, options) {
|
|
if ($.isPlainObject(element)) {
|
|
options = element;
|
|
element = $("<div />")
|
|
}
|
|
this.beforeExecute = $.Callbacks();
|
|
this.afterExecute = $.Callbacks();
|
|
this.callBase(element, options)
|
|
},
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
action: null,
|
|
id: null,
|
|
title: "",
|
|
icon: "",
|
|
iconSrc: "",
|
|
visible: true,
|
|
disabled: false
|
|
})
|
|
},
|
|
execute: function() {
|
|
var isDisabled = this._options.disabled;
|
|
if ($.isFunction(isDisabled))
|
|
isDisabled = !!isDisabled.apply(this, arguments);
|
|
if (isDisabled)
|
|
throw new Error(DX.utils.stringFormat("Cannot execute command: {0}", this._options.id));
|
|
this.beforeExecute.fire(arguments);
|
|
this._createActionByOption("action", {allowedForGesture: true}).apply(this, arguments);
|
|
this.afterExecute.fire(arguments)
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-command")
|
|
},
|
|
_renderDisabledState: $.noop,
|
|
_dispose: function() {
|
|
this.callBase();
|
|
this._element().removeData(this.NAME);
|
|
this.beforeExecute.empty();
|
|
this.afterExecute.empty()
|
|
}
|
|
});
|
|
ui.registerComponent("dxCommand", DX.framework.dxCommand)
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.commandMapping.js */
|
|
(function($, DX) {
|
|
DX.framework.CommandMapping = DX.Class.inherit({
|
|
ctor: function() {
|
|
this._commandMappings = {};
|
|
this._containerDefaults = {}
|
|
},
|
|
setDefaults: function(containerId, defaults) {
|
|
this._containerDefaults[containerId] = defaults;
|
|
return this
|
|
},
|
|
mapCommands: function(containerId, commandMappings) {
|
|
var self = this;
|
|
$.each(commandMappings, function(index, commandMapping) {
|
|
if (typeof commandMapping === "string")
|
|
commandMapping = {id: commandMapping};
|
|
var commandId = commandMapping.id;
|
|
var mappings = self._commandMappings[containerId] || {};
|
|
mappings[commandId] = $.extend({
|
|
showIcon: true,
|
|
showText: true
|
|
}, self._containerDefaults[containerId] || {}, commandMapping);
|
|
self._commandMappings[containerId] = mappings
|
|
});
|
|
this._initExistingCommands();
|
|
return this
|
|
},
|
|
unmapCommands: function(containerId, commandIds) {
|
|
var self = this;
|
|
$.each(commandIds, function(index, commandId) {
|
|
var mappings = self._commandMappings[containerId] || {};
|
|
if (mappings)
|
|
delete mappings[commandId]
|
|
});
|
|
this._initExistingCommands()
|
|
},
|
|
getCommandMappingForContainer: function(commandId, containerId) {
|
|
return (this._commandMappings[containerId] || {})[commandId]
|
|
},
|
|
checkCommandsExist: function(commands) {
|
|
var self = this,
|
|
result = $.grep(commands, function(commandName, index) {
|
|
return $.inArray(commandName, self._existingCommands) < 0 && $.inArray(commandName, commands) === index
|
|
});
|
|
if (result.length !== 0)
|
|
throw new Error("The '" + result.join("', '") + "' command" + (result.length === 1 ? " is" : "s are") + " not registred in the application's command mapping. See http://dxpr.es/1bTjfj1 for more details.");
|
|
},
|
|
load: function(config) {
|
|
if (!config)
|
|
return;
|
|
var self = this;
|
|
$.each(config, function(name, container) {
|
|
self.setDefaults(name, container.defaults);
|
|
self.mapCommands(name, container.commands)
|
|
});
|
|
return this
|
|
},
|
|
_initExistingCommands: function() {
|
|
var self = this;
|
|
this._existingCommands = [];
|
|
$.each(self._commandMappings, function(name, _commands) {
|
|
$.each(_commands, function(index, command) {
|
|
if ($.inArray(command.id, self._existingCommands) < 0)
|
|
self._existingCommands.push(command.id)
|
|
})
|
|
})
|
|
}
|
|
});
|
|
DX.framework.CommandMapping.defaultMapping = {
|
|
"global-navigation": {
|
|
defaults: {
|
|
showIcon: true,
|
|
showText: true
|
|
},
|
|
commands: []
|
|
},
|
|
"ios-header-toolbar": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true,
|
|
location: "right"
|
|
},
|
|
commands: ["edit", "save", {
|
|
id: "back",
|
|
location: "left"
|
|
}, {
|
|
id: "cancel",
|
|
location: "left"
|
|
}, {
|
|
id: "create",
|
|
showIcon: true,
|
|
showText: false
|
|
}]
|
|
},
|
|
"ios-action-sheet": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true
|
|
},
|
|
commands: []
|
|
},
|
|
"ios-view-footer": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true
|
|
},
|
|
commands: [{
|
|
id: "delete",
|
|
type: "danger"
|
|
}]
|
|
},
|
|
"android-header-toolbar": {
|
|
defaults: {
|
|
showIcon: true,
|
|
showText: false,
|
|
location: "right"
|
|
},
|
|
commands: [{
|
|
id: "back",
|
|
showIcon: false,
|
|
location: "left"
|
|
}, "create", "edit", "save", {
|
|
id: "cancel",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "delete",
|
|
showText: true,
|
|
location: "menu"
|
|
}]
|
|
},
|
|
"android-simple-toolbar": {
|
|
defaults: {
|
|
showIcon: true,
|
|
showText: false,
|
|
location: "right"
|
|
},
|
|
commands: [{
|
|
id: "back",
|
|
showIcon: false,
|
|
location: "left"
|
|
}, {id: "create"}, {
|
|
id: "save",
|
|
showText: true,
|
|
location: "left"
|
|
}, {
|
|
id: "edit",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "cancel",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "delete",
|
|
showText: true,
|
|
location: "menu"
|
|
}]
|
|
},
|
|
"android-footer-toolbar": {
|
|
defaults: {location: "right"},
|
|
commands: [{
|
|
id: "create",
|
|
showText: false,
|
|
location: "center"
|
|
}, {
|
|
id: "edit",
|
|
showText: false,
|
|
location: "left"
|
|
}, {
|
|
id: "delete",
|
|
location: "menu"
|
|
}, {
|
|
id: "save",
|
|
showIcon: false,
|
|
location: "left"
|
|
}]
|
|
},
|
|
"tizen-header-toolbar": {
|
|
defaults: {
|
|
showIcon: true,
|
|
showText: false,
|
|
location: "right"
|
|
},
|
|
commands: [{
|
|
id: "back",
|
|
showIcon: false,
|
|
location: "left"
|
|
}, "create", "edit", "save", {
|
|
id: "cancel",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "delete",
|
|
showText: true,
|
|
location: "menu"
|
|
}]
|
|
},
|
|
"tizen-footer-toolbar": {
|
|
defaults: {location: "right"},
|
|
commands: [{
|
|
id: "create",
|
|
showText: false
|
|
}, {
|
|
id: "edit",
|
|
showText: false,
|
|
location: "left"
|
|
}, {
|
|
id: "delete",
|
|
location: "menu"
|
|
}, {
|
|
id: "save",
|
|
showIcon: false,
|
|
location: "left"
|
|
}]
|
|
},
|
|
"tizen-simple-toolbar": {
|
|
defaults: {
|
|
showIcon: true,
|
|
showText: false,
|
|
location: "right"
|
|
},
|
|
commands: [{
|
|
id: "back",
|
|
showIcon: false,
|
|
location: "left"
|
|
}, {id: "create"}, {
|
|
id: "save",
|
|
showText: true,
|
|
location: "left"
|
|
}, {
|
|
id: "edit",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "cancel",
|
|
showText: true,
|
|
location: "menu"
|
|
}, {
|
|
id: "delete",
|
|
showText: true,
|
|
location: "menu"
|
|
}]
|
|
},
|
|
"generic-header-toolbar": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true,
|
|
location: "right"
|
|
},
|
|
commands: ["edit", "save", {
|
|
id: "back",
|
|
location: "left"
|
|
}, {
|
|
id: "cancel",
|
|
location: "left"
|
|
}, {
|
|
id: "create",
|
|
showIcon: true,
|
|
showText: false
|
|
}]
|
|
},
|
|
"generic-view-footer": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true
|
|
},
|
|
commands: [{
|
|
id: "delete",
|
|
type: "danger"
|
|
}]
|
|
},
|
|
"win8-appbar": {
|
|
defaults: {location: "right"},
|
|
commands: ["edit", "cancel", "save", "delete", {
|
|
id: "create",
|
|
location: "left"
|
|
}]
|
|
},
|
|
"win8-toolbar": {
|
|
defaults: {
|
|
showText: false,
|
|
location: "left"
|
|
},
|
|
commands: [{id: "previousPage"}]
|
|
},
|
|
"win8-phone-appbar": {
|
|
defaults: {location: "center"},
|
|
commands: ["create", "edit", "cancel", "save", {
|
|
id: "delete",
|
|
location: "menu"
|
|
}]
|
|
},
|
|
"desktop-toolbar": {
|
|
defaults: {
|
|
showIcon: false,
|
|
showText: true,
|
|
location: "right"
|
|
},
|
|
commands: ["cancel", "create", "edit", "save", {
|
|
id: "delete",
|
|
type: "danger"
|
|
}]
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.viewCache.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
DX.framework.ViewCache = Class.inherit({
|
|
ctor: function() {
|
|
this._cache = {}
|
|
},
|
|
setView: function(key, viewInfo) {
|
|
this._cache[key] = viewInfo
|
|
},
|
|
getView: function(key) {
|
|
return this._cache[key]
|
|
},
|
|
removeView: function(key) {
|
|
var result = this._cache[key];
|
|
delete this._cache[key];
|
|
return result
|
|
},
|
|
clear: function() {
|
|
this._cache = {}
|
|
},
|
|
hasView: function(key) {
|
|
return key in this._cache
|
|
}
|
|
});
|
|
DX.framework.NullViewCache = Class.inherit({
|
|
setView: $.noop,
|
|
getView: $.noop,
|
|
removeView: $.noop,
|
|
clear: $.noop,
|
|
hasView: $.noop
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.stateManager.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
DX.framework.MemoryKeyValueStorage = Class.inherit({
|
|
ctor: function() {
|
|
this.storage = {}
|
|
},
|
|
getItem: function(key) {
|
|
return this.storage[key]
|
|
},
|
|
setItem: function(key, value) {
|
|
this.storage[key] = value
|
|
},
|
|
removeItem: function(key) {
|
|
delete this.storage[key]
|
|
}
|
|
});
|
|
DX.framework.StateManager = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.storage = options.storage || new DX.framework.MemoryKeyValueStorage;
|
|
this.stateSources = options.stateSources || []
|
|
},
|
|
addStateSource: function(stateSource) {
|
|
this.stateSources.push(stateSource)
|
|
},
|
|
removeStateSource: function(stateSource) {
|
|
var index = $.inArray(stateSource, this.stateSources);
|
|
if (index > -1) {
|
|
this.stateSources.splice(index, 1);
|
|
stateSource.removeState(this.storage)
|
|
}
|
|
},
|
|
saveState: function() {
|
|
var self = this;
|
|
$.each(this.stateSources, function(index, stateSource) {
|
|
stateSource.saveState(self.storage)
|
|
})
|
|
},
|
|
restoreState: function() {
|
|
var self = this;
|
|
$.each(this.stateSources, function(index, stateSource) {
|
|
stateSource.restoreState(self.storage)
|
|
})
|
|
},
|
|
clearState: function() {
|
|
var self = this;
|
|
$.each(this.stateSources, function(index, stateSource) {
|
|
stateSource.removeState(self.storage)
|
|
})
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.browserAdapters.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
var ROOT_PAGE_URL = "__root__";
|
|
DX.framework.DefaultBrowserAdapter = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this._window = options.window || window;
|
|
this.popState = $.Callbacks();
|
|
$(this._window).on("hashchange", $.proxy(this._onHashChange, this))
|
|
},
|
|
replaceState: function(uri) {
|
|
uri = this._normalizeUri(uri);
|
|
this._window.history.replaceState(null, null, "#" + uri)
|
|
},
|
|
pushState: function(uri) {
|
|
uri = this._normalizeUri(uri);
|
|
this._window.history.pushState(null, null, "#" + uri)
|
|
},
|
|
createRootPage: function() {
|
|
this._window.history.replaceState(null, null, "#" + ROOT_PAGE_URL)
|
|
},
|
|
_onHashChange: function() {
|
|
this.popState.fire()
|
|
},
|
|
back: function() {
|
|
this._window.history.back()
|
|
},
|
|
getHash: function() {
|
|
return this._normalizeUri(this._window.location.hash)
|
|
},
|
|
isRootPage: function() {
|
|
return this.getHash() === ROOT_PAGE_URL
|
|
},
|
|
_normalizeUri: function(uri) {
|
|
return (uri || "").replace(/^#+/, "")
|
|
},
|
|
canBack: function() {
|
|
return this._window.history.length > 2
|
|
}
|
|
});
|
|
DX.framework.OldBrowserAdapter = DX.framework.DefaultBrowserAdapter.inherit({
|
|
ctor: function() {
|
|
this._innerEventCount = 0;
|
|
this.callBase.apply(this, arguments)
|
|
},
|
|
replaceState: function(uri) {
|
|
uri = this._normalizeUri(uri);
|
|
if (this.getHash() !== uri) {
|
|
this._skipNextEvent();
|
|
this.back();
|
|
this._skipNextEvent();
|
|
this._window.location.hash = uri
|
|
}
|
|
},
|
|
pushState: function(uri) {
|
|
uri = this._normalizeUri(uri);
|
|
if (this.getHash() !== uri) {
|
|
this._skipNextEvent();
|
|
this._window.location.hash = uri
|
|
}
|
|
},
|
|
createRootPage: function() {
|
|
this.pushState(ROOT_PAGE_URL)
|
|
},
|
|
_onHashChange: function() {
|
|
if (this._innerEventCount)
|
|
this._innerEventCount--;
|
|
else
|
|
this.popState.fire()
|
|
},
|
|
_skipNextEvent: function() {
|
|
this._innerEventCount++
|
|
}
|
|
});
|
|
DX.framework.HistorylessBrowserAdapter = DX.framework.DefaultBrowserAdapter.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this._window = options.window || window;
|
|
this.popState = $.Callbacks();
|
|
$(this._window).on("dxback", $.proxy(this._onHashChange, this));
|
|
this._currentHash = this._window.location.hash
|
|
},
|
|
replaceState: function(uri) {
|
|
this._currentHash = this._normalizeUri(uri)
|
|
},
|
|
pushState: function(uri) {
|
|
this._currentHash = this._normalizeUri(uri)
|
|
},
|
|
createRootPage: function() {
|
|
this.pushState(ROOT_PAGE_URL)
|
|
},
|
|
_onHashChange: function() {
|
|
this.back();
|
|
this.popState.fire()
|
|
},
|
|
getHash: function() {
|
|
return this._normalizeUri(this._currentHash)
|
|
},
|
|
back: function() {
|
|
this.replaceState(ROOT_PAGE_URL)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.browserNavigationDevice.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
var SESSION_KEY = "dxPhoneJSApplication";
|
|
DX.framework.BrowserNavigationDevice = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this._browserAdapter = this._createBrowserAdapter(options);
|
|
this.uriChanged = $.Callbacks();
|
|
this.backInitiated = $.Callbacks();
|
|
this._deferredNavigate = null;
|
|
this._browserAdapter.popState.add($.proxy(this._onPopState, this));
|
|
if (window.sessionStorage && !sessionStorage.getItem(SESSION_KEY)) {
|
|
sessionStorage.removeItem(SESSION_KEY);
|
|
this._prepareBrowserHistory()
|
|
}
|
|
if (this._browserAdapter.isRootPage())
|
|
this._browserAdapter.pushState("");
|
|
$(window).unload(this._saveBrowserState())
|
|
},
|
|
_isBuggyAndroid: function() {
|
|
var version = DX.devices.real.version;
|
|
return DX.devices.real.platform === "android" && version.length > 1 && (version[0] === 2 && version[1] < 4 || version[0] < 2)
|
|
},
|
|
_createBrowserAdapter: function(options) {
|
|
var sourceWindow = options.window || window;
|
|
if (sourceWindow === sourceWindow.top)
|
|
if (sourceWindow.history.replaceState && sourceWindow.history.pushState && !this._isBuggyAndroid())
|
|
return new DX.framework.DefaultBrowserAdapter(options);
|
|
else
|
|
return new DX.framework.OldBrowserAdapter(options);
|
|
else
|
|
return new DX.framework.HistorylessBrowserAdapter(options)
|
|
},
|
|
_saveBrowserState: function() {
|
|
if (window.sessionStorage)
|
|
sessionStorage.setItem(SESSION_KEY, true)
|
|
},
|
|
_prepareBrowserHistory: function() {
|
|
var hash = this.getUri();
|
|
this._browserAdapter.createRootPage();
|
|
this._browserAdapter.pushState(hash)
|
|
},
|
|
getUri: function() {
|
|
return this._browserAdapter.getHash()
|
|
},
|
|
setUri: function(uri) {
|
|
if (this._browserAdapter.isRootPage())
|
|
this._browserAdapter.pushState(uri);
|
|
else
|
|
this._browserAdapter.replaceState(uri)
|
|
},
|
|
_onPopState: function(uri) {
|
|
var self = this,
|
|
currentHash = this.getUri();
|
|
if (this._deferredNavigate && this._deferredNavigate.state() === "pending")
|
|
if (this._browserAdapter.isRootPage())
|
|
this._deferredNavigate.resolve();
|
|
else
|
|
this._browserAdapter.back();
|
|
else if (this._browserAdapter.isRootPage())
|
|
this.backInitiated.fire();
|
|
else {
|
|
this._deferredNavigate = $.Deferred().done(function() {
|
|
self.uriChanged.fire(currentHash)
|
|
});
|
|
this._browserAdapter.back()
|
|
}
|
|
},
|
|
back: function() {
|
|
this._browserAdapter.back()
|
|
},
|
|
canBack: function() {
|
|
return this._browserAdapter.canBack()
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.navigationManager.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
var NAVIGATION_TARGETS = {
|
|
current: "current",
|
|
blank: "blank",
|
|
back: "back"
|
|
},
|
|
STORAGE_HISTORY_KEY = "__history";
|
|
DX.framework.NavigationStack = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.itemsRemoved = $.Callbacks();
|
|
this.clear()
|
|
},
|
|
currentItem: function() {
|
|
return this.items[this.currentIndex]
|
|
},
|
|
back: function(uri) {
|
|
this.currentIndex--;
|
|
if (this.currentIndex < 0)
|
|
throw Error("Unable to go back");
|
|
var currentItem = this.currentItem();
|
|
if (currentItem.uri !== uri)
|
|
this._updateItem(this.currentIndex, uri)
|
|
},
|
|
forward: function() {
|
|
this.currentIndex++;
|
|
if (this.currentIndex >= this.items.length)
|
|
throw Error("Unable to go forward");
|
|
},
|
|
navigate: function(uri, replaceCurrent) {
|
|
if (this.currentIndex < this.items.length && this.currentIndex > -1 && this.items[this.currentIndex].uri === uri)
|
|
return;
|
|
if (replaceCurrent && this.currentIndex > -1)
|
|
this.currentIndex--;
|
|
if (this.currentIndex + 1 < this.items.length && this.items[this.currentIndex + 1].uri === uri)
|
|
this.currentIndex++;
|
|
else {
|
|
var toDelete = this.items.splice(this.currentIndex + 1, this.items.length - this.currentIndex - 1);
|
|
this.items.push({});
|
|
this.currentIndex++;
|
|
this._updateItem(this.currentIndex, uri);
|
|
this._deleteItems(toDelete)
|
|
}
|
|
return this.currentItem()
|
|
},
|
|
_updateItem: function(index, uri) {
|
|
var item = this.items[index];
|
|
item.uri = uri;
|
|
item.key = this.items[0].uri + "_" + index + "_" + uri
|
|
},
|
|
_deleteItems: function(items) {
|
|
if (items)
|
|
this.itemsRemoved.fire(items)
|
|
},
|
|
getPreviousItem: function() {
|
|
return this.items.length > 1 ? this.items[this.currentIndex - 1] : undefined
|
|
},
|
|
canBack: function() {
|
|
return this.currentIndex > 0
|
|
},
|
|
clear: function() {
|
|
this._deleteItems(this.items);
|
|
this.items = [];
|
|
this.currentIndex = -1
|
|
}
|
|
});
|
|
DX.framework.NavigationManager = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
var self = this;
|
|
self.navigationStacks = {};
|
|
self._keepPositionInStack = options.keepPositionInStack;
|
|
self.currentStack = new DX.framework.NavigationStack;
|
|
self.currentUri = undefined;
|
|
self.navigating = $.Callbacks();
|
|
self.navigated = $.Callbacks();
|
|
self.navigatingBack = $.Callbacks();
|
|
self.navigationCanceled = $.Callbacks();
|
|
self.itemRemoved = $.Callbacks();
|
|
self._navigationDevice = options.navigationDevice || new DX.framework.BrowserNavigationDevice;
|
|
self._navigationDevice.uriChanged.add($.proxy(self.navigate, self));
|
|
self._navigationDevice.backInitiated.add($.proxy(self.back, self));
|
|
self._stateStorageKey = options.stateStorageKey || STORAGE_HISTORY_KEY
|
|
},
|
|
navigate: function(uri, options) {
|
|
var self = this;
|
|
options = $.extend({target: NAVIGATION_TARGETS.blank}, options || {});
|
|
if (uri === undefined)
|
|
uri = self._navigationDevice.getUri();
|
|
while (DX.backButtonCallback.fire());
|
|
if (/^_back$/.test(uri)) {
|
|
self.back();
|
|
return
|
|
}
|
|
var args = {
|
|
currentUri: self.currentUri,
|
|
uri: uri,
|
|
options: options,
|
|
cancel: false,
|
|
navigateWhen: []
|
|
};
|
|
self.navigating.fire(args);
|
|
uri = args.uri;
|
|
if (args.cancel || self.currentUri === uri) {
|
|
self._navigationDevice.setUri(self.currentUri);
|
|
self.navigationCanceled.fire(args)
|
|
}
|
|
else
|
|
$.when.apply($, args.navigateWhen).done(function() {
|
|
DX.utils.executeAsync(function() {
|
|
var previousUri = self.currentUri;
|
|
self.currentUri = uri;
|
|
self._updateHistory(uri, options);
|
|
self._navigationDevice.setUri(self.currentUri);
|
|
self.navigated.fire({
|
|
uri: uri,
|
|
previousUri: previousUri,
|
|
options: options,
|
|
item: self.currentItem()
|
|
})
|
|
})
|
|
})
|
|
},
|
|
_createNavigationStack: function() {
|
|
var result = new DX.framework.NavigationStack;
|
|
result.itemsRemoved.add($.proxy(this._removeItems, this));
|
|
return result
|
|
},
|
|
_updateHistory: function(uri, options) {
|
|
var isRoot = options.root,
|
|
forceIsRoot = isRoot,
|
|
forceToRoot = false;
|
|
if (isRoot || !this.currentStack.items.length) {
|
|
this.navigationStacks[uri] = this.navigationStacks[uri] || this._createNavigationStack();
|
|
if (this.currentStack === this.navigationStacks[uri])
|
|
forceToRoot = true;
|
|
else
|
|
this.currentStack = this.navigationStacks[uri];
|
|
forceIsRoot = true
|
|
}
|
|
if (isRoot && this.currentStack.items.length)
|
|
if (this._keepPositionInStack && options.root && !forceToRoot)
|
|
this.currentUri = this.currentItem().uri;
|
|
else {
|
|
this.currentStack.currentIndex = 0;
|
|
if (this.currentItem().uri !== uri)
|
|
this.currentStack.navigate(uri, true)
|
|
}
|
|
else {
|
|
var prevIndex = this.currentStack.currentIndex,
|
|
prevItem = this.currentItem() || {};
|
|
switch (options.target) {
|
|
case NAVIGATION_TARGETS.blank:
|
|
this.currentStack.navigate(uri);
|
|
break;
|
|
case NAVIGATION_TARGETS.current:
|
|
this.currentStack.navigate(uri, true);
|
|
break;
|
|
case NAVIGATION_TARGETS.back:
|
|
if (this.currentStack.currentIndex > 0)
|
|
this.currentStack.back(uri);
|
|
else
|
|
this.currentStack.navigate(uri, true);
|
|
break;
|
|
default:
|
|
throw Error(DX.utils.stringFormat("Unknown navigation target: \"{0}\". Use the DevExpress.framework.NavigationManager.NAVIGATION_TARGETS enumerable values", options.target));
|
|
}
|
|
if (options.direction === undefined) {
|
|
var indexDelta = this.currentStack.currentIndex - prevIndex;
|
|
if (indexDelta < 0)
|
|
options.direction = this.currentItem().backDirection || "backward";
|
|
else if (indexDelta > 0 && this.currentStack.currentIndex > 0)
|
|
options.direction = "forward";
|
|
else
|
|
options.direction = "none"
|
|
}
|
|
prevItem.backDirection = options.direction === "forward" ? "backward" : "none"
|
|
}
|
|
options.root = forceIsRoot
|
|
},
|
|
_removeItems: function(items) {
|
|
var self = this;
|
|
$.each(items, function(index, item) {
|
|
self.itemRemoved.fire(item)
|
|
})
|
|
},
|
|
back: function(alternate) {
|
|
var navigatingBackArgs = {cancel: DX.backButtonCallback.fire()};
|
|
if (!navigatingBackArgs.cancel)
|
|
this.navigatingBack.fire(navigatingBackArgs);
|
|
if (navigatingBackArgs.cancel) {
|
|
this._navigationDevice.setUri(this.currentUri);
|
|
return
|
|
}
|
|
var item = this.getPreviousItem();
|
|
if (item)
|
|
this.navigate(item.uri, {
|
|
target: NAVIGATION_TARGETS.back,
|
|
item: item
|
|
});
|
|
else if (alternate)
|
|
this.navigate(alternate);
|
|
else
|
|
this._navigateDeviceBack()
|
|
},
|
|
_navigateDeviceBack: function() {
|
|
this._navigationDevice.back()
|
|
},
|
|
getPreviousItem: function() {
|
|
return this.currentStack.getPreviousItem()
|
|
},
|
|
currentItem: function() {
|
|
return this.currentStack.currentItem()
|
|
},
|
|
currentIndex: function() {
|
|
return this.currentStack.currentIndex
|
|
},
|
|
rootUri: function() {
|
|
return this.currentStack.items.length ? this.currentStack.items[0].uri : this.currentUri
|
|
},
|
|
canBack: function() {
|
|
return this.currentStack.canBack() || DX.backButtonCallback.hasCallback()
|
|
},
|
|
getItemByIndex: function(index) {
|
|
return this.currentStack.items[index]
|
|
},
|
|
saveState: function(storage) {
|
|
if (this.currentStack.items.length) {
|
|
var state = {
|
|
items: this.currentStack.items,
|
|
currentIndex: this.currentStack.currentIndex,
|
|
currentStackKey: this.currentStack.items[0].uri
|
|
};
|
|
var json = JSON.stringify(state);
|
|
storage.setItem(this._stateStorageKey, json)
|
|
}
|
|
else
|
|
this.removeState(storage)
|
|
},
|
|
restoreState: function(storage) {
|
|
if (this.disableRestoreState)
|
|
return;
|
|
var json = storage.getItem(this._stateStorageKey);
|
|
if (json)
|
|
try {
|
|
var state = JSON.parse(json),
|
|
stack = this._createNavigationStack();
|
|
if (!state.items[0].uri)
|
|
throw Error("Error while application state restoring. State has been cleared. Refresh the page");
|
|
stack.items = state.items;
|
|
stack.currentIndex = state.currentIndex;
|
|
this.navigationStacks[stack.items[0].uri] = stack;
|
|
this.currentStack = this.navigationStacks[state.currentStackKey];
|
|
this._navigationDevice.setUri(this.currentItem().uri)
|
|
}
|
|
catch(e) {
|
|
this.removeState(storage);
|
|
throw e;
|
|
}
|
|
},
|
|
removeState: function(storage) {
|
|
storage.removeItem(this._stateStorageKey)
|
|
},
|
|
clearHistory: function() {
|
|
this.currentStack.clear()
|
|
}
|
|
});
|
|
DX.framework.NavigationManager.NAVIGATION_TARGETS = NAVIGATION_TARGETS
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.actionExecutors.js */
|
|
(function($, DX, undefined) {
|
|
DX.framework.createActionExecutors = function(app) {
|
|
return {
|
|
routing: {execute: function(e) {
|
|
if ($.isPlainObject(e.action)) {
|
|
var toBack = e.action.backBehaviour;
|
|
if (e.action.backBehaviour)
|
|
delete e.action.backBehaviour;
|
|
var routeValues = e.action,
|
|
uri = app.router.format(routeValues);
|
|
if (toBack)
|
|
app.back(uri);
|
|
else
|
|
app.navigate(uri);
|
|
e.handled = true
|
|
}
|
|
}},
|
|
hash: {execute: function(e) {
|
|
if (typeof e.action !== "string" || e.action.charAt(0) !== "#")
|
|
return;
|
|
var uriTemplate = e.action.substr(1),
|
|
args = e.args[0],
|
|
uri = uriTemplate;
|
|
var defaultEvaluate = function(expr) {
|
|
var getter = DX.data.utils.compileGetter(expr),
|
|
model = e.args[0].model;
|
|
return getter(model)
|
|
};
|
|
var evaluate = args.evaluate || defaultEvaluate;
|
|
uri = uriTemplate.replace(/\{([^}]+)\}/g, function(entry, expr) {
|
|
expr = $.trim(expr);
|
|
if (expr.indexOf(",") > -1)
|
|
expr = $.map(expr.split(","), $.trim);
|
|
var value = evaluate(expr);
|
|
value = DX.framework.Route.prototype.formatSegment(value);
|
|
return value !== undefined ? value : entry
|
|
});
|
|
var navigateOptions = (e.component || {}).NAME === "dxCommand" ? e.component.option() : {};
|
|
app.navigate(uri, navigateOptions);
|
|
e.handled = true
|
|
}}
|
|
}
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.application.js */
|
|
(function($, DX) {
|
|
var Class = DX.Class,
|
|
BACK_COMMAND_TITLE,
|
|
INIT_IN_PROGRESS = "InProgress",
|
|
INIT_COMPLETE = "Inited",
|
|
frameworkNS = DX.framework;
|
|
DX.framework.Application = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this._options = options;
|
|
this.namespace = options.namespace || options.ns || window;
|
|
this.components = [];
|
|
BACK_COMMAND_TITLE = DX.localization.localizeString("@Back");
|
|
this.router = options.router || new DX.framework.MvcRouter;
|
|
this.navigationManager = options.navigationManager || new DX.framework.NavigationManager({keepPositionInStack: options.navigateToRootViewMode === "keepHistory"});
|
|
this.navigationManager.navigating.add($.proxy(this._onNavigating, this));
|
|
this.navigationManager.navigated.add($.proxy(this._onNavigated, this));
|
|
this.navigationManager.navigationCanceled.add($.proxy(this._onNavigationCanceled, this));
|
|
this.navigationManager.itemRemoved.add($.proxy(this._onNavigationItemRemoved, this));
|
|
this.stateManager = options.stateManager || new DX.framework.StateManager({storage: options.stateStorage || sessionStorage});
|
|
this.stateManager.addStateSource(this.navigationManager);
|
|
this._viewCache = options.disableViewCache ? new DX.framework.NullViewCache : options.viewCache || new DX.framework.ViewCache;
|
|
this.navigation = this._createNavigationCommands(options.navigation);
|
|
this.commandMapping = this._createCommandMapping(options.commandMapping, this.navigation);
|
|
this.beforeViewSetup = $.Callbacks();
|
|
this.afterViewSetup = $.Callbacks();
|
|
this.viewShowing = $.Callbacks();
|
|
this.viewShown = $.Callbacks();
|
|
this.viewHidden = $.Callbacks();
|
|
this.viewDisposing = $.Callbacks();
|
|
this.viewDisposed = $.Callbacks();
|
|
this.navigating = $.Callbacks();
|
|
this.initialized = $.Callbacks();
|
|
this._isNavigating = false;
|
|
this._viewsToDispose = [];
|
|
DX.registerActionExecutor(DX.framework.createActionExecutors(this));
|
|
DX.overlayTargetContainer(".dx-viewport");
|
|
this.components.push(this.router);
|
|
this.components.push(this.navigationManager)
|
|
},
|
|
_createCommandMapping: function(commandMapping, navigationCommands) {
|
|
var result = commandMapping;
|
|
if (!(commandMapping instanceof DX.framework.CommandMapping)) {
|
|
result = new DX.framework.CommandMapping;
|
|
result.load(DX.framework.CommandMapping.defaultMapping || {}).load(commandMapping || {})
|
|
}
|
|
var navigationCommandIds = $.map(navigationCommands, function(command) {
|
|
return command.option("id")
|
|
});
|
|
result.mapCommands("global-navigation", navigationCommandIds);
|
|
return result
|
|
},
|
|
_createNavigationCommands: function(commandConfig) {
|
|
if (!commandConfig)
|
|
return [];
|
|
var self = this,
|
|
generatedIdCount = 0;
|
|
return $.map(commandConfig, function(item) {
|
|
var command;
|
|
if (item instanceof frameworkNS.dxCommand)
|
|
command = item;
|
|
else
|
|
command = new frameworkNS.dxCommand($.extend({root: true}, item));
|
|
if (!command.option("id"))
|
|
command.option("id", "navigation_" + generatedIdCount++);
|
|
return command
|
|
})
|
|
},
|
|
_callComponentMethod: function(methodName, args) {
|
|
var tasks = [];
|
|
$.each(this.components, function(index, component) {
|
|
if (component[methodName] && $.isFunction(component[methodName])) {
|
|
var result = component[methodName](args);
|
|
if (result && result.done)
|
|
tasks.push(result)
|
|
}
|
|
});
|
|
return $.when.apply($, tasks)
|
|
},
|
|
init: function() {
|
|
var self = this;
|
|
self._initState = INIT_IN_PROGRESS;
|
|
return self._callComponentMethod("init").done(function() {
|
|
self._initState = INIT_COMPLETE;
|
|
self._processEvent("initialized")
|
|
})
|
|
},
|
|
_onNavigating: function(args) {
|
|
var self = this;
|
|
if (self._isNavigating) {
|
|
self._pendingNavigationArgs = args;
|
|
args.cancel = true;
|
|
return
|
|
}
|
|
else {
|
|
self._isNavigating = true;
|
|
delete self._pendingNavigationArgs
|
|
}
|
|
var routeData = this.router.parse(args.uri);
|
|
if (!routeData)
|
|
throw new Error(DX.utils.stringFormat("Routing rule is not found for the \"{0}\" url", args.uri));
|
|
var uri = this.router.format(routeData);
|
|
if (args.uri !== uri && uri) {
|
|
args.cancel = true;
|
|
DX.utils.executeAsync(function() {
|
|
self.navigate(uri, args.options)
|
|
})
|
|
}
|
|
else
|
|
self._processEvent("navigating", args)
|
|
},
|
|
_onNavigated: function(args) {
|
|
var self = this,
|
|
direction = args.options.direction,
|
|
deferred = $.Deferred(),
|
|
viewInfo = self._acquireViewInfo(args.item);
|
|
if (!self._isViewReadyToShow(viewInfo))
|
|
self._setViewLoadingState(viewInfo, direction).done(function() {
|
|
DX.utils.executeAsync(function() {
|
|
self._createViewModel(viewInfo);
|
|
self._createViewCommands(viewInfo);
|
|
deferred.resolve()
|
|
})
|
|
});
|
|
else
|
|
deferred.resolve();
|
|
deferred.done(function() {
|
|
self._highlightCurrentNavigationCommand(viewInfo);
|
|
self._showView(viewInfo, direction).done(function() {
|
|
self._isNavigating = false;
|
|
var pendingArgs = self._pendingNavigationArgs;
|
|
if (pendingArgs)
|
|
DX.utils.executeAsync(function() {
|
|
self.navigate(pendingArgs.uri, pendingArgs.options)
|
|
})
|
|
})
|
|
})
|
|
},
|
|
_isViewReadyToShow: function(viewInfo) {
|
|
return !!viewInfo.model
|
|
},
|
|
_onNavigationCanceled: function(args) {
|
|
var self = this;
|
|
if (!self._pendingNavigationArgs || self._pendingNavigationArgs.uri !== args.uri) {
|
|
var currentItem = self.navigationManager.currentItem();
|
|
if (currentItem)
|
|
DX.utils.executeAsync(function() {
|
|
var viewInfo = self._acquireViewInfo(currentItem);
|
|
self._highlightCurrentNavigationCommand(viewInfo)
|
|
});
|
|
self._isNavigating = false
|
|
}
|
|
},
|
|
_onViewRemoved: function(viewInfo) {
|
|
this._viewsToDispose.push(viewInfo)
|
|
},
|
|
_disposeRemovedViews: function() {
|
|
var viewInfo;
|
|
while (viewInfo = this._viewsToDispose.shift()) {
|
|
var args = {viewInfo: viewInfo};
|
|
this._processEvent("viewDisposing", args, args.viewInfo.model);
|
|
this._disposeView(viewInfo);
|
|
this._processEvent("viewDisposed", args, args.viewInfo.model)
|
|
}
|
|
},
|
|
_onNavigationItemRemoved: function(item) {
|
|
var viewInfo = this._viewCache.removeView(item.key);
|
|
if (viewInfo)
|
|
this._onViewRemoved(viewInfo)
|
|
},
|
|
_onViewHidden: function(viewInfo) {
|
|
var args = {viewInfo: viewInfo};
|
|
this._processEvent("viewHidden", args, args.viewInfo.model)
|
|
},
|
|
_disposeView: function(viewInfo) {
|
|
if (!viewInfo.model)
|
|
return;
|
|
var commands = viewInfo.model.commands || [];
|
|
$.each(commands, function(index, command) {
|
|
command._dispose()
|
|
})
|
|
},
|
|
_acquireViewInfo: function(navigationItem) {
|
|
var viewInfo = this._viewCache.getView(navigationItem.key);
|
|
if (!viewInfo) {
|
|
viewInfo = this._createViewInfo(navigationItem);
|
|
this._viewCache.setView(navigationItem.key, viewInfo)
|
|
}
|
|
return viewInfo
|
|
},
|
|
_processEvent: function(eventName, args, model) {
|
|
this._callComponentMethod(eventName, args);
|
|
if (this[eventName] && this[eventName].fire)
|
|
this[eventName].fire(args);
|
|
var modelMethod = (model || {})[eventName];
|
|
if (modelMethod)
|
|
modelMethod.call(model, args)
|
|
},
|
|
_createViewInfo: function(navigationItem) {
|
|
var uri = navigationItem.uri,
|
|
routeData = this.router.parse(uri);
|
|
var viewInfo = {
|
|
viewName: routeData.view,
|
|
routeData: routeData,
|
|
uri: uri,
|
|
key: navigationItem.key,
|
|
canBack: this.canBack()
|
|
};
|
|
return viewInfo
|
|
},
|
|
_createViewModel: function(viewInfo) {
|
|
this._processEvent("beforeViewSetup", {viewInfo: viewInfo});
|
|
viewInfo.model = viewInfo.model || this._callViewCodeBehind(viewInfo.routeData);
|
|
this._processEvent("afterViewSetup", {viewInfo: viewInfo})
|
|
},
|
|
_createViewCommands: function(viewInfo) {
|
|
viewInfo.commands = viewInfo.model.commands || [];
|
|
if (viewInfo.canBack)
|
|
this._appendBackCommand(viewInfo)
|
|
},
|
|
_callViewCodeBehind: function(routeData) {
|
|
var setupFunc = $.noop;
|
|
if (routeData.view in this.namespace)
|
|
setupFunc = this.namespace[routeData.view];
|
|
return setupFunc.call(this.namespace, routeData) || {}
|
|
},
|
|
_appendBackCommand: function(viewInfo) {
|
|
var commands = viewInfo.commands;
|
|
var toMergeTo = [new DX.framework.dxCommand({
|
|
id: "back",
|
|
title: BACK_COMMAND_TITLE,
|
|
behavior: "back",
|
|
action: "#_back",
|
|
icon: "arrowleft",
|
|
type: "back"
|
|
})];
|
|
var result = DX.framework.utils.mergeCommands(toMergeTo, commands);
|
|
commands.length = 0;
|
|
commands.push.apply(commands, result)
|
|
},
|
|
_showView: function(viewInfo, direction) {
|
|
var self = this;
|
|
var eventArgs = {
|
|
viewInfo: viewInfo,
|
|
direction: direction
|
|
};
|
|
self._processEvent("viewShowing", eventArgs, viewInfo.model);
|
|
return self._showViewImpl(eventArgs.viewInfo, eventArgs.direction).done(function() {
|
|
self._processEvent("viewShown", eventArgs, viewInfo.model);
|
|
self._disposeRemovedViews()
|
|
})
|
|
},
|
|
_highlightCurrentNavigationCommand: function(viewInfo) {
|
|
var self = this,
|
|
selectedCommand,
|
|
currentUri = viewInfo.uri,
|
|
currentNavigationItemId = viewInfo.model && viewInfo.model.currentNavigationItemId;
|
|
if (currentNavigationItemId !== undefined)
|
|
$.each(this.navigation, function(index, command) {
|
|
if (command.option("id") === currentNavigationItemId) {
|
|
selectedCommand = command;
|
|
return false
|
|
}
|
|
});
|
|
if (!selectedCommand)
|
|
$.each(this.navigation, function(index, command) {
|
|
var commandUri = command.option("action");
|
|
if (DX.utils.isString(commandUri)) {
|
|
commandUri = commandUri.replace(/^#+/, "");
|
|
if (commandUri === self.navigationManager.rootUri()) {
|
|
selectedCommand = command;
|
|
return false
|
|
}
|
|
}
|
|
});
|
|
$.each(this.navigation, function(index, command) {
|
|
command.option("highlighted", command === selectedCommand)
|
|
})
|
|
},
|
|
_initViewLoadingState: DX.abstract,
|
|
_setCurrentViewAsyncImpl: DX.abstract,
|
|
navigate: function(uri, options) {
|
|
var self = this;
|
|
if ($.isPlainObject(uri)) {
|
|
uri = self.router.format(uri);
|
|
if (uri === false)
|
|
throw new Error("The passed object cannot be formatted into a uri string by router. An appropriate route should be registered.");
|
|
}
|
|
if (!self._initState)
|
|
self.init().done(function() {
|
|
self.restoreState();
|
|
self.navigate(uri, options)
|
|
});
|
|
else if (self._initState === INIT_COMPLETE)
|
|
self.navigationManager.navigate(uri, options);
|
|
else
|
|
throw new Error("Unable to navigate. Application is being initialized. Consider using the 'HtmlApplication.navigating' event to alter the navigation logic.");
|
|
},
|
|
canBack: function() {
|
|
return this.navigationManager.canBack()
|
|
},
|
|
back: function() {
|
|
this.navigationManager.back()
|
|
},
|
|
saveState: function() {
|
|
this.stateManager.saveState()
|
|
},
|
|
restoreState: function() {
|
|
this.stateManager.restoreState()
|
|
},
|
|
clearState: function() {
|
|
this.stateManager.clearState()
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.html.js */
|
|
(function($, DX, undefined) {
|
|
DX.framework.html = {layoutControllers: []}
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.widgetCommandAdapters.js */
|
|
(function($, DX) {
|
|
var adapters = DX.framework.html.commandToDXWidgetAdapters = {
|
|
_updateItems: [],
|
|
addCommandBase: function(widget, command, containerOptions, initialItemOptions, customizeItem) {
|
|
var itemOptions = $.extend(initialItemOptions, containerOptions, command.option());
|
|
var items = widget.option("items");
|
|
items.push(itemOptions);
|
|
var updateItem = function(name, newValue, oldValue) {
|
|
$.extend(itemOptions, command.option());
|
|
customizeItem(itemOptions, name, newValue, oldValue);
|
|
if (name !== "highlighted")
|
|
widget.option("items", items)
|
|
};
|
|
this._updateItems.push(updateItem);
|
|
updateItem();
|
|
command.optionChanged.add(updateItem);
|
|
widget.disposing.add(function() {
|
|
command.optionChanged.remove(updateItem)
|
|
})
|
|
}
|
|
};
|
|
adapters.dxToolbar = {addCommand: function($container, command, containerOptions) {
|
|
var toolbar = $container.data("dxToolbar"),
|
|
initialItemData = {command: command};
|
|
toolbar.option("itemClickAction", function(e) {
|
|
if (e.itemData.command)
|
|
e.itemData.command.execute()
|
|
});
|
|
function customizeOption(itemOptions) {
|
|
var location = resolvePropertyValue(command, containerOptions, "location");
|
|
itemOptions.location = location;
|
|
if (location === "menu")
|
|
itemOptions.text = resolveTextValue(command, containerOptions);
|
|
else {
|
|
var options = {
|
|
text: resolveTextValue(command, containerOptions),
|
|
disabled: command.option("disabled"),
|
|
icon: resolveIconValue(command, containerOptions, "icon"),
|
|
iconSrc: resolveIconValue(command, containerOptions, "iconSrc"),
|
|
type: resolveTypeValue(command, containerOptions)
|
|
};
|
|
itemOptions.options = options;
|
|
initialItemData.widget = "button"
|
|
}
|
|
}
|
|
adapters.addCommandBase(toolbar, command, containerOptions, initialItemData, customizeOption);
|
|
toolbar.option("visible", true)
|
|
}};
|
|
adapters.dxActionSheet = {addCommand: function($container, command, containerOptions) {
|
|
var actionSheet = $container.data("dxActionSheet"),
|
|
initialItemData = {command: command};
|
|
adapters.addCommandBase(actionSheet, command, containerOptions, initialItemData, function(itemOptions) {
|
|
itemOptions.text = resolveTextValue(command, containerOptions);
|
|
itemOptions.icon = resolveIconValue(command, containerOptions, "icon");
|
|
itemOptions.iconSrc = resolveIconValue(command, containerOptions, "iconSrc")
|
|
})
|
|
}};
|
|
adapters.dxList = {addCommand: function($container, command, containerOptions) {
|
|
var list = $container.data("dxList");
|
|
adapters.addCommandBase(list, command, containerOptions, {}, function(itemOptions) {
|
|
itemOptions.title = resolveTextValue(command, containerOptions);
|
|
itemOptions.clickAction = function() {
|
|
if (!itemOptions.disabled)
|
|
command.execute()
|
|
};
|
|
itemOptions.icon = resolveIconValue(command, containerOptions, "icon");
|
|
itemOptions.iconSrc = resolveIconValue(command, containerOptions, "iconSrc")
|
|
})
|
|
}};
|
|
adapters.dxNavBar = {addCommand: function($container, command, containerOptions) {
|
|
var navbar = $container.data("dxNavBar");
|
|
var initialItemData = {command: command};
|
|
navbar.option("itemClickAction", function(e) {
|
|
var items = navbar.option("items");
|
|
for (var i = items.length; --i; )
|
|
items[i].command.option("highlighted", false);
|
|
e.itemData.command.execute()
|
|
});
|
|
var updateSelectedIndex = function() {
|
|
var items = navbar.option("items");
|
|
for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
|
|
if (items[i].highlighted) {
|
|
navbar.option("selectedIndex", i);
|
|
break
|
|
}
|
|
};
|
|
adapters.addCommandBase(navbar, command, containerOptions, initialItemData, function(itemOptions, name, newValue, oldValue) {
|
|
if (name === "highlighted") {
|
|
if (newValue)
|
|
updateSelectedIndex()
|
|
}
|
|
else {
|
|
itemOptions.text = resolveTextValue(command, containerOptions);
|
|
itemOptions.icon = resolveIconValue(command, containerOptions, "icon");
|
|
itemOptions.iconSrc = resolveIconValue(command, containerOptions, "iconSrc");
|
|
updateSelectedIndex()
|
|
}
|
|
})
|
|
}};
|
|
adapters.dxPivot = {addCommand: function($container, command, containerOptions) {
|
|
var pivot = $container.data("dxPivot");
|
|
var initialItemData = {command: command};
|
|
pivot.option("itemSelectAction", function(e) {
|
|
e.itemData.command.execute()
|
|
});
|
|
var updateSelectedIndex = function() {
|
|
var items = pivot.option("items") || [];
|
|
for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
|
|
if (items[i].highlighted) {
|
|
pivot.option("selectedIndex", i);
|
|
break
|
|
}
|
|
};
|
|
adapters.addCommandBase(pivot, command, containerOptions, initialItemData, function(itemOptions, name, newValue, oldValue) {
|
|
if (name === "highlighted") {
|
|
if (newValue)
|
|
updateSelectedIndex()
|
|
}
|
|
else {
|
|
itemOptions.title = resolveTextValue(command, containerOptions);
|
|
updateSelectedIndex()
|
|
}
|
|
})
|
|
}};
|
|
adapters.dxSlideOut = {addCommand: function($container, command, containerOptions) {
|
|
var slideOut = $container.data("dxSlideOut");
|
|
var initialItemData = {command: command};
|
|
slideOut.option("itemClickAction", function(e) {
|
|
e.itemData.command.execute()
|
|
});
|
|
var updateSelectedIndex = function() {
|
|
var items = slideOut.option("items") || [];
|
|
for (var i = 0, itemsCount = items.length; i < itemsCount; i++)
|
|
if (items[i].highlighted) {
|
|
slideOut.option("selectedIndex", i);
|
|
break
|
|
}
|
|
};
|
|
adapters.addCommandBase(slideOut, command, containerOptions, initialItemData, function(itemOptions, name, newValue, oldValue) {
|
|
if (name === "highlighted") {
|
|
if (newValue)
|
|
updateSelectedIndex()
|
|
}
|
|
else {
|
|
itemOptions.title = resolveTextValue(command, containerOptions);
|
|
itemOptions.icon = resolveIconValue(command, containerOptions, "icon");
|
|
itemOptions.iconSrc = resolveIconValue(command, containerOptions, "iconSrc");
|
|
updateSelectedIndex()
|
|
}
|
|
})
|
|
}};
|
|
var resolvePropertyValue = function(command, containerOptions, propertyName) {
|
|
var defaultOption = containerOptions ? containerOptions[propertyName] : undefined;
|
|
return command.option(propertyName) || defaultOption
|
|
};
|
|
var resolveTextValue = function(command, containerOptions) {
|
|
var hasIcon = !!command.option("icon") || command.option("iconSrc"),
|
|
titleValue = resolvePropertyValue(command, containerOptions, "title");
|
|
return containerOptions.showText || !hasIcon ? titleValue : ""
|
|
};
|
|
var resolveIconValue = function(command, containerOptions, propertyName) {
|
|
var hasText = !!command.option("title"),
|
|
iconValue = resolvePropertyValue(command, containerOptions, propertyName);
|
|
return containerOptions.showIcon || !hasText ? iconValue : undefined
|
|
};
|
|
var resolveTypeValue = function(command, containerOptions) {
|
|
return resolvePropertyValue(command, containerOptions, "type")
|
|
}
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.commandManager.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
ui = DevExpress.ui;
|
|
DX.framework.dxCommandContainer = ui.Component.inherit({
|
|
ctor: function(element, options) {
|
|
if ($.isPlainObject(element)) {
|
|
options = element;
|
|
element = $("<div />")
|
|
}
|
|
this.callBase(element, options)
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-command-container")
|
|
}
|
|
});
|
|
ui.registerComponent("dxCommandContainer", DX.framework.dxCommandContainer);
|
|
DX.framework.html.CommandManager = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.globalCommands = options.globalCommands || [];
|
|
this.commandsToWidgetRegistry = [this._commandsToDXWidget];
|
|
this.commandMapping = options.commandMapping || new DX.framework.CommandMapping
|
|
},
|
|
_commandsToDXWidget: function($container, commandInfos) {
|
|
var componentNames = $container.data("dxComponents");
|
|
var adapters = DX.framework.html.commandToDXWidgetAdapters;
|
|
if (componentNames)
|
|
for (var index in componentNames) {
|
|
var widgetName = componentNames[index];
|
|
if (widgetName in adapters) {
|
|
var widget = $container.data(widgetName);
|
|
widget.beginUpdate();
|
|
$.each(commandInfos, function(index, commandInfo) {
|
|
adapters[widgetName].addCommand($container, commandInfo.command, commandInfo.options)
|
|
});
|
|
widget.endUpdate();
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
},
|
|
_findCommands: function($view) {
|
|
var result = $.map($view.addBack().find(".dx-command"), function(element) {
|
|
return $(element).dxCommand("instance")
|
|
});
|
|
return result
|
|
},
|
|
_findCommandContainers: function($markup) {
|
|
var result = $.map($markup.find(".dx-command-container"), function(element) {
|
|
return $(element).dxCommandContainer("instance")
|
|
});
|
|
return result
|
|
},
|
|
_checkCommandId: function(id, command) {
|
|
if (id === null)
|
|
throw new Error("The command's 'id' option should be specified.\r\nProcessed markup: " + command._element().get(0).outerHTML);
|
|
},
|
|
_arrangeCommandsToContainers: function(commands, containers) {
|
|
var self = this,
|
|
commandHash = {},
|
|
commandIds = [];
|
|
$.each(commands, function(i, command) {
|
|
var id = command.option("id");
|
|
self._checkCommandId(id, command);
|
|
commandIds.push(id);
|
|
commandHash[id] = command
|
|
});
|
|
self.commandMapping.checkCommandsExist(commandIds);
|
|
$.each(containers, function(k, container) {
|
|
var commandInfos = [];
|
|
$.each(commandHash, function(id, command) {
|
|
var commandId = id;
|
|
var commandOptions = self.commandMapping.getCommandMappingForContainer(commandId, container.option("id"));
|
|
if (commandOptions)
|
|
commandInfos.push({
|
|
command: command,
|
|
options: commandOptions
|
|
})
|
|
});
|
|
self._attachCommandsToContainer(container._element(), commandInfos)
|
|
})
|
|
},
|
|
_attachCommandsToContainer: function($container, commandInfos) {
|
|
var handled = false;
|
|
$.each(this.commandsToWidgetRegistry, function(index, commandsToWidget) {
|
|
handled = commandsToWidget($container, commandInfos);
|
|
return !handled
|
|
});
|
|
if (!handled)
|
|
this._defaultCommandsToContainer($container, commandInfos)
|
|
},
|
|
_defaultCommandsToContainer: function($container, commandInfos) {
|
|
$.each(commandInfos, function(index, commandInfo) {
|
|
var command = commandInfo.command,
|
|
$source = command._element();
|
|
if ($source) {
|
|
$container.append($source);
|
|
$source.on("dxclick", function() {
|
|
command.execute()
|
|
})
|
|
}
|
|
})
|
|
},
|
|
_collectCommands: function($markup, extraCommands) {
|
|
var markupCommands = this._findCommands($markup);
|
|
var viewRelatedCommands = DX.framework.utils.mergeCommands(extraCommands, markupCommands);
|
|
var allCommands = DX.framework.utils.mergeCommands(this.globalCommands, viewRelatedCommands);
|
|
return allCommands
|
|
},
|
|
layoutCommands: function($markup, extraCommands) {
|
|
extraCommands = extraCommands || [];
|
|
var allCommands = this._collectCommands($markup, extraCommands);
|
|
var commandContainers = this._findCommandContainers($markup);
|
|
this._arrangeCommandsToContainers(allCommands, commandContainers)
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.layoutController.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
var HIDDEN_BAG_ID = "__hidden-bag";
|
|
var TRANSITION_SELECTOR = ".dx-transition:not(.dx-transition .dx-transition)";
|
|
var transitionSelector = function(transitionName) {
|
|
return ".dx-transition-" + transitionName
|
|
};
|
|
DX.framework.html.DefaultLayoutController = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this._layoutTemplateName = options.layoutTemplateName || "";
|
|
this._disableViewLoadingState = options.disableViewLoadingState;
|
|
this._layoutModel = options.layoutModel || {}
|
|
},
|
|
init: function(options) {
|
|
options = options || {};
|
|
this._$viewPort = options.$viewPort || $("body");
|
|
this._$hiddenBag = options.$hiddenBag || $(document.getElementById(HIDDEN_BAG_ID)) || $("<div/>").hide().appendTo("body");
|
|
this.viewReleased = $.Callbacks();
|
|
this.viewRendered = $.Callbacks();
|
|
this._commandManager = options.commandManager || new DX.framework.html.CommandManager({commandMapping: options.commandMapping});
|
|
this._viewEngine = options.viewEngine;
|
|
this._prepareTemplates(options.navigation || [])
|
|
},
|
|
activate: function() {
|
|
this._justActivated = true;
|
|
this._visibleViews = {};
|
|
this._getRootElement().appendTo(this._$viewPort).show()
|
|
},
|
|
deactivate: function() {
|
|
var self = this;
|
|
$.each(this._visibleViews, function(index, viewInfo) {
|
|
self._hideView(viewInfo);
|
|
self._releaseView(viewInfo)
|
|
});
|
|
this._moveToHiddenBag(this._getRootElement())
|
|
},
|
|
_getPreviousViewInfo: function(viewInfo) {
|
|
return this._visibleViews[this._getTargetFrame(viewInfo)]
|
|
},
|
|
_prepareTemplates: function(navigationCommands) {
|
|
var self = this;
|
|
var $layoutTemplate = self._viewEngine.findLayoutTemplate(this._getLayoutTemplateName()).removeClass("dx-hidden");
|
|
self._$layoutTemplate = $layoutTemplate;
|
|
self._$mainLayout = self._createEmptyLayout().show();
|
|
self._createNavigation(navigationCommands);
|
|
self._blankViewInfo = self._createBlankViewInfo($layoutTemplate)
|
|
},
|
|
_createNavigation: function(navigationCommands) {
|
|
this._viewEngine._applyTemplate(this._$mainLayout, this._layoutModel);
|
|
this._renderCommands(this._$mainLayout, navigationCommands)
|
|
},
|
|
_getRootElement: function() {
|
|
return this._$mainLayout
|
|
},
|
|
_getViewFrame: function(viewInfo) {
|
|
return this._$mainLayout
|
|
},
|
|
_getLayoutTemplateName: function() {
|
|
return this._layoutTemplateName
|
|
},
|
|
_createBlankViewInfo: function($layoutTemplate) {
|
|
var self = this;
|
|
var $blankView = $layoutTemplate.clone().addClass("blank-view").appendTo(self._$hiddenBag);
|
|
self._viewEngine._createComponents($blankView);
|
|
var model = {title: ko.observable()};
|
|
this._getTransitionElements($blankView).each(function(i, item) {
|
|
self._viewEngine._applyTemplate($(item), model)
|
|
});
|
|
var result = {
|
|
model: model,
|
|
renderResult: {
|
|
$markup: $blankView,
|
|
$viewItems: $()
|
|
},
|
|
isBlankView: true
|
|
};
|
|
self._appendViewToLayout(result);
|
|
return result
|
|
},
|
|
_createViewLayoutTemplate: function() {
|
|
var self = this;
|
|
var $viewLayoutTemplate = self._$layoutTemplate.clone().appendTo(self._$hiddenBag);
|
|
self._viewEngine._createComponents($viewLayoutTemplate);
|
|
return $viewLayoutTemplate
|
|
},
|
|
_createEmptyLayout: function() {
|
|
var self = this;
|
|
var $result = self._$layoutTemplate.clone().appendTo(self._$hiddenBag);
|
|
self._viewEngine._createComponents($result);
|
|
self._removeTransitionContent($result);
|
|
return $result
|
|
},
|
|
_removeTransitionContent: function($markup) {
|
|
var $transitionElements = this._getTransitionElements($markup);
|
|
$transitionElements.children().remove()
|
|
},
|
|
_getTransitionElements: function($markup) {
|
|
return $markup.find(TRANSITION_SELECTOR).addBack(TRANSITION_SELECTOR)
|
|
},
|
|
setViewLoadingState: function(viewInfo, direction) {
|
|
var self = this;
|
|
if (self._disableViewLoadingState)
|
|
return $.Deferred().resolve().promise();
|
|
var blankViewInfo = $.extend({}, viewInfo, self._blankViewInfo);
|
|
self._blankViewInfo.model.title((viewInfo.viewTemplateInfo || {}).title || "Loading...");
|
|
return self._showViewImpl(blankViewInfo, direction)
|
|
},
|
|
showView: function(viewInfo, direction) {
|
|
var self = this;
|
|
var previousViewInfo = self._getPreviousViewInfo(viewInfo);
|
|
if (previousViewInfo && previousViewInfo.isBlankView)
|
|
direction = "none";
|
|
self._ensureViewRendered(viewInfo);
|
|
return this._showViewImpl(viewInfo, direction).done(function() {
|
|
self._onViewShown(viewInfo)
|
|
})
|
|
},
|
|
disposeView: function(viewInfo) {
|
|
if (viewInfo.renderResult) {
|
|
viewInfo.renderResult.$markup.remove();
|
|
viewInfo.renderResult.$viewItems.remove();
|
|
delete viewInfo.renderResult
|
|
}
|
|
},
|
|
_prepareViewTemplate: function($viewTemplate, viewInfo) {
|
|
this._viewEngine._createComponents($viewTemplate)
|
|
},
|
|
_renderView: function($viewTemplate, viewInfo) {
|
|
var self = this;
|
|
var $layout = this._createViewLayoutTemplate();
|
|
var $viewItems = $viewTemplate.children();
|
|
this._getTransitionElements($layout).each(function(i, item) {
|
|
self._viewEngine._applyTemplate($(item), viewInfo.model)
|
|
});
|
|
this._viewEngine._applyLayoutCore($viewTemplate, $layout);
|
|
var isSimplifiedMarkup = true,
|
|
outOfContentItems = $();
|
|
$viewItems.each(function(i, item) {
|
|
var $item = $(item);
|
|
self._viewEngine._applyTemplate($item, viewInfo.model);
|
|
if ($item.is(".dx-command,.dx-content,script"))
|
|
isSimplifiedMarkup = false;
|
|
else
|
|
outOfContentItems = outOfContentItems.add($item)
|
|
});
|
|
if (outOfContentItems.length && !isSimplifiedMarkup)
|
|
throw new Error("All the dxView element children should be either of the dxCommand or dxContent type.\r\nProcessed markup: " + outOfContentItems[0].outerHTML);
|
|
viewInfo.renderResult = {
|
|
$markup: $layout,
|
|
$viewItems: $viewItems
|
|
}
|
|
},
|
|
_renderCommands: function($markup, commands) {
|
|
var commandContainers = this._findCommandContainers($markup);
|
|
this._commandManager._arrangeCommandsToContainers(commands, commandContainers)
|
|
},
|
|
_applyViewCommands: function(viewInfo) {
|
|
var $viewItems = viewInfo.renderResult.$viewItems,
|
|
$markup = viewInfo.renderResult.$markup,
|
|
viewCommands = this._commandManager._findCommands($viewItems);
|
|
viewInfo.commands = DX.framework.utils.mergeCommands(viewInfo.commands || [], viewCommands);
|
|
this._renderCommands($markup, viewInfo.commands)
|
|
},
|
|
_findCommandContainers: function($markup) {
|
|
return this._viewEngine._createComponents($markup, ["dxCommandContainer"])
|
|
},
|
|
_ensureViewRendered: function(viewInfo) {
|
|
var self = this;
|
|
if (!viewInfo.renderResult) {
|
|
var $viewTemplate = viewInfo.$viewTemplate || this._viewEngine.findViewTemplate(viewInfo.viewName);
|
|
this._prepareViewTemplate($viewTemplate, viewInfo);
|
|
this._renderView($viewTemplate, viewInfo);
|
|
this._applyViewCommands(viewInfo);
|
|
self._appendViewToLayout(viewInfo);
|
|
self._onRenderComplete(viewInfo);
|
|
self.viewRendered.fire(viewInfo)
|
|
}
|
|
},
|
|
_appendViewToLayout: function(viewInfo) {
|
|
var self = this,
|
|
$viewFrame = self._getViewFrame(viewInfo),
|
|
$markup = viewInfo.renderResult.$markup,
|
|
$transitionContentElements = $();
|
|
$.each($markup.find(".dx-content-placeholder"), function(index, el) {
|
|
var placeholder = $(el).dxContentPlaceholder("instance");
|
|
placeholder.prepareTransition()
|
|
});
|
|
$.each(self._getTransitionElements($viewFrame), function(index, transitionElement) {
|
|
var $transition = $(transitionElement),
|
|
$viewElement = $markup.find(transitionSelector($transition.data("dx-transition-name"))).children();
|
|
self._hideViewElements($viewElement);
|
|
$transition.append($viewElement);
|
|
$transitionContentElements = $transitionContentElements.add($viewElement)
|
|
});
|
|
self._$mainLayout.append(viewInfo.renderResult.$viewItems.filter(".dx-command"));
|
|
$markup.remove();
|
|
viewInfo.renderResult.$markup = $transitionContentElements
|
|
},
|
|
_onRenderComplete: function(){},
|
|
_onViewShown: function(viewInfo) {
|
|
$(document).trigger("dx.viewchanged")
|
|
},
|
|
_doTransition: function(viewInfo, direction) {
|
|
var self = this,
|
|
deferred = $.Deferred();
|
|
var transitions = $.map(viewInfo.renderResult.$markup, function(transitionContent) {
|
|
var $transitionContent = $(transitionContent),
|
|
$transition = $transitionContent.parent(),
|
|
transitionType = self._disableTransitions ? "none" : $transition.data("dx-transition-type");
|
|
return {
|
|
destination: $transition,
|
|
source: $transitionContent,
|
|
type: transitionType || "none",
|
|
direction: direction || "none"
|
|
}
|
|
});
|
|
self._executeTransitions(transitions).done(function() {
|
|
deferred.resolve()
|
|
});
|
|
return deferred.promise()
|
|
},
|
|
_hideView: function(viewInfo) {
|
|
if (viewInfo.renderResult)
|
|
this._hideViewElements(viewInfo.renderResult.$markup)
|
|
},
|
|
_showViewImpl: function(viewInfo, direction) {
|
|
var self = this,
|
|
deferred = $.Deferred();
|
|
if (this._justActivated) {
|
|
this._justActivated = false;
|
|
direction = "none"
|
|
}
|
|
return self._doTransition(viewInfo, direction).done(function() {
|
|
self._changeView(viewInfo)
|
|
})
|
|
},
|
|
_releaseView: function(viewInfo) {
|
|
this.viewReleased.fireWith(this, [viewInfo])
|
|
},
|
|
_getViewPortElement: function() {
|
|
return this._$viewPort
|
|
},
|
|
_getHiddenBagElement: function() {
|
|
return this._$hiddenBag
|
|
},
|
|
_changeView: function(viewInfo) {
|
|
var self = this;
|
|
var previousViewInfo = self._getPreviousViewInfo(viewInfo);
|
|
if (previousViewInfo && previousViewInfo !== viewInfo) {
|
|
self._hideView(previousViewInfo);
|
|
if (!previousViewInfo.isBlankView)
|
|
this._releaseView(previousViewInfo)
|
|
}
|
|
this._visibleViews[this._getTargetFrame(viewInfo)] = viewInfo
|
|
},
|
|
_getTargetFrame: function(viewInfo) {
|
|
return "content"
|
|
},
|
|
_hideViewElements: function($elements) {
|
|
this._patchIDs($elements);
|
|
this._disableInputs($elements);
|
|
$elements.removeClass("dx-active-view").addClass("dx-inactive-view")
|
|
},
|
|
_showViewElements: function($elements) {
|
|
this._unpatchIDs($elements);
|
|
this._enableInputs($elements);
|
|
$elements.removeClass("dx-inactive-view").addClass("dx-active-view")
|
|
},
|
|
_executeTransitions: function(transitions) {
|
|
var self = this;
|
|
var animatedTransitions = $.map(transitions, function(transitionOptions) {
|
|
self._showViewElements(transitionOptions.source);
|
|
if (transitionOptions.source.children().length)
|
|
return DX.framework.html.TransitionExecutor.create(transitionOptions.destination, transitionOptions)
|
|
});
|
|
var animatedDeferreds = $.map(animatedTransitions, function(transition) {
|
|
transition.options.source.addClass("dx-transition-source");
|
|
return transition.exec()
|
|
});
|
|
var result = $.when.apply($, animatedDeferreds).done(function() {
|
|
$.each(animatedTransitions, function(index, transition) {
|
|
transition.finalize();
|
|
self._hideViewElements(transition.options.source.parent().find(".dx-active-view:not(.dx-transition-source)"));
|
|
transition.options.source.removeClass("dx-transition-source")
|
|
})
|
|
});
|
|
return result
|
|
},
|
|
_patchIDs: function($markup) {
|
|
this._processIDs($markup, function(id) {
|
|
var result = id;
|
|
if (id.indexOf(HIDDEN_BAG_ID) === -1)
|
|
result = HIDDEN_BAG_ID + "-" + id;
|
|
return result
|
|
})
|
|
},
|
|
_unpatchIDs: function($markup) {
|
|
this._processIDs($markup, function(id) {
|
|
var result = id;
|
|
if (id.indexOf(HIDDEN_BAG_ID) === 0)
|
|
result = id.substr(HIDDEN_BAG_ID.length + 1);
|
|
return result
|
|
})
|
|
},
|
|
_processIDs: function($markup, process) {
|
|
var elementsWithIds = $markup.find("[id]");
|
|
$.each(elementsWithIds, function(index, element) {
|
|
var $el = $(element),
|
|
id = $el.attr("id");
|
|
$el.attr("id", process(id))
|
|
})
|
|
},
|
|
_enableInputs: function($markup) {
|
|
var $inputs = $markup.find(":input[data-dx-disabled=true]");
|
|
$.each($inputs, function(index, input) {
|
|
$(input).removeAttr("disabled").removeAttr("data-dx-disabled")
|
|
})
|
|
},
|
|
_disableInputs: function($markup) {
|
|
var $inputs = $markup.find(":input:not([disabled], [disabled=true])");
|
|
$.each($inputs, function(index, input) {
|
|
$(input).attr({
|
|
disabled: true,
|
|
"data-dx-disabled": true
|
|
})
|
|
})
|
|
},
|
|
_moveToViewPort: function($items) {
|
|
this._unpatchIDs($items);
|
|
$items.appendTo(this._getViewPortElement())
|
|
},
|
|
_moveToHiddenBag: function($items) {
|
|
this._patchIDs($items);
|
|
$items.appendTo(this._getHiddenBagElement())
|
|
}
|
|
});
|
|
DX.framework.html.layoutControllers.push({controller: new DX.framework.html.DefaultLayoutController})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.templateEngine.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class;
|
|
DX.framework.html.KnockoutJSTemplateEngine = Class.inherit({applyTemplate: function(template, model) {
|
|
ko.applyBindings(model, $(template).get(0))
|
|
}})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.viewEngine.js */
|
|
(function($, DX, undefined) {
|
|
var Class = DX.Class,
|
|
ui = DX.ui,
|
|
_VIEW_ROLE = "dxView",
|
|
_LAYOUT_ROLE = "dxLayout";
|
|
DX.framework[_VIEW_ROLE] = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
name: null,
|
|
title: null,
|
|
layout: null
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-view")
|
|
}
|
|
});
|
|
ui.registerComponent(_VIEW_ROLE, DX.framework.dxView);
|
|
DX.framework[_LAYOUT_ROLE] = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {name: null})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-layout")
|
|
}
|
|
});
|
|
ui.registerComponent(_LAYOUT_ROLE, DX.framework.dxLayout);
|
|
DX.framework.dxViewPlaceholder = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {viewName: null})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
this._element().addClass("dx-view-placeholder")
|
|
}
|
|
});
|
|
ui.registerComponent("dxViewPlaceholder", DX.framework.dxViewPlaceholder);
|
|
var setupTransitionElement = function($element, transitionType, transitionName, contentCssPosition) {
|
|
if (contentCssPosition === "absolute")
|
|
$element.addClass("dx-transition-absolute");
|
|
else
|
|
$element.addClass("dx-transition-static");
|
|
$element.addClass("dx-transition").addClass("dx-transition-" + transitionName);
|
|
$element.data("dx-transition-type", transitionType);
|
|
$element.data("dx-transition-name", transitionName)
|
|
};
|
|
var setupTransitionInnerElement = function($element) {
|
|
$element.addClass("dx-transition-inner-wrapper")
|
|
};
|
|
DX.framework.dxTransition = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
name: null,
|
|
type: "slide"
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
var element = this._element();
|
|
setupTransitionElement(element, this.option("type"), this.option("name"), "absolute");
|
|
element.wrapInner("<div/>");
|
|
setupTransitionInnerElement(element.children())
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._element().empty()
|
|
}
|
|
});
|
|
ui.registerComponent("dxTransition", DX.framework.dxTransition);
|
|
DX.framework.dxContentPlaceholder = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {
|
|
name: null,
|
|
transition: "none",
|
|
contentCssPosition: "absolute"
|
|
})
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
var $element = this._element();
|
|
$element.addClass("dx-content-placeholder").addClass("dx-content-placeholder-" + this.option("name"));
|
|
setupTransitionElement($element, this.option("transition"), this.option("name"), this.option("contentCssPosition"))
|
|
},
|
|
prepareTransition: function() {
|
|
var $element = this._element();
|
|
if ($element.children(".dx-content").length === 0) {
|
|
$element.wrapInner("<div>");
|
|
$element.children().dxContent({targetPlaceholder: this.option("name")})
|
|
}
|
|
}
|
|
});
|
|
ui.registerComponent("dxContentPlaceholder", DX.framework.dxContentPlaceholder);
|
|
DX.framework.dxContent = ui.Component.inherit({
|
|
_defaultOptions: function() {
|
|
return $.extend(this.callBase(), {targetPlaceholder: null})
|
|
},
|
|
_optionChanged: function(name) {
|
|
this._refresh()
|
|
},
|
|
_clean: function() {
|
|
this.callBase();
|
|
this._element().removeClass(this._currentClass)
|
|
},
|
|
_render: function() {
|
|
this.callBase();
|
|
var element = this._element();
|
|
element.addClass("dx-content");
|
|
this._currentClass = "dx-content-" + this.option("targetPlaceholder");
|
|
element.addClass(this._currentClass);
|
|
setupTransitionInnerElement(element)
|
|
}
|
|
});
|
|
ui.registerComponent("dxContent", DX.framework.dxContent);
|
|
DX.framework.html.ViewEngine = Class.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.$root = options.$root;
|
|
this.device = options.device || {};
|
|
this.templateEngine = options.templateEngine;
|
|
this.dataOptionsAttributeName = options.dataOptionsAttributeName || "data-options";
|
|
this._templateMap = {};
|
|
this._pendingViewContainer = null;
|
|
this.viewSelecting = $.Callbacks();
|
|
this.modelFromViewDataExtended = $.Callbacks();
|
|
this.layoutSelecting = $.Callbacks();
|
|
this.layoutApplying = $.Callbacks();
|
|
this.layoutApplied = $.Callbacks()
|
|
},
|
|
init: function() {
|
|
var self = this;
|
|
this._initDefaultLayout();
|
|
return this._loadTemplates().done(function() {
|
|
self._enumerateTemplates(function(template) {
|
|
self._applyPartialViews(template._element())
|
|
})
|
|
})
|
|
},
|
|
_enumerateTemplates: function(processFn) {
|
|
var self = this;
|
|
$.each(self._templateMap, function(name, templatesByRoleMap) {
|
|
$.each(templatesByRoleMap, function(role, templates) {
|
|
$.each(templates, function(index, template) {
|
|
processFn(template)
|
|
})
|
|
})
|
|
})
|
|
},
|
|
_findComponent: function(name, role) {
|
|
return ((this._templateMap[name] || {})[role] || [])[0]
|
|
},
|
|
_findTemplate: function(name, role) {
|
|
var self = this,
|
|
component = self._findComponent(name, role);
|
|
if (!component)
|
|
throw new Error("Error 404: Template not found. role: " + role + ", name: " + name);
|
|
var $template = component._element(),
|
|
$result = $template.clone();
|
|
this._createComponents($result, [role]);
|
|
return $result
|
|
},
|
|
findViewTemplate: function(viewName) {
|
|
var findViewEventArgs = {viewName: viewName};
|
|
this.viewSelecting.fire(findViewEventArgs);
|
|
return findViewEventArgs.view ? $(findViewEventArgs.view) : this._findTemplate(viewName, _VIEW_ROLE, true)
|
|
},
|
|
_extendModelFromViewData: function($view, model) {
|
|
DX.utils.extendFromObject(model, $view.data(_VIEW_ROLE).option());
|
|
this.modelFromViewDataExtended.fire({
|
|
view: $view,
|
|
model: model
|
|
})
|
|
},
|
|
_createComponents: function($markup, types) {
|
|
var self = this;
|
|
var result = [];
|
|
$markup.find("*").addBack().filter("[" + self.dataOptionsAttributeName + "]").each(function(index, element) {
|
|
var $element = $(element),
|
|
optionsString = $element.attr(self.dataOptionsAttributeName),
|
|
options;
|
|
try {
|
|
options = new Function("return {" + optionsString + "}")()
|
|
}
|
|
catch(ex) {
|
|
throw new Error(DX.utils.stringFormat("Unable to parse options.\nMessage: {0};\nOptions value: {1}", ex, optionsString));
|
|
}
|
|
for (var componentName in options)
|
|
if (!types || $.inArray(componentName, types) > -1)
|
|
if ($element[componentName]) {
|
|
$element[componentName](options[componentName]);
|
|
result.push($element[componentName]("instance"))
|
|
}
|
|
});
|
|
return result
|
|
},
|
|
_loadTemplatesFromMarkup: function($markup) {
|
|
if ($markup.find("[data-dx-role]").length)
|
|
throw Error("View templates should be updated according to the 13.1 changes. Go to http://dxpr.es/15ikrJA for more details");
|
|
var self = this;
|
|
$markup.appendTo(this.$root);
|
|
DX.localization.localizeNode($markup);
|
|
var components = self._createComponents($markup, [_VIEW_ROLE, _LAYOUT_ROLE]);
|
|
$.each(components, function(index, component) {
|
|
var $element = component._element();
|
|
$element.addClass("dx-hidden");
|
|
self._registerTemplateComponent(component);
|
|
component._element().detach()
|
|
})
|
|
},
|
|
_registerTemplateComponent: function(component) {
|
|
var self = this,
|
|
$element = component._element(),
|
|
role = component.NAME,
|
|
options = component.option(),
|
|
templateName = options.name,
|
|
componentsByRoleMap = self._templateMap[templateName] || {};
|
|
componentsByRoleMap[role] = componentsByRoleMap[role] || [];
|
|
componentsByRoleMap[role].push(component);
|
|
self._templateMap[templateName] = componentsByRoleMap
|
|
},
|
|
getViewTemplateInfo: function(viewName) {
|
|
return this._templateMap[viewName][_VIEW_ROLE][0].option()
|
|
},
|
|
_applyPartialViews: function($render) {
|
|
var self = this;
|
|
this._createComponents($render, ["dxViewPlaceholder"]);
|
|
$.each($render.find(".dx-view-placeholder"), function() {
|
|
var $partialPlaceholder = $(this);
|
|
var viewName = $partialPlaceholder.data("dxViewPlaceholder").option("viewName");
|
|
var $view = self._findTemplate(viewName, _VIEW_ROLE);
|
|
self._applyPartialViews($view);
|
|
$partialPlaceholder.append($view);
|
|
$view.removeClass("dx-hidden")
|
|
})
|
|
},
|
|
_ajaxImpl: function() {
|
|
return $.ajax.apply($, arguments)
|
|
},
|
|
_loadTemplates: function() {
|
|
var self = this;
|
|
this._templateMap = {};
|
|
this._loadTemplatesFromMarkup(this.$root.children());
|
|
var tasks = [];
|
|
var winPhonePrefix;
|
|
if (location.protocol.indexOf("wmapp") >= 0)
|
|
winPhonePrefix = location.protocol + "www/";
|
|
$("head").find("link[rel='dx-template']").each(function(index, link) {
|
|
var url = $(link).attr("href");
|
|
var task = self._ajaxImpl({
|
|
url: (winPhonePrefix || "") + url,
|
|
isLocal: winPhonePrefix ? true : undefined,
|
|
success: function(data) {
|
|
self._loadTemplatesFromMarkup(DX.utils.createMarkupFromString(data))
|
|
},
|
|
dataType: "html"
|
|
});
|
|
tasks.push(task)
|
|
});
|
|
return $.when.apply($, tasks).done(function() {
|
|
$.each(self._templateMap, function(name, templatesByRoleMap) {
|
|
$.each(templatesByRoleMap, function(role, templates) {
|
|
self._filterTemplatesByDevice(templates)
|
|
})
|
|
})
|
|
})
|
|
},
|
|
_filterTemplatesByDevice: function(components) {
|
|
var bestMatches = DX.utils.findBestMatches(this.device, components, function(component) {
|
|
return component.option()
|
|
});
|
|
this._checkMatchedTemplates(bestMatches);
|
|
var match = bestMatches[0];
|
|
$.each(components, function(index, component) {
|
|
if (component != match) {
|
|
component._dispose();
|
|
component._element().remove()
|
|
}
|
|
});
|
|
components.length = 0;
|
|
if (match)
|
|
components.push(match)
|
|
},
|
|
_checkMatchedTemplates: function(bestMatches) {
|
|
if (bestMatches.length > 1) {
|
|
var message = "Concurrent templates are found:\r\n";
|
|
$.each(bestMatches, function(index, match) {
|
|
message += match._element().attr("data-options") + "\r\n"
|
|
});
|
|
message += "Target device:\r\n";
|
|
message += JSON.stringify(this.device);
|
|
throw Error(message);
|
|
}
|
|
},
|
|
_extendModelFormViewTemplate: function($viewTemplate, model) {
|
|
this._extendModelFromViewData($viewTemplate, model)
|
|
},
|
|
_ensureTemplates: function(viewInfo) {
|
|
this._ensureViewTemplate(viewInfo)
|
|
},
|
|
_ensureViewTemplate: function(viewInfo) {
|
|
viewInfo.$viewTemplate = viewInfo.$viewTemplate || this.findViewTemplate(viewInfo.viewName);
|
|
return viewInfo.$viewTemplate
|
|
},
|
|
_wrapViewDefaultContent: function($viewTemplate) {
|
|
$viewTemplate.wrapInner("<div class=\"dx-full-height\"></div>");
|
|
$viewTemplate.children().eq(0).dxContent({targetPlaceholder: 'content'})
|
|
},
|
|
_initDefaultLayout: function() {
|
|
this._$defaultLayoutTemplate = $("<div class=\"dx-full-height\" data-options=\"dxLayout : { name: 'default' } \"> \
|
|
<div class=\"dx-full-height\" data-options=\"dxContentPlaceholder : { name: 'content' } \" ></div> \
|
|
</div>")
|
|
},
|
|
_getDefaultLayoutTemplate: function() {
|
|
var $result = this._$defaultLayoutTemplate.clone();
|
|
this._createComponents($result);
|
|
return $result
|
|
},
|
|
findLayoutTemplate: function(layoutName) {
|
|
if (!layoutName)
|
|
return this._getDefaultLayoutTemplate();
|
|
var findLayoutEventArgs = {layoutName: layoutName};
|
|
this.layoutSelecting.fire(findLayoutEventArgs);
|
|
return findLayoutEventArgs.layout ? $(findLayoutEventArgs.layout) : this._findTemplate(layoutName, _LAYOUT_ROLE)
|
|
},
|
|
_applyTemplate: function($markup, model) {
|
|
var self = this;
|
|
$markup.each(function(i, element) {
|
|
self.templateEngine.applyTemplate(element, model)
|
|
})
|
|
},
|
|
_applyLayoutCore: function($view, $layout) {
|
|
if ($layout === undefined || $layout.length === 0)
|
|
$layout = this._getDefaultLayoutTemplate();
|
|
if ($view.children(".dx-content").length === 0)
|
|
this._wrapViewDefaultContent($view);
|
|
var $toMerge = $().add($layout).add($view);
|
|
var $placeholderContents = $toMerge.find(".dx-content");
|
|
$.each($placeholderContents, function() {
|
|
var $placeholderContent = $(this);
|
|
var placeholderId = $placeholderContent.data("dxContent").option("targetPlaceholder");
|
|
var $placeholder = $toMerge.find(".dx-content-placeholder-" + placeholderId);
|
|
$placeholder.empty();
|
|
$placeholder.append($placeholderContent)
|
|
});
|
|
$placeholderContents.filter(":not(.dx-content-placeholder .dx-content)").remove();
|
|
return $layout
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.htmlApplication.js */
|
|
(function($, DX, undefined) {
|
|
var frameworkNS = DX.framework,
|
|
htmlNS = frameworkNS.html;
|
|
var VIEW_PORT_CLASSNAME = "dx-viewport";
|
|
var HIDDEN_BAG_ID = "__hidden-bag";
|
|
var HIDDEN_BAG_CLASSNAME = "dx-hidden-bag";
|
|
htmlNS.HtmlApplication = frameworkNS.Application.inherit({
|
|
ctor: function(options) {
|
|
options = options || {};
|
|
this.callBase(options);
|
|
this._$root = $(options.rootNode || document.body);
|
|
this._initViewPort(options.viewPort);
|
|
this.device = options.device || DX.devices.current();
|
|
this._navigationType = options.navigationType || options.defaultLayout;
|
|
this._initHiddenBag();
|
|
this.viewEngine = options.viewEngine || new htmlNS.ViewEngine({
|
|
$root: this._$root,
|
|
device: this.device,
|
|
templateEngine: options.templateEngine || new htmlNS.KnockoutJSTemplateEngine({navigationManager: this.navigationManager})
|
|
});
|
|
this.components.push(this.viewEngine);
|
|
this.viewRendered = $.Callbacks();
|
|
this._layoutControllers = options.layoutControllers || htmlNS.layoutControllers;
|
|
this._availableLayoutControllers = [];
|
|
this.resolveLayoutController = $.Callbacks()
|
|
},
|
|
_initViewPort: function(options) {
|
|
this._$viewPort = this._getViewPort();
|
|
options = options || {};
|
|
if (DX.devices.current().platform === "desktop")
|
|
options = $.extend({disabled: true}, options);
|
|
if (!options.disabled)
|
|
DX.ui.initViewport(options);
|
|
DX.devices.attachCss(this._$viewPort);
|
|
this._$viewPort.addClass(this._getColorSchemeClass())
|
|
},
|
|
_getViewPort: function() {
|
|
var $viewPort = $("." + VIEW_PORT_CLASSNAME);
|
|
if (!$viewPort.length)
|
|
$viewPort = $("<div>").addClass(VIEW_PORT_CLASSNAME).appendTo(this._$root);
|
|
return $viewPort
|
|
},
|
|
_initHiddenBag: function() {
|
|
this._$hiddenBag = this._getHiddenBag(this._$root, this._$viewPort)
|
|
},
|
|
_getHiddenBag: function($root, $viewPort) {
|
|
var $hiddenBag = $("#" + HIDDEN_BAG_ID);
|
|
if (!$hiddenBag.length)
|
|
$hiddenBag = $("<div/>").addClass(HIDDEN_BAG_CLASSNAME).attr("id", HIDDEN_BAG_ID).appendTo($root);
|
|
$hiddenBag.addClass(($viewPort.attr("class") || "").replace(VIEW_PORT_CLASSNAME, ""));
|
|
return $hiddenBag
|
|
},
|
|
_showViewImpl: function(viewInfo, direction) {
|
|
this._activateLayoutController(viewInfo.layoutController);
|
|
return this._activeLayoutController.showView(viewInfo, direction)
|
|
},
|
|
_setViewLoadingState: function(viewInfo, direction) {
|
|
this._activateLayoutController(viewInfo.layoutController);
|
|
return this._activeLayoutController.setViewLoadingState(viewInfo, direction)
|
|
},
|
|
_resolveLayoutController: function(viewInfo) {
|
|
var args = {
|
|
viewInfo: viewInfo,
|
|
layoutController: null,
|
|
availableLayoutControllers: this._availableLayoutControllers
|
|
};
|
|
this._processEvent("resolveLayoutController", args, viewInfo.model);
|
|
return args.layoutController || this._resolveLayoutControllerImpl(viewInfo)
|
|
},
|
|
_resolveLayoutControllerImpl: function(viewInfo) {
|
|
var viewTemplateInfo = viewInfo.viewTemplateInfo || {},
|
|
target = $.extend({
|
|
root: !viewInfo.canBack,
|
|
navigationType: viewTemplateInfo.navigationType || viewTemplateInfo.layout || this._navigationType
|
|
}, DX.devices.current());
|
|
var matches = DX.utils.findBestMatches(target, this._availableLayoutControllers);
|
|
if (!matches.length)
|
|
throw Error("The layout controller cannot be resolved. There are no appropriate layout controllers for the current context. Make sure you have the corresponding *.js references in your main *.html file.");
|
|
if (matches.length > 1)
|
|
throw Error("The layout controller cannot be resolved. Two or more layout controllers suit the current context. Make the layout controllers registration more specific.");
|
|
if (matches[0].navigationType !== target.navigationType)
|
|
throw Error("The layout controller cannot be resolved. There are no appropriate layout controllers for the specified navigation type: '" + target.navigationType + "'. Make sure you have the corresponding *.js references in your main *.html file.");
|
|
return matches[0].controller
|
|
},
|
|
_activateLayoutController: function(layoutController) {
|
|
var self = this;
|
|
if (self._activeLayoutController !== layoutController) {
|
|
if (self._activeLayoutController)
|
|
self._activeLayoutController.deactivate();
|
|
layoutController.activate();
|
|
self._activeLayoutController = layoutController
|
|
}
|
|
},
|
|
init: function() {
|
|
var self = this,
|
|
result = this.callBase();
|
|
result.done(function() {
|
|
self._initLayoutControllers()
|
|
});
|
|
return result
|
|
},
|
|
_disposeView: function(viewInfo) {
|
|
if (viewInfo.layoutController.disposeView)
|
|
viewInfo.layoutController.disposeView(viewInfo);
|
|
this.callBase(viewInfo)
|
|
},
|
|
viewPort: function() {
|
|
return this._$viewPort
|
|
},
|
|
_getThemeClasses: function(device) {
|
|
var platformToThemeMap = {
|
|
ios: "dx-theme-ios dx-theme-ios-typography",
|
|
android: "dx-theme-android dx-theme-android-typography",
|
|
desktop: "dx-theme-desktop dx-theme-desktop-typography",
|
|
win8: "dx-theme-win8 dx-theme-win8-typography",
|
|
win8phone: "dx-theme-win8 dx-theme-win8-typography",
|
|
tizen: "dx-theme-tizen dx-theme-tizen-typography",
|
|
generic: "dx-theme-generic dx-theme-generic-typography"
|
|
};
|
|
return platformToThemeMap[device.platform]
|
|
},
|
|
_createViewInfo: function(navigationItem) {
|
|
var viewInfo = this.callBase(navigationItem);
|
|
viewInfo.viewTemplateInfo = this.viewEngine.getViewTemplateInfo(viewInfo.viewName) || {};
|
|
viewInfo.layoutController = this._resolveLayoutController(viewInfo);
|
|
return viewInfo
|
|
},
|
|
_createViewModel: function(viewInfo) {
|
|
this.callBase(viewInfo);
|
|
var templateInfo = viewInfo.viewTemplateInfo,
|
|
model = viewInfo.model;
|
|
for (var name in templateInfo)
|
|
if (!(name in model))
|
|
model[name] = templateInfo[name]
|
|
},
|
|
_checklayoutControllersRegistration: function(controllers) {
|
|
var result = [];
|
|
$.each(controllers, function(oldControllerName, controllerInfo) {
|
|
if (!controllerInfo.controller)
|
|
result.push(oldControllerName)
|
|
});
|
|
if (result.length !== 0)
|
|
throw new Error("A deprecated way is used for the registration of the following layout controllers: '" + result.join("' ,'") + "'.\r\nFor details, read the http://dxpr.es/1bTjfj1");
|
|
},
|
|
_initLayoutControllers: function() {
|
|
var self = this;
|
|
self._checklayoutControllersRegistration(self._layoutControllers);
|
|
$.each(self._layoutControllers, function(index, controllerInfo) {
|
|
var controller = controllerInfo.controller;
|
|
if (DX.utils.findBestMatches(DX.devices.current(), [controllerInfo]).length) {
|
|
self._availableLayoutControllers.push(controllerInfo);
|
|
if (controller.init)
|
|
controller.init({
|
|
app: self,
|
|
$viewPort: self._$viewPort,
|
|
$hiddenBag: self._$hiddenBag,
|
|
navigationManager: self.navigationManager,
|
|
commandMapping: self.commandMapping,
|
|
viewEngine: self.viewEngine,
|
|
navigation: self.navigation
|
|
});
|
|
if (controller.viewReleased)
|
|
controller.viewReleased.add(function(viewInfo) {
|
|
self._onViewReleased(viewInfo)
|
|
});
|
|
if (controller.viewRendered)
|
|
controller.viewRendered.add(function(viewInfo) {
|
|
self._processEvent("viewRendered", viewInfo, viewInfo.model)
|
|
})
|
|
}
|
|
})
|
|
},
|
|
_onViewReleased: function(viewInfo) {
|
|
this._onViewHidden(viewInfo);
|
|
if (!this._viewCache.hasView(viewInfo.key))
|
|
this._onViewRemoved(viewInfo)
|
|
},
|
|
_getColorSchemeClass: function() {
|
|
var $indicator = $("<div>").addClass("dx-color-scheme").appendTo(this._$viewPort),
|
|
markerThemeProperty = "font-family",
|
|
colorSchemeName = $indicator.css(markerThemeProperty).replace(/^['"]|['"]$/g, "");
|
|
$indicator.remove();
|
|
if (!colorSchemeName || colorSchemeName === "#") {
|
|
DX.utils.logger.info("Color scheme name is undefined");
|
|
return
|
|
}
|
|
return "dx-color-scheme-" + colorSchemeName
|
|
}
|
|
})
|
|
})(jQuery, DevExpress);
|
|
/*! Module framework, file framework.transitionExecutor.js */
|
|
(function($, DX) {
|
|
$.fn.extend({unwrapInner: function(selector) {
|
|
return this.each(function() {
|
|
var t = this,
|
|
c = $(t).children(selector);
|
|
c.each(function() {
|
|
var e = $(this);
|
|
e.contents().appendTo(t);
|
|
e.remove()
|
|
})
|
|
})
|
|
}});
|
|
var TRANSITION_DURATION = 400;
|
|
var TransitionExecutor = DX.Class.inherit({
|
|
ctor: function(container, options) {
|
|
this.container = container;
|
|
this.options = options
|
|
},
|
|
exec: function() {
|
|
var self = this,
|
|
options = self.options;
|
|
var $source = options.source,
|
|
$destination = options.destination;
|
|
var $sourceAbsoluteWrapper = $source,
|
|
$destinationRelativeWrapper = $destination,
|
|
$destinationAbsoluteWrapper = self._getTransitionInnerElement($destination);
|
|
this._finalize = function(){};
|
|
return self._animate($.extend({}, options, {
|
|
source: $sourceAbsoluteWrapper,
|
|
destination: $destinationAbsoluteWrapper
|
|
}))
|
|
},
|
|
finalize: function() {
|
|
if (!this._finalize)
|
|
throw Error("The \"exec\" method should be called before the \"finalize\" one");
|
|
this._finalize()
|
|
},
|
|
_getTransitionInnerElement: function($transitionElement) {
|
|
return $transitionElement.children(".dx-active-view:not(.dx-transition-source)")
|
|
},
|
|
_animate: function() {
|
|
return (new $.Deferred).resolve().promise()
|
|
}
|
|
});
|
|
var NoneTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
|
|
var $source = options.source,
|
|
$destination = options.destination;
|
|
var containerWidth = this.container.width();
|
|
DX.fx.animate($source, {
|
|
type: "slide",
|
|
from: {left: 0},
|
|
to: {left: 0},
|
|
duration: 0
|
|
});
|
|
DX.fx.animate($destination, {
|
|
type: "slide",
|
|
from: {left: -containerWidth},
|
|
to: {left: -containerWidth},
|
|
duration: 0
|
|
});
|
|
return $.Deferred().resolve().promise()
|
|
}});
|
|
var SlideTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
|
|
if (options.direction === "none") {
|
|
alert("none");
|
|
return $.Deferred().resolve().promise()
|
|
}
|
|
var $source = options.source,
|
|
$destination = options.destination;
|
|
var containerWidth = this.container.width(),
|
|
destinationLeft = $destination.position().left;
|
|
if (options.direction === "backward")
|
|
containerWidth = -containerWidth;
|
|
var promiseSource = DX.fx.animate($source, {
|
|
type: "slide",
|
|
from: {left: containerWidth},
|
|
to: {left: 0},
|
|
duration: TRANSITION_DURATION
|
|
});
|
|
var promiseDestination = DX.fx.animate($destination, {
|
|
type: "slide",
|
|
from: {left: 0},
|
|
to: {left: -containerWidth},
|
|
duration: TRANSITION_DURATION
|
|
});
|
|
return $.when(promiseDestination, promiseSource)
|
|
}});
|
|
var SlideIOS7TransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
|
|
if (options.direction === "none") {
|
|
alert("none");
|
|
return $.Deferred().resolve().promise()
|
|
}
|
|
var $source = options.source,
|
|
$destination = options.destination;
|
|
var containerWidth = this.container.width(),
|
|
slowTransitionWidth = containerWidth / 5,
|
|
sourceLeftFrom,
|
|
sourceLeftTo,
|
|
destinationLeftFrom,
|
|
destinationLeftTo,
|
|
destinationLeft = $destination.position().left,
|
|
sourceZIndex = $source.css("z-index"),
|
|
destinationZIndex = $destination.css("z-index");
|
|
if (options.direction === "backward") {
|
|
sourceLeftFrom = -slowTransitionWidth;
|
|
sourceLeftTo = 0;
|
|
destinationLeftFrom = 0;
|
|
destinationLeftTo = containerWidth;
|
|
$source.css("z-index", 1);
|
|
$destination.css("z-index", 2)
|
|
}
|
|
else {
|
|
sourceLeftFrom = containerWidth;
|
|
sourceLeftTo = 0;
|
|
destinationLeftFrom = 0;
|
|
destinationLeftTo = -slowTransitionWidth;
|
|
$source.css("z-index", 2);
|
|
$destination.css("z-index", 1)
|
|
}
|
|
var promiseSource = DX.fx.animate($source, {
|
|
type: "slide",
|
|
from: {left: sourceLeftFrom},
|
|
to: {left: sourceLeftTo},
|
|
duration: TRANSITION_DURATION
|
|
});
|
|
var promiseDestination = DX.fx.animate($destination, {
|
|
type: "slide",
|
|
from: {left: destinationLeftFrom},
|
|
to: {left: destinationLeftTo},
|
|
duration: TRANSITION_DURATION
|
|
});
|
|
return $.when(promiseDestination, promiseSource).done(function() {
|
|
$source.css("z-index", sourceZIndex);
|
|
$destination.css("z-index", destinationZIndex)
|
|
})
|
|
}});
|
|
var OverflowTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
|
|
var $source = options.source,
|
|
$destination = options.destination,
|
|
destinationTop = $destination.position().top,
|
|
destinationLeft = $destination.position().left,
|
|
containerWidth = this.container.width();
|
|
if (options.direction === "backward")
|
|
containerWidth = -containerWidth;
|
|
var animations = [];
|
|
if (options.direction === "forward")
|
|
animations.push(DX.fx.animate($source, {
|
|
type: "slide",
|
|
from: {
|
|
top: destinationTop,
|
|
left: containerWidth + destinationLeft,
|
|
"z-index": 1
|
|
},
|
|
to: {left: destinationLeft},
|
|
duration: TRANSITION_DURATION
|
|
}));
|
|
else {
|
|
animations.push(DX.fx.animate($source, {
|
|
type: "slide",
|
|
from: {
|
|
left: destinationLeft,
|
|
"z-index": 1
|
|
},
|
|
to: {left: destinationLeft},
|
|
duration: TRANSITION_DURATION
|
|
}));
|
|
animations.push(DX.fx.animate($destination, {
|
|
type: "slide",
|
|
from: {"z-index": 2},
|
|
to: {left: destinationLeft - containerWidth},
|
|
duration: TRANSITION_DURATION
|
|
}))
|
|
}
|
|
return $.when.apply($, animations)
|
|
}});
|
|
var FadeTransitionExecutor = TransitionExecutor.inherit({_animate: function(options) {
|
|
var $source = options.source,
|
|
$destination = options.destination,
|
|
d = new $.Deferred;
|
|
$source.css({opacity: 0});
|
|
$destination.animate({opacity: 0}, TRANSITION_DURATION);
|
|
$source.animate({opacity: 1}, TRANSITION_DURATION, function() {
|
|
d.resolve()
|
|
});
|
|
return d.promise()
|
|
}});
|
|
TransitionExecutor.create = function(container, options) {
|
|
var transitionType = options.direction === "none" ? "none" : options.type;
|
|
var device = DX.devices.current();
|
|
switch (transitionType) {
|
|
case"none":
|
|
return new NoneTransitionExecutor(container, options);
|
|
case"slide":
|
|
if (device.platform === "ios" && device.version[0] === 7)
|
|
return new SlideIOS7TransitionExecutor(container, options);
|
|
else
|
|
return new SlideTransitionExecutor(container, options);
|
|
case"fade":
|
|
return new FadeTransitionExecutor(container, options);
|
|
case"overflow":
|
|
return new OverflowTransitionExecutor(container, options);
|
|
default:
|
|
throw Error(DX.utils.formatString("Unknown transition type \"{0}\"", options.type));
|
|
}
|
|
};
|
|
DX.framework.html.TransitionExecutor = TransitionExecutor
|
|
})(jQuery, DevExpress);
|
|
DevExpress.MOD_FRAMEWORK = true
|
|
}
|