(function(kendo, $){
var ui = kendo.ui;
var Widget = ui.Widget;
var Object_keys = typeof Object.keys == "function" ? Object.keys : function(obj) {
var a = [];
for (var i in obj) if (Object.prototype.hasOwnProperty.call(obj, i)) {
a.push(i);
}
return a;
};
function map(a, fn) {
if (typeof a.map == "function")
return a.map(fn);
var ret = [];
for (var i = 0; i < a.length; ++i) {
ret[i] = fn.call(a, a[i], i);
}
return ret;
}
function filter(a, fn) {
if (typeof a.filter == "function")
return a.filter(fn);
var ret = [];
for (var i = 0; i < a.length; ++i) {
if (fn(a[i], i))
ret.push(a[i]);
}
return ret;
}
function indexOf(a, el) {
if (typeof a.indexOf == "function")
return a.indexOf(el);
for (var i = 0; i < a.length; ++i) {
if (a[i] === el)
return i;
}
return -1;
}
var template =
('
' +
'
' +
' ' +
'
' +
' ' +
' ' +
'
' +
'
' +
'
Data source
' +
' ' +
'
' +
'
' +
'
' +
' ' +
'
' +
'
Events
' +
' ' +
"
"
);
var Inspector = Widget.extend({
options: {
name : "Inspector",
showPicker : true,
showEvents : true,
docBaseUrl : null,
widget : null,
tooltips : false,
showAllOptions : false
},
init: function(element, options) {
var self = this;
Widget.fn.init.call(self, element, options);
element = self.element;
options = self.options;
element.addClass("kendo-inspector");
$(template).appendTo(element);
if (!options.showEvents) {
element.find(".kendo-inspector-section.events").remove();
}
if (!options.showPicker) {
element.find(".grab-widget").remove();
}
self._addListeners();
self.reset(options.widget);
},
reset: function(widget) {
var self = this, element = self.element;
element.find(".kendo-inspector-section .sec-content").empty();
element.find(".kendo-inspector-section.widget .sec-title").text(widget.options.name + " options");
var cont = element.find(".kendo-inspector-section.widget .sec-content");
if (self.widget) {
self._unwatchWidget();
}
self.widget = widget;
if (!widget) {
return;
}
displayJSON(safeValueForJSON(widget)).appendTo(cont);
displayJSON({ element: safeValueForJSON(widget.element) }).appendTo(cont);
if (widget.wrapper && $(widget.wrapper)[0] !== $(widget.element)[0]) {
displayJSON({ wrapper: safeValueForJSON(widget.wrapper) }).appendTo(cont);
}
var orig_options = widget.constructor.prototype.options;
function wrapOption(key, val, path) {
path = path.slice(1);
var modified = propertyChanged(orig_options, path, val);
if (self.options.docBaseUrl) {
path = filter(path, function(x){ return typeof x == "string" }).join(".");
var url = self.options.docBaseUrl + "#configuration";
if (path) {
url += "-" + path;
}
return "" + htmlescape(key) + "";
}
else {
return "" + htmlescape(key) + "";
}
}
var opts = widget.options;
if (!self.options.showAllOptions) {
opts = {};
for (var i in widget.options) if (Object.prototype.hasOwnProperty.call(widget.options, i)) {
if (propertyChanged(orig_options, [ i ], widget.options[i])) {
opts[i] = widget.options[i];
}
}
}
displayJSON({ options: safeValueForJSON(opts) }, {
filterable: true,
sort: true,
wrapProperty: wrapOption
}).appendTo(cont);
element.find(".kendo-inspector-section.datasource").removeClass("visible").css({
display: widget.dataSource ? "block" : "none"
});
if (self.options.showEvents) {
self._watchWidget();
}
},
_sectionToggled: function(sec, visible) {
var self = this, secname = sec.data("section");
switch (secname) {
case "datasource":
if (visible) {
var cont = sec.find(".sec-content").empty();
var ds = getWidgetDataSource(self.widget);
displayJSON({ options: ds.options }, {
filterable: true,
collapsed: true
}).appendTo(cont);
displayJSON({ data: ds.data }, {
filterable: true,
onEdit: function(path, val, callback){
path = path.slice(1);
try {
// if we can't parse it, it'll remain a string
val = JSON.parse(val);
} catch(ex) {};
if (setDatasourceProperty(self.widget, path, val)) {
callback(val);
}
}
}).appendTo(cont);
}
break;
}
},
_onWidgetEvent: function(eventName, ev) {
var now = new Date().getTime();
ev = safeValueForJSON(ev);
ev.__eventName = eventName;
ev.__timestamp = new Date();
var cont = this.element.find(".kendo-inspector-section.events .sec-content");
var el = displayEvent(ev).prependTo(cont);
if (this._lastEventTime && now - this._lastEventTime > 100) {
el.addClass("separator-bottom");
}
this._lastEventTime = now;
},
_watchWidget: function() {
var self = this, widget = self.widget;
self._lastEventTime = null;
function makeHandler(eventName) {
return function(ev) {
if (running) {
self._onWidgetEvent(eventName, ev);
}
};
}
if (!widget.__kendo_inspector_watcher) {
var running = true;
widget.__kendo_inspector_watcher = {
stop: function() { running = false },
resume: function() { running = true }
};
map(widget.events, function(eventName){
widget.bind(eventName, makeHandler(eventName));
});
}
widget.__kendo_inspector_watcher.resume();
},
_unwatchWidget: function() {
if (this.widget.__kendo_inspector_watcher)
this.widget.__kendo_inspector_watcher.stop();
},
_addListeners: function() {
var self = this, element = self.element;
// expand/collapse sections on clicking the title
element.on("click", ".sec-title", function(ev){
var sec = $(ev.target).closest(".kendo-inspector-section");
sec.toggleClass("visible");
self._sectionToggled(sec, sec.hasClass("visible"));
});
// expand/collapse object properties
element.on("click", ".codefold-button, .property", function(ev){
var cf = $(ev.target).closest(".expandable");
cf.toggleClass("collapsed");
if (!cf.hasClass("collapsed")) {
cf.find(".hidden").removeClass("hidden");
if (cf.data("lazy-id")) {
var data = getCachedObject(cf.data("lazy-id"));
var html = displayJSON(safeValueForJSON(data), { innerObject: true });
cf.find(".codefold-body").html(html);
cf.removeAttr("data-lazy-id");
cf.removeData("lazy-id");
}
}
});
// right-clicking an expander deep-expands/collapses subproperties
element.on("contextmenu", ".codefold-button", function(ev){
ev.preventDefault();
ev.stopPropagation();
var cf = $(ev.target).closest(".expandable");
if (cf.data("lazy-id")) {
var data = getCachedObject(cf.data("lazy-id"));
var html = displayJSON(safeValueForJSON(data), { innerObject: true });
cf.find(".codefold-body").html(html);
cf.removeAttr("data-lazy-id");
cf.removeData("lazy-id");
cf.removeClass("collapsed");
} else {
cont();
}
function cont() {
var sub = cf.find(".expandable").not("[data-lazy-id]");
if (sub.length > 0) {
cf.removeClass("collapsed");
if ($(sub[0]).hasClass("collapsed")) {
sub.removeClass("collapsed");
} else {
sub.addClass("collapsed");
}
} else {
cf.toggleClass("collapsed");
}
}
});
// support editable fields
element.on("click", ".editable-object .editable", function(ev){
var span = $(ev.target).hide();
var orig = span.attr("data-value");
var input = $("")
.val(orig)
.on("keydown", function(ev){
if (ev.keyCode == 27) {
ev.preventDefault();
cancel();
return false;
}
else if (ev.keyCode == 13) {
input.off("blur");
ev.preventDefault();
save();
return false;
}
else setTimeout(resize, 5);
})
.on("blur", function(ev){
// seems more intuitive to save than cancel on blur
input.off("blur");
ev.preventDefault();
save();
})
.insertBefore(span)
.focus();
input[0].select();
resize();
var done = false;
function resize() {
if (done) return;
span.text(input.val());
span.show();
var width = span.width();
span.hide();
if (width > 0) {
input.width(width + 20);
}
}
function cancel() {
input.remove();
span.show();
span.text(orig);
}
function save() {
span.trigger("editable:save", [ input.val(), function(val){
if (arguments.length == 0) {
cancel();
} else {
val = JSON.stringify(val);
span.text(val);
span.attr("data-value", val);
input.remove();
span.show();
done = true;
}
} ]);
}
});
// highlight widget on hover
element.on("mouseenter", "[data-widget-id]", function(ev){
var id = $(ev.target).attr("data-widget-id");
highlightWidget(id);
});
// highlight element on hover
element.on("mouseenter", "[data-element-id]", function(ev){
var id = $(ev.target).attr("data-element-id");
highlightElement(id);
});
element.on("mouseleave", "[data-widget-id], [data-element-id]", function(ev){
removeHighlight();
});
element.on("mouseenter", ".codefold-button", function(ev){
$(ev.target).closest(".codefold").addClass("highlight");
});
element.on("mouseleave", ".codefold-button", function(ev){
$(ev.target).closest(".codefold").removeClass("highlight");
});
// grab widget
element.on("click", ".grab-widget", function(ev){
self.grabWidget();
});
element.on("click", ".clear-section", function(ev){
var cont = $(ev.currentTarget).closest(".kendo-inspector-section").find(".sec-content");
cont.empty();
self._lastEventTime = null;
});
element.on("click", "[data-object-id]", function(ev){
var el = $(ev.currentTarget);
if (el.is("[data-element-id]")) {
console.log(getCachedObject(el.data("element-id")));
} else {
window.$K = getCachedObject(el.data("object-id"));
console.log(window.$K);
}
});
if (self.options.tooltips) {
element.kendoTooltip({
filter: "[data-object-id]",
content : function(data) {
if (data.target.is("[data-element-id]")) {
return "
Click to dump with console.log
";
} else {
return "
Click to dump with console.log. Places reference in global $K variable.
";
}
}
});
}
},
grabWidget: function(callback) {
var self = this, grabbed = null;
$(document.body)
.addClass("kendo-inspector-grabbing")
.on("mouseenter.kendoInspector", "[data-role]", function(ev){
var el = $(ev.currentTarget);
if (el.data("role") == "draggable") {
return;
}
grabbed = kendoWidgetInstance(el);
if (grabbed) {
highlightWidget(grabbed);
}
})
.on("mouseleave.kendoInspector", ".kendo-inspector-highlight", function(ev){
removeHighlight();
grabbed = null;
})
.on("mousedown.kendoInspector", function(ev){
$(document.body).off(".kendoInspector");
$(document.body).removeClass("kendo-inspector-grabbing");
removeHighlight();
ev.preventDefault();
ev.stopPropagation();
if (grabbed) {
self.reset(grabbed);
}
if (callback) {
callback(grabbed);
}
});
}
});
ui.plugin(Inspector);
function kendoWidgetInstance(el) {
el = $(el);
return kendo.widgetInstance(el, kendo.ui) ||
kendo.widgetInstance(el, kendo.mobile.ui) ||
kendo.widgetInstance(el, kendo.dataviz.ui);
}
var OBJECT_ID = 0;
var CACHE = {};
function cacheObject(w) {
if (w.__kendo_inspector_id) {
return w.__kendo_inspector_id;
}
var id = w.__kendo_inspector_id = ++OBJECT_ID;
CACHE[id] = w;
return id;
}
function setDatasourceProperty(wid, path, val) {
var w = getCachedObject(wid);
var ds = w.dataSource;
var data = ds.data();
var i = 0;
while (i < path.length) {
var prop = path[i++];
if (data instanceof kendo.data.ObservableObject) {
if (i < path.length) {
data = data.get(prop);
} else {
data.set(prop, val);
return true;
}
}
else if (data instanceof kendo.data.ObservableArray || $.isArray(data)) {
if (i < path.length) {
data = data[prop];
} else {
data.splice(prop, 1, val);
return true;
}
}
else if (data instanceof Date) {
var new_data = new Date(data);
val = parseInt(val, 10);
if (isNaN(val)) return false;
switch (prop) {
case "year" : new_data.setFullYear(val) ; break;
case "month" : new_data.setMonth(val) ; break;
case "date" : new_data.setDate(val) ; break;
case "hours" : new_data.setHours(val) ; break;
case "minutes" : new_data.setMinutes(val) ; break;
case "seconds" : new_data.setSeconds(val) ; break;
case "milliseconds" : new_data.setMilliseconds(val) ; break;
default:
return false;
}
setDatasourceProperty(w, path.slice(0, -1), new_data);
return new_data;
}
else if (typeof data == "object") {
if (i < path.length) {
data = data[prop];
} else {
data[prop] = val;
return true;
}
}
else {
console.error("Can't setDatasourceProperty on", data);
return false;
}
}
return false;
}
function removeFromCache(w) {
var id = w.__kendo_inspector_id;
if (id) {
delete CACHE[id];
delete w.__kendo_inspector_id;
return id;
}
}
function getCachedObject(obj) {
if (typeof obj == "object") return obj;
return CACHE[obj];
}
function elementInView(el) {
var pos = $(el).offset().top;
var top = $(window).scrollTop();
var bot = top + $(window).height();
return pos > top + 10 && pos < bot - 10;
}
function _highlightElement(el, text) {
removeHighlight();
el = $(el);
if (el.is(":visible")) {
var hl = "
";
if (text) hl += htmlescape(text);
hl += "
";
hl = $(hl);
var pos = el.offset();
hl.css({
"border-left-width" : el.css("padding-left"),
"border-top-width" : el.css("padding-top"),
"border-right-width" : el.css("padding-right"),
"border-bottom-width" : el.css("padding-bottom"),
"left" : pos.left,
"top" : pos.top,
"width" : el.outerWidth(),
"height" : el.outerHeight(),
"line-height" : el.outerHeight() + "px"
});
hl.appendTo(el[0].ownerDocument.body);
// that's not good for the demo pages
// if (!elementInView(el))
// el.get(0).scrollIntoView();
}
}
function highlightElement(id) {
var el = getCachedObject(id);
_highlightElement(el, "<" + $(el)[0].tagName.toLowerCase() + ">");
}
function highlightWidget(id) {
var w = getCachedObject(id);
var el = w.wrapper || w.element;
_highlightElement(el, w.options.name);
}
function removeHighlight() {
$(".kendo-inspector-highlight").remove();
}
function makeSpecial(type, props) {
props.__kendo_inspector_type = type;
return props;
}
function makeWidgetInfo(w, extended) {
var el = w.wrapper || w.element;
var ret = {
id : cacheObject(w),
type : w.options.name,
prefix : w.options.prefix,
element_tag : w.element.get(0).tagName,
element_id : w.element.attr("id"),
element_class : w.element.attr("class"),
visible : el.is(":visible"),
hasModel : !!w.dataSource,
wasInspected : w === window.$K
};
if (typeof w.value == "function") {
ret.value = safeValueForJSON(w.value());
}
if (extended) {
ret.widget = safeValueForJSON(w);
ret.element = safeValueForJSON(w.element.get(0));
if (w.wrapper) {
ret.wrapper = safeValueForJSON(w.wrapper.get(0));
}
}
return ret;
}
function getWidgetDataSource(id) {
var w = getCachedObject(id);
var ds = w.dataSource;
var data = ds.data();
return {
data : safeValueForJSON(data.toJSON()),
options : safeValueForJSON(ds.options)
};
}
// reliability isn't on the list of JavaScript's main features.
function isObject(x, type) {
if ($.isArray(x)) return false;
var rx = new RegExp("^\\[object " + type);
return typeof x == "object" && rx.test(x.toString());
// try {
// return typeof x == "object" && rx.test(Object.prototype.toString.call(x));
// } catch(ex) {
// return false;
// }
}
function isDomNode(x) {
return ((typeof Node != "undefined" && x instanceof Node)
|| (typeof x == "object" &&
/function|object/.test(typeof x.insertBefore) &&
/function|object/.test(typeof x.cloneNode)));
}
function isDomElement(x) {
return isObject(x, "HTML") ||
(typeof x == "object" &&
/function|object/.test(typeof x.insertBefore) &&
/function|object/.test(typeof x.cloneNode) &&
/object/.test(typeof x.children));
}
//
function safeValueForJSON(x, options) {
if (!options) options = {};
function shouldSendLazy(obj) {
if (obj === x) return false;
var len = $.isArray(obj) ? obj.length : Object_keys(obj).length;
if (len == 0) return false;
if (options.lazy) return true;
return len > 20;
}
var seen = [];
var count = 0;
var TOO_BIG = {};
try {
return saferize(x);
} catch(ex) {
if (ex === TOO_BIG) {
return makeSpecial("too-big", {
id: cacheObject(x)
});
}
throw ex;
}
function saferize(x) {
++count;
//if (count > 3000) throw TOO_BIG;
if (count > 50) options.lazy = true;
try {
if (x === null) {
return x;
}
if (x instanceof Date) {
return makeSpecial("Date", {
year : x.getFullYear(),
month : x.getMonth(),
date : x.getDate(),
hours : x.getHours(),
minutes : x.getMinutes(),
seconds : x.getSeconds(),
milliseconds : x.getMilliseconds()
});
}
if (x instanceof $) {
return makeSpecial("jQuery", {
selector : x.selector,
elements : map(x.get(), saferize)
});
}
if (isDomElement(x)) {
return makeSpecial("Element", {
id : cacheObject(x),
tag : x.tagName,
element_id : x.id,
element_class : x.className
});
}
if (isDomNode(x)) {
return "### DOM NODE ###";
}
if (isObject(x, "Window")) {
return "### Window ###";
}
if (x instanceof kendo.ui.Widget) {
return makeSpecial("kendo.ui.Widget", {
id : cacheObject(x),
type : x.options.name
});
}
if (typeof x == "function") {
return "### FUNCTION ###";
}
if (typeof x == "object") {
if (indexOf(seen, x) >= 0) {
return "### CIRCULAR ###";
}
seen.push(x);
if (typeof x.toJSON == "function") {
return saferize(x.toJSON());
}
if ($.isArray(x)) {
// var n = x.length;
// if (n > 102) {
// x = x.slice(0, 100);
// x.push("### Array too big (" + (n - 100) + " elements not displayed) ###");
// }
if (shouldSendLazy(x)) {
return {
__kendo_inspector_type: "Array",
id: cacheObject(x),
length: x.length
};
}
return map(x, saferize);
}
if (shouldSendLazy(x)) {
return {
__kendo_inspector_type: "Object",
id: cacheObject(x),
length: Object_keys(x).length - 1
};
}
var tmp = {};
for (var i in x) if (i != "dataSource" && x.hasOwnProperty(i)) {
if (x[i] === window[i]) {
// dumping global objects is a bad idea.
continue;
}
else if (/undefined|function/.test(typeof x[i])) {
continue;
}
else {
tmp[i] = saferize(x[i]);
}
}
return tmp;
}
return x;
} catch(ex) {
if (ex === TOO_BIG) throw ex;
// console.error(ex);
// console.error("saferize failed: ");
// console.error(x);
// throw ex;
return "### ERROR ###";
}
}
}
function displayEvent(ev, includeWidget) {
var type = ev.__eventName;
var ts = ev.__timestamp;
var time = kendo.format("{0:HH:mm:ss}", ts) + "." + ts.getMilliseconds();
var name = "[" + time + "] " + type;
if (includeWidget && ev.sender) {
name += " in " + wrapWidget(ev.sender);
}
var obj = {};
delete ev.__eventName;
delete ev.__timestamp;
obj[name] = ev;
return displayJSON(obj, {
collapsed: true,
wrapProperty: function(key, val, currentPath) {
if (key === name) {
return "" + key + "";
}
}
});
function wrapWidget(obj) {
return "" + obj.type + "";
}
}
function displayJSON(orig_obj, options) {
if (!options) options = {};
var currentPath = [];
var onEdit = options.onEdit;
function currentPathAttr() {
return currentPath.length > 0 ? htmlescape(JSON.stringify(currentPath)) : "";
}
function wrapEditable(thing) {
var val = htmlescape(thing);
if (onEdit) {
return "" + val + "";
}
return "" + val + "";
}
function wrapProperty(key, val) {
if (options.wrapProperty) {
var ret = options.wrapProperty(key, val, currentPath);
if (ret) return ret;
}
return "" + htmlescape(key) + "";
}
function wrapWidget(obj) {
return "### Kendo Widget (" + obj.type + ") ###";
}
function wrapElement(obj) {
return "### DOM element (" + obj.tag + ") ###";
}
function wrapLink(link) {
return "" + link.text + "";
}
function wrapTooBig(obj) {
return "### OBJECT TOO BIG ###";
}
var html = function rec(obj) {
function displayProp(name, value) {
var x = inspectValue(value);
if (x.expandable && x.objectId)
return displayLazyProp(name, value, x);
var html = "
"
+ "";
} else {
html += "'>";
}
html += wrapProperty(name, value) + ": ";
value = rec(value);
if (x.title) {
html += json_heading(x.title);
}
if (x.expandable) {
html += "
" + value + "
";
} else {
html += value;
}
html += "
";
return html;
}
function displayLazyProp(name, value, x) {
var html = "
";
html += wrapProperty(name, value) + ": ";
html += json_heading(x.title);
html += "
…
";
return html;
}
if (obj == null) {
return wrapEditable("null");
}
else if ($.isArray(obj)) {
return map(obj, function(el, i){
currentPath.push(i);
var html = displayProp(i+"", el);
currentPath.pop();
return html;
}).join("");
}
else if (obj instanceof Date) {
return wrapEditable(rec(obj.toUTCString()));
}
else if (typeof obj == "object") {
delete obj.__kendo_inspector_id;
switch (obj.__kendo_inspector_type) {
case "kendo.ui.Widget":
return wrapWidget(obj);
case "Element":
return wrapElement(obj);
case "jQuery":
delete obj.__kendo_inspector_type;
break;
case "Date":
delete obj.__kendo_inspector_type;
break;
case "link":
return wrapLink(obj);
case "too-big":
return wrapTooBig(obj);
}
var a = Object_keys(obj);
if (options.sort) {
if (options.sort instanceof Function) {
a = a.sort(function(a, b){
return options.sort(a, b, obj);
});
} else {
a = a.sort(function(a, b){
a = a.toLowerCase();
b = b.toLowerCase();
return a < b ? -1 : a > b ? 1 : 0;
});
}
}
return map(a, function(key){
currentPath.push(key);
var html = displayProp(key, obj[key]);
currentPath.pop();
return html;
}).join("");
}
else {
return wrapEditable(JSON.stringify(obj));
}
}(orig_obj);
function inspectValue(thing) {
if ($.isArray(thing)) return {
expandable : thing.length > 0,
title : "Array[" + thing.length + "]"
};
if (thing == null) return { expandable: false };
if (typeof thing == "object") {
switch (thing.__kendo_inspector_type) {
case "Array":
return {
expandable : thing.length > 0,
objectId : thing.id,
title : "Array[" + thing.length + "]"
};
case "Object":
return {
expandable : thing.length > 0,
objectId : thing.id,
title : "Object{" + thing.length + "}"
};
case "kendo.ui.Widget":
case "Element":
case "link":
case "too-big":
return { expandable: false };
case "jQuery":
case "Date":
return {
expandable : true,
title : thing.__kendo_inspector_type
};
}
var keys = Object_keys(thing);
return {
expandable : keys.length > 0,
title : "Object{" + keys.length + "}"
};
}
return false;
}
if (options.innerObject) return html;
var has_expandable_props = (function(){
var props = Object_keys(orig_obj);
for (var i = props.length; --i >= 0;) {
if (inspectValue(orig_obj[props[i]]).expandable)
return true;
}
return false;
})();
if (has_expandable_props) {
html += "
";
if (options.filterable) {
html += "";
}
// html += "";
// html += "";
html += "
";
}
var pre = $("")
.html(html)
.on("editable:save", ".editable", function(ev, val, callback){
var path = JSON.parse($(ev.target).attr("data-path"));
onEdit(path, val, callback);
});
if (options.filterable) (function(){
var filter = $(".filter", pre);
var input = $("input", filter);
function apply(orig) {
var val = input.val().toLowerCase();
if (val != "") {
filter.addClass("has-query");
filter.closest(".codefold-operations").addClass("has-query");
} else {
filter.removeClass("has-query");
filter.closest(".codefold-operations").removeClass("has-query");
}
if (orig == null || val != orig) {
pre.find(".filterable").each(function(){
var el = $(this);
var txt = el.text();
if (txt.toLowerCase().indexOf(val) >= 0) {
el.removeClass("hidden");
} else {
el.addClass("hidden");
}
});
}
}
input.on("keydown", function(ev){
if (ev.keyCode == 27) {
input.val("");
apply(null);
ev.preventDefault();
return false;
}
var orig = input.val();
setTimeout(function(){
apply(orig);
}, 10);
});
filter.on("mousedown", function(ev){
if (ev.target === this && $(this).hasClass("has-query")) {
input.val("");
apply(null);
input.blur();
ev.preventDefault();
ev.stopPropagation();
}
});
}());
return pre;
}
function propertyChanged(object, path, value) {
path = path.slice();
var x = object;
while (x != null && path.length > 0)
x = x[path.shift()];
if (path.length > 0)
return true;
return !equals(x, value);
}
function equals(a, b) {
if (a == null) return b == null;
if (b == null) return a == null;
if ($.isArray(a) && $.isArray(b)) {
if (a.length != b.length) return false;
for (var i = a.length; --i >= 0;) {
if (!equals(a[i], b[i])) return false;
}
return true;
}
if (typeof a != typeof b) return false;
if (typeof a == "object") {
var keys = Object_keys(a);
for (var i = keys.length; --i >= 0;) {
if (!equals(a[i], b[i])) return false;
}
return true;
}
return a == b;
}
function htmlescape(txt) {
if (txt == undefined) return "null";
return txt.replace(/&/g, "&")
.replace(/\x22/g, """)
.replace(/\x27/g, "'")
.replace(//g, ">")
.replace(/\u00A0/g, " ");
}
function json_heading(title) {
return "" + title + " ";
}
})(kendo, jQuery);