').append(that.ul).on('mousedown' + ns, proxy(that._listMousedown, that));
id = element.attr(ID);
if (id) {
that.list.attr(ID, id + '-list');
that.ul.attr(ID, id + '_listbox');
}
that._header();
that._accessors();
that._initValue();
},
options: {
valuePrimitive: false,
headerTemplate: ''
},
setOptions: function (options) {
Widget.fn.setOptions.call(this, options);
if (options && options.enable !== undefined) {
options.enabled = options.enable;
}
},
focus: function () {
this._focused.focus();
},
readonly: function (readonly) {
this._editable({
readonly: readonly === undefined ? true : readonly,
disable: false
});
},
enable: function (enable) {
this._editable({
readonly: false,
disable: !(enable = enable === undefined ? true : enable)
});
},
_listOptions: function (options) {
var that = this;
var currentOptions = that.options;
var virtual = currentOptions.virtual;
var listBoundHandler = proxy(that._listBound, that);
virtual = typeof virtual === 'object' ? virtual : {};
options = $.extend({
autoBind: false,
selectable: true,
dataSource: that.dataSource,
click: proxy(that._click, that),
change: proxy(that._listChange, that),
activate: proxy(that._activateItem, that),
deactivate: proxy(that._deactivateItem, that),
dataBinding: function () {
that.trigger('dataBinding');
that._angularItems('cleanup');
},
dataBound: listBoundHandler,
listBound: listBoundHandler,
height: currentOptions.height,
dataValueField: currentOptions.dataValueField,
dataTextField: currentOptions.dataTextField,
groupTemplate: currentOptions.groupTemplate,
fixedGroupTemplate: currentOptions.fixedGroupTemplate,
template: currentOptions.template
}, options, virtual);
if (!options.template) {
options.template = '#:' + kendo.expr(options.dataTextField, 'data') + '#';
}
return options;
},
_initList: function () {
var that = this;
var listOptions = that._listOptions({ selectedItemChange: proxy(that._listChange, that) });
if (!that.options.virtual) {
that.listView = new kendo.ui.StaticList(that.ul, listOptions);
} else {
that.listView = new kendo.ui.VirtualList(that.ul, listOptions);
}
that._setListValue();
},
_setListValue: function (value) {
value = value || this.options.value;
if (value !== undefined) {
this.listView.value(value).done(proxy(this._updateSelectionState, this));
}
},
_updateSelectionState: $.noop,
_listMousedown: function (e) {
if (!this.filterInput || this.filterInput[0] !== e.target) {
e.preventDefault();
}
},
_isFilterEnabled: function () {
var filter = this.options.filter;
return filter && filter !== 'none';
},
_filterSource: function (filter, force) {
var that = this;
var options = that.options;
var dataSource = that.dataSource;
var expression = extend({}, dataSource.filter() || {});
var removed = removeFiltersForField(expression, options.dataTextField);
if ((filter || removed) && that.trigger('filtering', { filter: filter })) {
return;
}
expression = {
filters: expression.filters || [],
logic: 'and'
};
if (filter) {
expression.filters.push(filter);
}
if (that._cascading) {
this.listView.setDSFilter(expression);
}
if (!force) {
dataSource.filter(expression);
} else {
dataSource.read({ filter: expression });
}
},
_header: function () {
var that = this;
var template = that.options.headerTemplate;
var header;
if ($.isFunction(template)) {
template = template({});
}
if (template) {
that.list.prepend(template);
header = that.ul.prev();
that.header = header[0] ? header : null;
if (that.header) {
that.angular('compile', function () {
return { elements: that.header };
});
}
}
},
_initValue: function () {
var that = this, value = that.options.value;
if (value !== null) {
that.element.val(value);
} else {
value = that._accessor();
that.options.value = value;
}
that._old = value;
},
_ignoreCase: function () {
var that = this, model = that.dataSource.reader.model, field;
if (model && model.fields) {
field = model.fields[that.options.dataTextField];
if (field && field.type && field.type !== 'string') {
that.options.ignoreCase = false;
}
}
},
_focus: function (candidate) {
return this.listView.focus(candidate);
},
current: function (candidate) {
return this._focus(candidate);
},
items: function () {
return this.ul[0].children;
},
destroy: function () {
var that = this;
var ns = that.ns;
Widget.fn.destroy.call(that);
that._unbindDataSource();
that.listView.destroy();
that.list.off(ns);
that.popup.destroy();
if (that._form) {
that._form.off('reset', that._resetHandler);
}
},
dataItem: function (index) {
var that = this;
if (index === undefined) {
return that.listView.selectedDataItems()[0];
}
if (typeof index !== 'number') {
if (that.options.virtual) {
return that.dataSource.getByUid($(index).data('uid'));
}
index = $(that.items()).index(index);
}
return that.dataSource.flatView()[index];
},
_activateItem: function () {
var current = this.listView.focus();
if (current) {
this._focused.add(this.filterInput).attr('aria-activedescendant', current.attr('id'));
}
},
_deactivateItem: function () {
this._focused.add(this.filterInput).removeAttr('aria-activedescendant');
},
_accessors: function () {
var that = this;
var element = that.element;
var options = that.options;
var getter = kendo.getter;
var textField = element.attr(kendo.attr('text-field'));
var valueField = element.attr(kendo.attr('value-field'));
if (!options.dataTextField && textField) {
options.dataTextField = textField;
}
if (!options.dataValueField && valueField) {
options.dataValueField = valueField;
}
that._text = getter(options.dataTextField);
that._value = getter(options.dataValueField);
},
_aria: function (id) {
var that = this, options = that.options, element = that._focused.add(that.filterInput);
if (options.suggest !== undefined) {
element.attr('aria-autocomplete', options.suggest ? 'both' : 'list');
}
id = id ? id + ' ' + that.ul[0].id : that.ul[0].id;
element.attr('aria-owns', id);
that.ul.attr('aria-live', !that._isFilterEnabled() ? 'off' : 'polite');
},
_blur: function () {
var that = this;
that._change();
that.close();
},
_change: function () {
var that = this;
var index = that.selectedIndex;
var optionValue = that.options.value;
var value = that.value();
var trigger;
if (that._isSelect && !that.listView.bound() && optionValue) {
value = optionValue;
}
if (value !== unifyType(that._old, typeof value)) {
trigger = true;
} else if (index !== undefined && index !== that._oldIndex) {
trigger = true;
}
if (trigger) {
that._old = value;
that._oldIndex = index;
if (!that._typing) {
that.element.trigger(CHANGE);
}
that.trigger(CHANGE);
}
that.typing = false;
},
_data: function () {
return this.dataSource.view();
},
_enable: function () {
var that = this, options = that.options, disabled = that.element.is('[disabled]');
if (options.enable !== undefined) {
options.enabled = options.enable;
}
if (!options.enabled || disabled) {
that.enable(false);
} else {
that.readonly(that.element.is('[readonly]'));
}
},
_dataValue: function (dataItem) {
var value = this._value(dataItem);
if (value === undefined) {
value = this._text(dataItem);
}
return value;
},
_offsetHeight: function () {
var offsetHeight = 0;
var siblings = this.listView.content.prevAll(':visible');
siblings.each(function () {
var element = $(this);
if (element.hasClass('k-list-filter')) {
offsetHeight += element.children().outerHeight();
} else {
offsetHeight += element.outerHeight();
}
});
return offsetHeight;
},
_height: function (length) {
var that = this;
var list = that.list;
var height = that.options.height;
var visible = that.popup.visible();
var offsetTop;
var popups;
if (length) {
popups = list.add(list.parent('.k-animation-container')).show();
if (!list.is(':visible')) {
popups.hide();
return;
}
height = that.listView.content[0].scrollHeight > height ? height : 'auto';
popups.height(height);
if (height !== 'auto') {
offsetTop = that._offsetHeight();
if (offsetTop) {
height -= offsetTop;
}
}
that.listView.content.height(height);
if (!visible) {
popups.hide();
}
}
return height;
},
_adjustListWidth: function () {
var list = this.list, width = list[0].style.width, wrapper = this.wrapper, computedStyle, computedWidth;
if (!list.data(WIDTH) && width) {
return;
}
computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
computedWidth = parseFloat(computedStyle && computedStyle.width) || wrapper.outerWidth();
if (computedStyle && browser.msie) {
computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
}
if (list.css('box-sizing') !== 'border-box') {
width = computedWidth - (list.outerWidth() - list.width());
} else {
width = computedWidth;
}
list.css({
fontFamily: wrapper.css('font-family'),
width: width
}).data(WIDTH, width);
return true;
},
_openHandler: function (e) {
this._adjustListWidth();
if (this.trigger(OPEN)) {
e.preventDefault();
} else {
this._focused.attr('aria-expanded', true);
this.ul.attr('aria-hidden', false);
}
},
_closeHandler: function (e) {
if (this.trigger(CLOSE)) {
e.preventDefault();
} else {
this._focused.attr('aria-expanded', false);
this.ul.attr('aria-hidden', true);
}
},
_focusItem: function () {
var listView = this.listView;
var focusedItem = listView.focus();
var index = listView.select();
index = index[index.length - 1];
if (index === undefined && this.options.highlightFirst && !focusedItem) {
index = 0;
}
if (index !== undefined) {
listView.focus(index);
} else {
listView.scrollToIndex(0);
}
},
_calculateGroupPadding: function (height) {
var li = this.ul.children('.k-first:first');
var groupHeader = this.listView.content.prev('.k-group-header');
var padding = 0;
if (groupHeader[0] && groupHeader[0].style.display !== 'none') {
if (height !== 'auto') {
padding = kendo.support.scrollbar();
}
padding += parseFloat(li.css('border-right-width'), 10) + parseFloat(li.children('.k-group').css('padding-right'), 10);
groupHeader.css('padding-right', padding);
}
},
_calculatePopupHeight: function (force) {
var height = this._height(this.dataSource.flatView().length || force);
this._calculateGroupPadding(height);
},
_resizePopup: function (force) {
if (this.options.virtual) {
return;
}
if (!this.popup.element.is(':visible')) {
this.popup.one('open', function (force) {
return proxy(function () {
this._calculatePopupHeight(force);
}, this);
}.call(this, force));
} else {
this._calculatePopupHeight(force);
}
},
_popup: function () {
var that = this;
that.popup = new ui.Popup(that.list, extend({}, that.options.popup, {
anchor: that.wrapper,
open: proxy(that._openHandler, that),
close: proxy(that._closeHandler, that),
animation: that.options.animation,
isRtl: support.isRtl(that.wrapper)
}));
},
_makeUnselectable: function () {
if (isIE8) {
this.list.find('*').not('.k-textbox').attr('unselectable', 'on');
}
},
_toggleHover: function (e) {
$(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
},
_toggle: function (open, preventFocus) {
var that = this;
var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
open = open !== undefined ? open : !that.popup.visible();
if (!preventFocus && !touchEnabled && that._focused[0] !== activeElement()) {
that._prevent = true;
that._focused.focus();
that._prevent = false;
}
that[open ? OPEN : CLOSE]();
},
_triggerCascade: function () {
var that = this;
if (!that._cascadeTriggered || that._old !== that.value() || that._oldIndex !== that.selectedIndex) {
that._cascadeTriggered = true;
that.trigger(CASCADE, { userTriggered: that._userTriggered });
}
},
_triggerChange: function () {
if (this._valueBeforeCascade !== this.value()) {
this.trigger(CHANGE);
}
},
_unbindDataSource: function () {
var that = this;
that.dataSource.unbind(REQUESTSTART, that._requestStartHandler).unbind(REQUESTEND, that._requestEndHandler).unbind('error', that._errorHandler);
}
});
function unifyType(value, type) {
if (value !== undefined && value !== '' && value !== null) {
if (type === 'boolean') {
value = Boolean(value);
} else if (type === 'number') {
value = Number(value);
} else if (type === 'string') {
value = value.toString();
}
}
return value;
}
extend(List, {
inArray: function (node, parentNode) {
var idx, length, siblings = parentNode.children;
if (!node || node.parentNode !== parentNode) {
return -1;
}
for (idx = 0, length = siblings.length; idx < length; idx++) {
if (node === siblings[idx]) {
return idx;
}
}
return -1;
},
unifyType: unifyType
});
kendo.ui.List = List;
ui.Select = List.extend({
init: function (element, options) {
List.fn.init.call(this, element, options);
this._initial = this.element.val();
},
setDataSource: function (dataSource) {
var that = this;
var parent;
that.options.dataSource = dataSource;
that._dataSource();
if (that.listView.bound()) {
that._initialIndex = null;
}
that.listView.setDataSource(that.dataSource);
if (that.options.autoBind) {
that.dataSource.fetch();
}
parent = that._parentWidget();
if (parent) {
that._cascadeSelect(parent);
}
},
close: function () {
this.popup.close();
},
select: function (candidate) {
var that = this;
if (candidate === undefined) {
return that.selectedIndex;
} else {
that._select(candidate);
that._old = that._accessor();
that._oldIndex = that.selectedIndex;
}
},
search: function (word) {
word = typeof word === 'string' ? word : this.text();
var that = this;
var length = word.length;
var options = that.options;
var ignoreCase = options.ignoreCase;
var field = options.dataTextField;
clearTimeout(that._typingTimeout);
if (!length || length >= options.minLength) {
that._state = 'filter';
if (!that._isFilterEnabled()) {
that._filter(word);
} else {
that._open = true;
that._filterSource({
value: ignoreCase ? word.toLowerCase() : word,
field: field,
operator: options.filter,
ignoreCase: ignoreCase
});
}
}
},
_accessor: function (value, idx) {
return this[this._isSelect ? '_accessorSelect' : '_accessorInput'](value, idx);
},
_accessorInput: function (value) {
var element = this.element[0];
if (value === undefined) {
return element.value;
} else {
if (value === null) {
value = '';
}
element.value = value;
}
},
_accessorSelect: function (value, idx) {
var element = this.element[0];
var selectedIndex = element.selectedIndex;
var option;
if (value === undefined) {
if (selectedIndex > -1) {
option = element.options[selectedIndex];
}
if (option) {
value = option.value;
}
return value || '';
} else {
if (selectedIndex > -1) {
element.options[selectedIndex].removeAttribute(SELECTED);
element.options[selectedIndex].selected = false;
}
if (idx === undefined) {
idx = -1;
}
if (value !== null && value !== '' && idx == -1) {
this._custom(value);
} else {
if (value) {
element.value = value;
} else {
element.selectedIndex = idx;
}
if (element.selectedIndex > -1) {
option = element.options[element.selectedIndex];
}
if (option) {
option.setAttribute(SELECTED, SELECTED);
}
}
}
},
_custom: function (value) {
var that = this;
var element = that.element;
var custom = that._customOption;
if (!custom) {
custom = $('
');
that._customOption = custom;
element.append(custom);
}
custom.text(value);
custom[0].setAttribute(SELECTED, SELECTED);
custom[0].selected = true;
},
_hideBusy: function () {
var that = this;
clearTimeout(that._busy);
that._arrow.removeClass(LOADING);
that._focused.attr('aria-busy', false);
that._busy = null;
},
_showBusy: function () {
var that = this;
that._request = true;
if (that._busy) {
return;
}
that._busy = setTimeout(function () {
if (that._arrow) {
that._focused.attr('aria-busy', true);
that._arrow.addClass(LOADING);
}
}, 100);
},
_requestEnd: function () {
this._request = false;
this._hideBusy();
},
_dataSource: function () {
var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {}, idx;
dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
if (that._isSelect) {
idx = element[0].selectedIndex;
if (idx > -1) {
options.index = idx;
}
dataSource.select = element;
dataSource.fields = [
{ field: options.dataTextField },
{ field: options.dataValueField }
];
}
if (that.dataSource) {
that._unbindDataSource();
} else {
that._requestStartHandler = proxy(that._showBusy, that);
that._requestEndHandler = proxy(that._requestEnd, that);
that._errorHandler = proxy(that._hideBusy, that);
}
that.dataSource = kendo.data.DataSource.create(dataSource).bind(REQUESTSTART, that._requestStartHandler).bind(REQUESTEND, that._requestEndHandler).bind('error', that._errorHandler);
},
_firstItem: function () {
this.listView.focusFirst();
},
_lastItem: function () {
this.listView.focusLast();
},
_nextItem: function () {
this.listView.focusNext();
},
_prevItem: function () {
this.listView.focusPrev();
},
_move: function (e) {
var that = this;
var key = e.keyCode;
var down = key === keys.DOWN;
var dataItem;
var pressed;
var current;
if (key === keys.UP || down) {
if (e.altKey) {
that.toggle(down);
} else {
if (!that.listView.bound()) {
if (!that._fetch) {
that.dataSource.one(CHANGE, function () {
that._fetch = false;
that._move(e);
});
that._fetch = true;
that._filterSource();
}
e.preventDefault();
return true;
}
current = that._focus();
if (!that._fetch && (!current || current.hasClass('k-state-selected'))) {
if (down) {
that._nextItem();
if (!that._focus()) {
that._lastItem();
}
} else {
that._prevItem();
if (!that._focus()) {
that._firstItem();
}
}
}
if (that.trigger(SELECT, { item: that._focus() })) {
that._focus(current);
return;
}
that._select(that._focus(), true);
if (!that.popup.visible()) {
that._blur();
}
}
e.preventDefault();
pressed = true;
} else if (key === keys.ENTER || key === keys.TAB) {
if (that.popup.visible()) {
e.preventDefault();
}
current = that._focus();
dataItem = that.dataItem();
if (!that.popup.visible() && (!dataItem || that.text() !== that._text(dataItem))) {
current = null;
}
var activeFilter = that.filterInput && that.filterInput[0] === activeElement();
if (current) {
if (that.trigger(SELECT, { item: current })) {
return;
}
that._select(current);
} else if (that.input) {
that._accessor(that.input.val());
that.listView.value(that.input.val());
}
if (that._focusElement) {
that._focusElement(that.wrapper);
}
if (activeFilter && key === keys.TAB) {
that.wrapper.focusout();
} else {
that._blur();
}
that.close();
pressed = true;
} else if (key === keys.ESC) {
if (that.popup.visible()) {
e.preventDefault();
}
that.close();
pressed = true;
}
return pressed;
},
_fetchData: function () {
var that = this;
var hasItems = !!that.dataSource.view().length;
if (that._request || that.options.cascadeFrom) {
return;
}
if (!that.listView.bound() && !that._fetch && !hasItems) {
that._fetch = true;
that.dataSource.fetch().done(function () {
that._fetch = false;
});
}
},
_options: function (data, optionLabel, value) {
var that = this, element = that.element, length = data.length, options = '', option, dataItem, dataText, dataValue, idx = 0;
if (optionLabel) {
options = optionLabel;
}
for (; idx < length; idx++) {
option = '
';
options += option;
}
element.html(options);
if (value !== undefined) {
element[0].value = value;
if (element[0].value && !value) {
element[0].selectedIndex = -1;
}
}
},
_reset: function () {
var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
if (form[0]) {
that._resetHandler = function () {
setTimeout(function () {
that.value(that._initial);
});
};
that._form = form.on('reset', that._resetHandler);
}
},
_parentWidget: function () {
var name = this.options.name;
var parentElement = $('#' + this.options.cascadeFrom);
var parent = parentElement.data('kendo' + name);
if (!parent) {
parent = parentElement.data('kendo' + alternativeNames[name]);
}
return parent;
},
_cascade: function () {
var that = this;
var options = that.options;
var cascade = options.cascadeFrom;
var cascadeHandler;
var parent;
if (cascade) {
parent = that._parentWidget();
if (!parent) {
return;
}
parent.bind('set', function () {
that.one('set', function (e) {
that._selectedValue = e.value;
});
});
options.autoBind = false;
cascadeHandler = proxy(function (e) {
var valueBeforeCascade = this.value();
this._userTriggered = e.userTriggered;
if (this.listView.bound()) {
this._clearSelection(parent, true);
}
this._cascadeSelect(parent, valueBeforeCascade);
}, that);
parent.first(CASCADE, cascadeHandler);
parent._focused.bind('focus', function () {
parent.unbind(CASCADE, cascadeHandler);
parent.first(CHANGE, cascadeHandler);
});
parent._focused.bind('focusout', function () {
parent.unbind(CHANGE, cascadeHandler);
parent.first(CASCADE, cascadeHandler);
});
if (parent.listView.bound()) {
that._cascadeSelect(parent);
} else if (!parent.value()) {
that.enable(false);
}
}
},
_cascadeChange: function (parent) {
var that = this;
var value = that._accessor() || that._selectedValue;
that._selectedValue = null;
if (that._userTriggered) {
that._clearSelection(parent, true);
} else if (value) {
if (value !== that.listView.value()[0]) {
that.value(value);
}
if (!that.dataSource.view()[0] || that.selectedIndex === -1) {
that._clearSelection(parent, true);
}
} else if (that.dataSource.flatView().length) {
that.select(that.options.index);
}
that.enable();
that._triggerCascade();
that._triggerChange();
that._userTriggered = false;
},
_cascadeSelect: function (parent, valueBeforeCascade) {
var that = this;
var dataItem = parent.dataItem();
var filterValue = dataItem ? parent._value(dataItem) : null;
var valueField = that.options.cascadeFromField || parent.options.dataValueField;
var expressions, filters;
that._valueBeforeCascade = valueBeforeCascade !== undefined ? valueBeforeCascade : that.value();
if (filterValue || filterValue === 0) {
expressions = that.dataSource.filter() || {};
removeFiltersForField(expressions, valueField);
filters = (expressions.filters || []).slice(0);
filters.push({
field: valueField,
operator: 'eq',
value: filterValue
});
var handler = function () {
that.unbind('dataBound', handler);
that._cascadeChange(parent);
};
that.first('dataBound', handler);
that._cascading = true;
that._filterSource({
field: valueField,
operator: 'eq',
value: filterValue
});
that._cascading = false;
} else {
that.enable(false);
that._clearSelection(parent);
that._triggerCascade();
that._triggerChange();
that._userTriggered = false;
}
}
});
var STATIC_LIST_NS = '.StaticList';
var StaticList = kendo.ui.DataBoundWidget.extend({
init: function (element, options) {
Widget.fn.init.call(this, element, options);
this.element.attr('role', 'listbox').on('click' + STATIC_LIST_NS, 'li', proxy(this._click, this)).on('mouseenter' + STATIC_LIST_NS, 'li', function () {
$(this).addClass(HOVER);
}).on('mouseleave' + STATIC_LIST_NS, 'li', function () {
$(this).removeClass(HOVER);
});
this.content = this.element.wrap('
').parent();
this.header = this.content.before('').prev();
this.bound(false);
this._optionID = kendo.guid();
this._selectedIndices = [];
this._view = [];
this._dataItems = [];
this._values = [];
var value = this.options.value;
if (value) {
this._values = $.isArray(value) ? value.slice(0) : [value];
}
this._getter();
this._templates();
this.setDataSource(this.options.dataSource);
this._onScroll = proxy(function () {
var that = this;
clearTimeout(that._scrollId);
that._scrollId = setTimeout(function () {
that._renderHeader();
}, 50);
}, this);
},
options: {
name: 'StaticList',
dataValueField: null,
valuePrimitive: false,
selectable: true,
template: null,
groupTemplate: null,
fixedGroupTemplate: null
},
events: [
'click',
CHANGE,
'activate',
'deactivate',
'dataBinding',
'dataBound',
'selectedItemChange'
],
setDataSource: function (source) {
var that = this;
var dataSource = source || {};
var value;
dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
dataSource = kendo.data.DataSource.create(dataSource);
if (that.dataSource) {
that.dataSource.unbind(CHANGE, that._refreshHandler);
value = that.value();
that.value([]);
that.bound(false);
that.value(value);
} else {
that._refreshHandler = proxy(that.refresh, that);
}
that.setDSFilter(dataSource.filter());
that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
that._fixedHeader();
},
skip: function () {
return this.dataSource.skip();
},
setOptions: function (options) {
Widget.fn.setOptions.call(this, options);
this._getter();
this._templates();
this._render();
},
destroy: function () {
this.element.off(STATIC_LIST_NS);
if (this._refreshHandler) {
this.dataSource.unbind(CHANGE, this._refreshHandler);
}
clearTimeout(this._scrollId);
Widget.fn.destroy.call(this);
},
scrollToIndex: function (index) {
var item = this.element[0].children[index];
if (item) {
this.scroll(item);
}
},
scroll: function (item) {
if (!item) {
return;
}
if (item[0]) {
item = item[0];
}
var content = this.content[0], itemOffsetTop = item.offsetTop, itemOffsetHeight = item.offsetHeight, contentScrollTop = content.scrollTop, contentOffsetHeight = content.clientHeight, bottomDistance = itemOffsetTop + itemOffsetHeight;
if (contentScrollTop > itemOffsetTop) {
contentScrollTop = itemOffsetTop;
} else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
contentScrollTop = bottomDistance - contentOffsetHeight;
}
content.scrollTop = contentScrollTop;
},
selectedDataItems: function (dataItems) {
if (dataItems === undefined) {
return this._dataItems.slice();
}
this._dataItems = dataItems;
this._values = this._getValues(dataItems);
},
_getValues: function (dataItems) {
var getter = this._valueGetter;
return $.map(dataItems, function (dataItem) {
return getter(dataItem);
});
},
focusNext: function () {
var current = this.focus();
if (!current) {
current = 0;
} else {
current = current.next();
}
this.focus(current);
},
focusPrev: function () {
var current = this.focus();
if (!current) {
current = this.element[0].children.length - 1;
} else {
current = current.prev();
}
this.focus(current);
},
focusFirst: function () {
this.focus(this.element[0].children[0]);
},
focusLast: function () {
this.focus(this.element[0].children[this.element[0].children.length - 1]);
},
focus: function (candidate) {
var that = this;
var id = that._optionID;
var hasCandidate;
if (candidate === undefined) {
return that._current;
}
candidate = that._get(candidate);
candidate = candidate[candidate.length - 1];
candidate = $(this.element[0].children[candidate]);
if (that._current) {
that._current.removeClass(FOCUSED).removeAttr('aria-selected').removeAttr(ID);
that.trigger('deactivate');
}
hasCandidate = !!candidate[0];
if (hasCandidate) {
candidate.addClass(FOCUSED);
that.scroll(candidate);
candidate.attr('id', id);
}
that._current = hasCandidate ? candidate : null;
that.trigger('activate');
},
focusIndex: function () {
return this.focus() ? this.focus().index() : undefined;
},
skipUpdate: function (skipUpdate) {
this._skipUpdate = skipUpdate;
},
select: function (indices) {
var that = this;
var selectable = that.options.selectable;
var singleSelection = selectable !== 'multiple' && selectable !== false;
var selectedIndices = that._selectedIndices;
var added = [];
var removed = [];
var result;
if (indices === undefined) {
return selectedIndices.slice();
}
indices = that._get(indices);
if (indices.length === 1 && indices[0] === -1) {
indices = [];
}
var filtered = that.isFiltered();
if (filtered && !singleSelection && that._deselectFiltered(indices)) {
return;
}
if (singleSelection && !filtered && $.inArray(indices[indices.length - 1], selectedIndices) !== -1) {
if (that._dataItems.length && that._view.length) {
that._dataItems = [that._view[selectedIndices[0]].item];
}
return;
}
result = that._deselect(indices);
removed = result.removed;
indices = result.indices;
if (indices.length) {
if (singleSelection) {
indices = [indices[indices.length - 1]];
}
added = that._select(indices);
}
if (added.length || removed.length) {
that._valueComparer = null;
that.trigger(CHANGE, {
added: added,
removed: removed
});
}
},
removeAt: function (position) {
this._selectedIndices.splice(position, 1);
this._values.splice(position, 1);
this._valueComparer = null;
return {
position: position,
dataItem: this._dataItems.splice(position, 1)[0]
};
},
setValue: function (value) {
value = $.isArray(value) || value instanceof ObservableArray ? value.slice(0) : [value];
this._values = value;
this._valueComparer = null;
},
value: function (value) {
var that = this;
var deferred = that._valueDeferred;
var indices;
if (value === undefined) {
return that._values.slice();
}
that.setValue(value);
if (!deferred || deferred.state() === 'resolved') {
that._valueDeferred = deferred = $.Deferred();
}
if (that.bound()) {
indices = that._valueIndices(that._values);
if (that.options.selectable === 'multiple') {
that.select(-1);
}
that.select(indices);
deferred.resolve();
}
that._skipUpdate = false;
return deferred;
},
items: function () {
return this.element.children('.k-item');
},
_click: function (e) {
if (!e.isDefaultPrevented()) {
if (!this.trigger('click', { item: $(e.currentTarget) })) {
this.select(e.currentTarget);
}
}
},
_valueExpr: function (type, values) {
var that = this;
var idx = 0;
var body;
var comparer;
var normalized = [];
if (!that._valueComparer || that._valueType !== type) {
that._valueType = type;
for (; idx < values.length; idx++) {
normalized.push(unifyType(values[idx], type));
}
body = 'for (var idx = 0; idx < ' + normalized.length + '; idx++) {' + ' if (current === values[idx]) {' + ' return idx;' + ' }' + '} ' + 'return -1;';
comparer = new Function('current', 'values', body);
that._valueComparer = function (current) {
return comparer(current, normalized);
};
}
return that._valueComparer;
},
_dataItemPosition: function (dataItem, values) {
var value = this._valueGetter(dataItem);
var valueExpr = this._valueExpr(typeof value, values);
return valueExpr(value);
},
_getter: function () {
this._valueGetter = kendo.getter(this.options.dataValueField);
},
_deselect: function (indices) {
var that = this;
var children = that.element[0].children;
var selectable = that.options.selectable;
var selectedIndices = that._selectedIndices;
var dataItems = that._dataItems;
var values = that._values;
var removed = [];
var i = 0;
var j;
var index, selectedIndex;
var removedIndices = 0;
indices = indices.slice();
if (selectable === true || !indices.length) {
for (; i < selectedIndices.length; i++) {
$(children[selectedIndices[i]]).removeClass('k-state-selected');
removed.push({
position: i,
dataItem: dataItems[i]
});
}
that._values = [];
that._dataItems = [];
that._selectedIndices = [];
} else if (selectable === 'multiple') {
for (; i < indices.length; i++) {
index = indices[i];
if (!$(children[index]).hasClass('k-state-selected')) {
continue;
}
for (j = 0; j < selectedIndices.length; j++) {
selectedIndex = selectedIndices[j];
if (selectedIndex === index) {
$(children[selectedIndex]).removeClass('k-state-selected');
removed.push({
position: j + removedIndices,
dataItem: dataItems.splice(j, 1)[0]
});
selectedIndices.splice(j, 1);
indices.splice(i, 1);
values.splice(j, 1);
removedIndices += 1;
i -= 1;
j -= 1;
break;
}
}
}
}
return {
indices: indices,
removed: removed
};
},
_deselectFiltered: function (indices) {
var children = this.element[0].children;
var dataItem, index, position;
var removed = [];
var idx = 0;
for (; idx < indices.length; idx++) {
index = indices[idx];
dataItem = this._view[index].item;
position = this._dataItemPosition(dataItem, this._values);
if (position > -1) {
removed.push(this.removeAt(position));
$(children[index]).removeClass('k-state-selected');
}
}
if (removed.length) {
this.trigger(CHANGE, {
added: [],
removed: removed
});
return true;
}
return false;
},
_select: function (indices) {
var that = this;
var children = that.element[0].children;
var data = that._view;
var dataItem, index;
var added = [];
var idx = 0;
if (indices[indices.length - 1] !== -1) {
that.focus(indices);
}
for (; idx < indices.length; idx++) {
index = indices[idx];
dataItem = data[index];
if (index === -1 || !dataItem) {
continue;
}
dataItem = dataItem.item;
that._selectedIndices.push(index);
that._dataItems.push(dataItem);
that._values.push(that._valueGetter(dataItem));
$(children[index]).addClass('k-state-selected').attr('aria-selected', true);
added.push({ dataItem: dataItem });
}
return added;
},
_get: function (candidate) {
if (typeof candidate === 'number') {
candidate = [candidate];
} else if (!isArray(candidate)) {
candidate = $(candidate).data('offset-index');
if (candidate === undefined) {
candidate = -1;
}
candidate = [candidate];
}
return candidate;
},
_template: function () {
var that = this;
var options = that.options;
var template = options.template;
if (!template) {
template = kendo.template('
${' + kendo.expr(options.dataTextField, 'data') + '}', { useWithBlock: false });
} else {
template = kendo.template(template);
template = function (data) {
return '
' + template(data) + '';
};
}
return template;
},
_templates: function () {
var template;
var templates = {
template: this.options.template,
groupTemplate: this.options.groupTemplate,
fixedGroupTemplate: this.options.fixedGroupTemplate
};
for (var key in templates) {
template = templates[key];
if (template && typeof template !== 'function') {
templates[key] = kendo.template(template);
}
}
this.templates = templates;
},
_normalizeIndices: function (indices) {
var newIndices = [];
var idx = 0;
for (; idx < indices.length; idx++) {
if (indices[idx] !== undefined) {
newIndices.push(indices[idx]);
}
}
return newIndices;
},
_valueIndices: function (values, indices) {
var data = this._view;
var idx = 0;
var index;
indices = indices ? indices.slice() : [];
if (!values.length) {
return [];
}
for (; idx < data.length; idx++) {
index = this._dataItemPosition(data[idx].item, values);
if (index !== -1) {
indices[index] = idx;
}
}
return this._normalizeIndices(indices);
},
_firstVisibleItem: function () {
var element = this.element[0];
var content = this.content[0];
var scrollTop = content.scrollTop;
var itemHeight = $(element.children[0]).height();
var itemIndex = Math.floor(scrollTop / itemHeight) || 0;
var item = element.children[itemIndex] || element.lastChild;
var forward = item.offsetTop < scrollTop;
while (item) {
if (forward) {
if (item.offsetTop + itemHeight > scrollTop || !item.nextSibling) {
break;
}
item = item.nextSibling;
} else {
if (item.offsetTop <= scrollTop || !item.previousSibling) {
break;
}
item = item.previousSibling;
}
}
return this._view[$(item).data('offset-index')];
},
_fixedHeader: function () {
if (this.isGrouped() && this.templates.fixedGroupTemplate) {
this.header.show();
this.content.scroll(this._onScroll);
} else {
this.header.hide();
this.content.off('scroll', this._onScroll);
}
},
_renderHeader: function () {
var template = this.templates.fixedGroupTemplate;
if (!template) {
return;
}
var visibleItem = this._firstVisibleItem();
if (visibleItem) {
this.header.html(template(visibleItem.group));
}
},
_renderItem: function (context) {
var item = '
';
item += this.templates.template(dataItem);
if (notFirstItem && context.newGroup) {
item += '' + this.templates.groupTemplate(context.group) + '
';
}
return item + '';
},
_render: function () {
var html = '';
var i = 0;
var idx = 0;
var context;
var dataContext = [];
var view = this.dataSource.view();
var values = this.value();
var group, newGroup, j;
var isGrouped = this.isGrouped();
if (isGrouped) {
for (i = 0; i < view.length; i++) {
group = view[i];
newGroup = true;
for (j = 0; j < group.items.length; j++) {
context = {
selected: this._selected(group.items[j], values),
item: group.items[j],
group: group.value,
newGroup: newGroup,
index: idx
};
dataContext[idx] = context;
idx += 1;
html += this._renderItem(context);
newGroup = false;
}
}
} else {
for (i = 0; i < view.length; i++) {
context = {
selected: this._selected(view[i], values),
item: view[i],
index: i
};
dataContext[i] = context;
html += this._renderItem(context);
}
}
this._view = dataContext;
this.element[0].innerHTML = html;
if (isGrouped && dataContext.length) {
this._renderHeader();
}
},
_selected: function (dataItem, values) {
var select = !this.isFiltered() || this.options.selectable === 'multiple';
return select && this._dataItemPosition(dataItem, values) !== -1;
},
setDSFilter: function (filter) {
this._lastDSFilter = extend({}, filter);
},
isFiltered: function () {
if (!this._lastDSFilter) {
this.setDSFilter(this.dataSource.filter());
}
return !kendo.data.Query.compareFilters(this.dataSource.filter(), this._lastDSFilter);
},
refresh: function (e) {
var that = this;
var action = e && e.action;
var skipUpdateOnBind = that.options.skipUpdateOnBind;
var isItemChange = action === 'itemchange';
var result;
that.trigger('dataBinding');
that._fixedHeader();
that._render();
that.bound(true);
if (isItemChange || action === 'remove') {
result = mapChangedItems(that._dataItems, e.items);
if (result.changed.length) {
if (isItemChange) {
that.trigger('selectedItemChange', { items: result.changed });
} else {
that.value(that._getValues(result.unchanged));
}
}
} else if (that.isFiltered() || that._skipUpdate) {
that.focus(0);
if (that._skipUpdate) {
that._skipUpdate = false;
that._selectedIndices = that._valueIndices(that._values, that._selectedIndices);
}
} else if (!skipUpdateOnBind && (!action || action === 'add')) {
that.value(that._values);
}
if (that._valueDeferred) {
that._valueDeferred.resolve();
}
that.trigger('dataBound');
},
bound: function (bound) {
if (bound === undefined) {
return this._bound;
}
this._bound = bound;
},
isGrouped: function () {
return (this.dataSource.group() || []).length;
}
});
ui.plugin(StaticList);
function mapChangedItems(selected, itemsToMatch) {
var itemsLength = itemsToMatch.length;
var selectedLength = selected.length;
var dataItem;
var found;
var i, j;
var changed = [];
var unchanged = [];
if (selectedLength) {
for (i = 0; i < selectedLength; i++) {
dataItem = selected[i];
found = false;
for (j = 0; j < itemsLength; j++) {
if (dataItem === itemsToMatch[j]) {
found = true;
changed.push({
index: i,
item: dataItem
});
break;
}
}
if (!found) {
unchanged.push(dataItem);
}
}
}
return {
changed: changed,
unchanged: unchanged
};
}
function removeFiltersForField(expression, field) {
var filters;
var found = false;
if (expression.filters) {
filters = $.grep(expression.filters, function (filter) {
found = removeFiltersForField(filter, field);
if (filter.filters) {
return filter.filters.length;
} else {
return filter.field != field;
}
});
if (!found && expression.filters.length !== filters.length) {
found = true;
}
expression.filters = filters;
}
return found;
}
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dropdownlist', [
'kendo.list',
'kendo.mobile.scroller'
], f);
}(function () {
var __meta__ = {
id: 'dropdownlist',
name: 'DropDownList',
category: 'web',
description: 'The DropDownList widget displays a list of values and allows the selection of a single value from the list.',
depends: ['list'],
features: [
{
id: 'mobile-scroller',
name: 'Mobile scroller',
description: 'Support for kinetic scrolling in mobile device',
depends: ['mobile.scroller']
},
{
id: 'virtualization',
name: 'VirtualList',
description: 'Support for virtualization',
depends: ['virtuallist']
}
]
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.ui, List = ui.List, Select = ui.Select, support = kendo.support, activeElement = kendo._activeElement, ObservableObject = kendo.data.ObservableObject, keys = kendo.keys, ns = '.kendoDropDownList', DISABLED = 'disabled', READONLY = 'readonly', CHANGE = 'change', FOCUSED = 'k-state-focused', DEFAULT = 'k-state-default', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', ARIA_READONLY = 'aria-readonly', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, TABINDEX = 'tabindex', STATE_FILTER = 'filter', STATE_ACCEPT = 'accept', MSG_INVALID_OPTION_LABEL = 'The `optionLabel` option is not valid due to missing fields. Define a custom optionLabel as shown here http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#configuration-optionLabel', proxy = $.proxy;
var DropDownList = Select.extend({
init: function (element, options) {
var that = this;
var index = options && options.index;
var optionLabel, text, disabled;
that.ns = ns;
options = $.isArray(options) ? { dataSource: options } : options;
Select.fn.init.call(that, element, options);
options = that.options;
element = that.element.on('focus' + ns, proxy(that._focusHandler, that));
that._focusInputHandler = $.proxy(that._focusInput, that);
that.optionLabel = $();
that._optionLabel();
that._inputTemplate();
that._reset();
that._prev = '';
that._word = '';
that._wrapper();
that._tabindex();
that.wrapper.data(TABINDEX, that.wrapper.attr(TABINDEX));
that._span();
that._popup();
that._mobile();
that._dataSource();
that._ignoreCase();
that._filterHeader();
that._aria();
that._enable();
that._oldIndex = that.selectedIndex = -1;
if (index !== undefined) {
options.index = index;
}
that._initialIndex = options.index;
that._initList();
that._cascade();
if (options.autoBind) {
that.dataSource.fetch();
} else if (that.selectedIndex === -1) {
text = options.text || '';
if (!text) {
optionLabel = options.optionLabel;
if (optionLabel && options.index === 0) {
text = optionLabel;
} else if (that._isSelect) {
text = element.children(':selected').text();
}
}
that._textAccessor(text);
}
disabled = $(that.element).parents('fieldset').is(':disabled');
if (disabled) {
that.enable(false);
}
that.listView.bind('click', function (e) {
e.preventDefault();
});
kendo.notify(that);
},
options: {
name: 'DropDownList',
enabled: true,
autoBind: true,
index: 0,
text: null,
value: null,
delay: 500,
height: 200,
dataTextField: '',
dataValueField: '',
optionLabel: '',
cascadeFrom: '',
cascadeFromField: '',
ignoreCase: true,
animation: {},
filter: 'none',
minLength: 1,
virtual: false,
template: null,
valueTemplate: null,
optionLabelTemplate: null,
groupTemplate: '#:data#',
fixedGroupTemplate: '#:data#'
},
events: [
'open',
'close',
CHANGE,
'select',
'filtering',
'dataBinding',
'dataBound',
'cascade',
'set'
],
setOptions: function (options) {
Select.fn.setOptions.call(this, options);
this.listView.setOptions(this._listOptions(options));
this._optionLabel();
this._inputTemplate();
this._accessors();
this._filterHeader();
this._enable();
this._aria();
if (!this.value() && this.hasOptionLabel()) {
this.select(0);
}
},
destroy: function () {
var that = this;
Select.fn.destroy.call(that);
that.wrapper.off(ns);
that.element.off(ns);
that._inputWrapper.off(ns);
that._arrow.off();
that._arrow = null;
that.optionLabel.off();
},
open: function () {
var that = this;
if (that.popup.visible()) {
return;
}
if (!that.listView.bound() || that._state === STATE_ACCEPT) {
that._open = true;
that._state = 'rebind';
if (that.filterInput) {
that.filterInput.val('');
that._prev = '';
}
that._filterSource();
} else if (that._allowOpening()) {
that.popup.one('activate', that._focusInputHandler);
that.popup.open();
that._focusItem();
}
},
_focusInput: function () {
this._focusElement(this.filterInput);
},
_allowOpening: function () {
return this.hasOptionLabel() || this.filterInput || this.dataSource.view().length;
},
toggle: function (toggle) {
this._toggle(toggle, true);
},
current: function (candidate) {
var current;
if (candidate === undefined) {
current = this.listView.focus();
if (!current && this.selectedIndex === 0 && this.hasOptionLabel()) {
return this.optionLabel;
}
return current;
}
this._focus(candidate);
},
dataItem: function (index) {
var that = this;
var dataItem = null;
if (index === null) {
return index;
}
if (index === undefined) {
dataItem = that.listView.selectedDataItems()[0];
} else {
if (typeof index !== 'number') {
if (that.options.virtual) {
return that.dataSource.getByUid($(index).data('uid'));
}
if (index.hasClass('k-list-optionlabel')) {
index = -1;
} else {
index = $(that.items()).index(index);
}
} else if (that.hasOptionLabel()) {
index -= 1;
}
dataItem = that.dataSource.flatView()[index];
}
if (!dataItem) {
dataItem = that._optionLabelDataItem();
}
return dataItem;
},
refresh: function () {
this.listView.refresh();
},
text: function (text) {
var that = this;
var dataItem, loweredText;
var ignoreCase = that.options.ignoreCase;
text = text === null ? '' : text;
if (text !== undefined) {
if (typeof text === 'string') {
loweredText = ignoreCase ? text.toLowerCase() : text;
that._select(function (data) {
data = that._text(data);
if (ignoreCase) {
data = (data + '').toLowerCase();
}
return data === loweredText;
});
dataItem = that.dataItem();
if (dataItem) {
text = dataItem;
}
}
that._textAccessor(text);
} else {
return that._textAccessor();
}
},
value: function (value) {
var that = this;
var listView = that.listView;
var dataSource = that.dataSource;
if (value === undefined) {
value = that._accessor() || that.listView.value()[0];
return value === undefined || value === null ? '' : value;
}
if (value || !that.hasOptionLabel()) {
that._initialIndex = null;
}
this.trigger('set', { value: value });
if (that._request && that.options.cascadeFrom && that.listView.bound()) {
if (that._valueSetter) {
dataSource.unbind(CHANGE, that._valueSetter);
}
that._valueSetter = proxy(function () {
that.value(value);
}, that);
dataSource.one(CHANGE, that._valueSetter);
return;
}
if (that._isFilterEnabled() && listView.bound() && listView.isFiltered()) {
listView.bound(false);
that._filterSource();
} else {
that._fetchData();
}
listView.value(value).done(function () {
if (that.selectedIndex === -1 && that.text()) {
that.text('');
that._accessor('', -1);
}
that._old = that._accessor();
that._oldIndex = that.selectedIndex;
});
},
hasOptionLabel: function () {
return this.optionLabel && !!this.optionLabel[0];
},
_optionLabel: function () {
var that = this;
var options = that.options;
var optionLabel = options.optionLabel;
var template = options.optionLabelTemplate;
if (!optionLabel) {
that.optionLabel.off().remove();
that.optionLabel = $();
return;
}
if (!template) {
template = '#:';
if (typeof optionLabel === 'string') {
template += 'data';
} else {
template += kendo.expr(options.dataTextField, 'data');
}
template += '#';
}
if (typeof template !== 'function') {
template = kendo.template(template);
}
that.optionLabelTemplate = template;
if (!that.hasOptionLabel()) {
that.optionLabel = $('
').prependTo(that.list);
}
that.optionLabel.html(template(optionLabel)).off().click(proxy(that._click, that)).on(HOVEREVENTS, that._toggleHover);
that.angular('compile', function () {
return {
elements: that.optionLabel,
data: [{ dataItem: that._optionLabelDataItem() }]
};
});
},
_optionLabelText: function () {
var optionLabel = this.options.optionLabel;
return typeof optionLabel === 'string' ? optionLabel : this._text(optionLabel);
},
_optionLabelDataItem: function () {
var that = this;
var optionLabel = that.options.optionLabel;
if (that.hasOptionLabel()) {
return $.isPlainObject(optionLabel) ? new ObservableObject(optionLabel) : that._assignInstance(that._optionLabelText(), '');
}
return null;
},
_buildOptions: function (data) {
var that = this;
if (!that._isSelect) {
return;
}
var value = that.listView.value()[0];
var optionLabel = that._optionLabelDataItem();
if (value === undefined || value === null) {
value = '';
}
if (optionLabel) {
optionLabel = '
';
}
that._options(data, optionLabel, value);
if (value !== List.unifyType(that._accessor(), typeof value)) {
that._customOption = null;
that._custom(value);
}
},
_listBound: function () {
var that = this;
var initialIndex = that._initialIndex;
var filtered = that._state === STATE_FILTER;
var data = that.dataSource.flatView();
var dataItem;
that._angularItems('compile');
that._presetValue = false;
that._resizePopup(true);
that.popup.position();
that._buildOptions(data);
that._makeUnselectable();
if (!filtered) {
if (that._open) {
that.toggle(that._allowOpening());
}
that._open = false;
if (!that._fetch) {
if (data.length) {
if (!that.listView.value().length && initialIndex > -1 && initialIndex !== null) {
that.select(initialIndex);
}
that._initialIndex = null;
dataItem = that.listView.selectedDataItems()[0];
if (dataItem && that.text() !== that._text(dataItem)) {
that._selectValue(dataItem);
}
} else if (that._textAccessor() !== that._optionLabelText()) {
that.listView.value('');
that._selectValue(null);
that._oldIndex = that.selectedIndex;
}
}
}
that._hideBusy();
that.trigger('dataBound');
},
_listChange: function () {
this._selectValue(this.listView.selectedDataItems()[0]);
if (this._presetValue || this._old && this._oldIndex === -1) {
this._oldIndex = this.selectedIndex;
}
},
_focusHandler: function () {
this.wrapper.focus();
},
_focusinHandler: function () {
this._inputWrapper.addClass(FOCUSED);
this._prevent = false;
},
_focusoutHandler: function () {
var that = this;
var filtered = that._state === STATE_FILTER;
var isIFrame = window.self !== window.top;
var focusedItem = that._focus();
if (!that._prevent) {
clearTimeout(that._typingTimeout);
if (filtered && focusedItem && !that.trigger('select', { item: focusedItem })) {
that._select(focusedItem, !that.dataSource.view().length);
}
if (support.mobileOS.ios && isIFrame) {
that._change();
} else {
that._blur();
}
that._inputWrapper.removeClass(FOCUSED);
that._prevent = true;
that._open = false;
that.element.blur();
}
},
_wrapperMousedown: function () {
this._prevent = !!this.filterInput;
},
_wrapperClick: function (e) {
e.preventDefault();
this.popup.unbind('activate', this._focusInputHandler);
this._focused = this.wrapper;
this._toggle();
},
_editable: function (options) {
var that = this;
var element = that.element;
var disable = options.disable;
var readonly = options.readonly;
var wrapper = that.wrapper.add(that.filterInput).off(ns);
var dropDownWrapper = that._inputWrapper.off(HOVEREVENTS);
if (!readonly && !disable) {
element.removeAttr(DISABLED).removeAttr(READONLY);
dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
wrapper.attr(TABINDEX, wrapper.data(TABINDEX)).attr(ARIA_DISABLED, false).attr(ARIA_READONLY, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that)).on('mousedown' + ns, proxy(that._wrapperMousedown, that));
that.wrapper.on('click' + ns, proxy(that._wrapperClick, that));
if (!that.filterInput) {
wrapper.on('keypress' + ns, proxy(that._keypress, that));
}
} else if (disable) {
wrapper.removeAttr(TABINDEX);
dropDownWrapper.addClass(STATEDISABLED).removeClass(DEFAULT);
} else {
dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED);
wrapper.on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that));
}
element.attr(DISABLED, disable).attr(READONLY, readonly);
wrapper.attr(ARIA_DISABLED, disable).attr(ARIA_READONLY, readonly);
},
_keydown: function (e) {
var that = this;
var key = e.keyCode;
var altKey = e.altKey;
var isInputActive;
var handled;
var isPopupVisible = that.popup.visible();
if (that.filterInput) {
isInputActive = that.filterInput[0] === activeElement();
}
if (key === keys.LEFT) {
key = keys.UP;
handled = true;
} else if (key === keys.RIGHT) {
key = keys.DOWN;
handled = true;
}
if (handled && isInputActive) {
return;
}
e.keyCode = key;
if (altKey && key === keys.UP || key === keys.ESC) {
that._focusElement(that.wrapper);
}
if (key === keys.ENTER && that._typingTimeout && that.filterInput && isPopupVisible) {
e.preventDefault();
return;
}
handled = that._move(e);
if (handled) {
return;
}
if (!isPopupVisible || !that.filterInput) {
if (key === keys.HOME) {
handled = true;
that._firstItem();
} else if (key === keys.END) {
handled = true;
that._lastItem();
}
if (handled) {
that._select(that._focus());
e.preventDefault();
}
}
if (!altKey && !handled && that.filterInput) {
that._search();
}
},
_matchText: function (text, word) {
var ignoreCase = this.options.ignoreCase;
if (text === undefined || text === null) {
return false;
}
text = text + '';
if (ignoreCase) {
text = text.toLowerCase();
}
return text.indexOf(word) === 0;
},
_shuffleData: function (data, splitIndex) {
var optionDataItem = this._optionLabelDataItem();
if (optionDataItem) {
data = [optionDataItem].concat(data);
}
return data.slice(splitIndex).concat(data.slice(0, splitIndex));
},
_selectNext: function () {
var that = this;
var data = that.dataSource.flatView();
var dataLength = data.length + (that.hasOptionLabel() ? 1 : 0);
var isInLoop = sameCharsOnly(that._word, that._last);
var startIndex = that.selectedIndex;
var oldFocusedItem;
var text;
if (startIndex === -1) {
startIndex = 0;
} else {
startIndex += isInLoop ? 1 : 0;
startIndex = normalizeIndex(startIndex, dataLength);
}
data = data.toJSON ? data.toJSON() : data.slice();
data = that._shuffleData(data, startIndex);
for (var idx = 0; idx < dataLength; idx++) {
text = that._text(data[idx]);
if (isInLoop && that._matchText(text, that._last)) {
break;
} else if (that._matchText(text, that._word)) {
break;
}
}
if (idx !== dataLength) {
oldFocusedItem = that._focus();
that._select(normalizeIndex(startIndex + idx, dataLength));
if (that.trigger('select', { item: that._focus() })) {
that._select(oldFocusedItem);
}
if (!that.popup.visible()) {
that._change();
}
}
},
_keypress: function (e) {
var that = this;
if (e.which === 0 || e.keyCode === kendo.keys.ENTER) {
return;
}
var character = String.fromCharCode(e.charCode || e.keyCode);
if (that.options.ignoreCase) {
character = character.toLowerCase();
}
if (character === ' ') {
e.preventDefault();
}
that._word += character;
that._last = character;
that._search();
},
_popupOpen: function () {
var popup = this.popup;
popup.wrapper = kendo.wrap(popup.element);
if (popup.element.closest('.km-root')[0]) {
popup.wrapper.addClass('km-popup km-widget');
this.wrapper.addClass('km-widget');
}
},
_popup: function () {
Select.fn._popup.call(this);
this.popup.one('open', proxy(this._popupOpen, this));
},
_click: function (e) {
var item = e.item || $(e.currentTarget);
e.preventDefault();
if (this.trigger('select', { item: item })) {
this.close();
return;
}
this._userTriggered = true;
this._select(item);
this._focusElement(this.wrapper);
this._blur();
},
_focusElement: function (element) {
var active = activeElement();
var wrapper = this.wrapper;
var filterInput = this.filterInput;
var compareElement = element === filterInput ? wrapper : filterInput;
var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
if (filterInput && filterInput[0] === element[0] && touchEnabled) {
return;
}
if (filterInput && compareElement[0] === active) {
this._prevent = true;
this._focused = element.focus();
}
},
_filter: function (word) {
if (word) {
var that = this;
var ignoreCase = that.options.ignoreCase;
if (ignoreCase) {
word = word.toLowerCase();
}
that._select(function (dataItem) {
return that._matchText(that._text(dataItem), word);
});
}
},
_search: function () {
var that = this;
var dataSource = that.dataSource;
clearTimeout(that._typingTimeout);
if (that._isFilterEnabled()) {
that._typingTimeout = setTimeout(function () {
var value = that.filterInput.val();
if (that._prev !== value) {
that._prev = value;
that.search(value);
}
that._typingTimeout = null;
}, that.options.delay);
} else {
that._typingTimeout = setTimeout(function () {
that._word = '';
}, that.options.delay);
if (!that.listView.bound()) {
dataSource.fetch().done(function () {
that._selectNext();
});
return;
}
that._selectNext();
}
},
_get: function (candidate) {
var data, found, idx;
var isFunction = typeof candidate === 'function';
var jQueryCandidate = !isFunction ? $(candidate) : $();
if (this.hasOptionLabel()) {
if (typeof candidate === 'number') {
if (candidate > -1) {
candidate -= 1;
}
} else if (jQueryCandidate.hasClass('k-list-optionlabel')) {
candidate = -1;
}
}
if (isFunction) {
data = this.dataSource.flatView();
for (idx = 0; idx < data.length; idx++) {
if (candidate(data[idx])) {
candidate = idx;
found = true;
break;
}
}
if (!found) {
candidate = -1;
}
}
return candidate;
},
_firstItem: function () {
if (this.hasOptionLabel()) {
this._focus(this.optionLabel);
} else {
this.listView.focusFirst();
}
},
_lastItem: function () {
this._resetOptionLabel();
this.listView.focusLast();
},
_nextItem: function () {
if (this.optionLabel.hasClass('k-state-focused')) {
this._resetOptionLabel();
this.listView.focusFirst();
} else {
this.listView.focusNext();
}
},
_prevItem: function () {
if (this.optionLabel.hasClass('k-state-focused')) {
return;
}
this.listView.focusPrev();
if (!this.listView.focus()) {
this._focus(this.optionLabel);
}
},
_focusItem: function () {
var listView = this.listView;
var focusedItem = listView.focus();
var index = listView.select();
index = index[index.length - 1];
if (index === undefined && this.options.highlightFirst && !focusedItem) {
index = 0;
}
if (index !== undefined) {
listView.focus(index);
} else {
if (this.options.optionLabel) {
this._focus(this.optionLabel);
this._select(this.optionLabel);
} else {
listView.scrollToIndex(0);
}
}
},
_resetOptionLabel: function (additionalClass) {
this.optionLabel.removeClass('k-state-focused' + (additionalClass || '')).removeAttr('id');
},
_focus: function (candidate) {
var listView = this.listView;
var optionLabel = this.optionLabel;
if (candidate === undefined) {
candidate = listView.focus();
if (!candidate && optionLabel.hasClass('k-state-focused')) {
candidate = optionLabel;
}
return candidate;
}
this._resetOptionLabel();
candidate = this._get(candidate);
listView.focus(candidate);
if (candidate === -1) {
optionLabel.addClass('k-state-focused').attr('id', listView._optionID);
this._focused.add(this.filterInput).removeAttr('aria-activedescendant').attr('aria-activedescendant', listView._optionID);
}
},
_select: function (candidate, keepState) {
var that = this;
candidate = that._get(candidate);
that.listView.select(candidate);
if (!keepState && that._state === STATE_FILTER) {
that._state = STATE_ACCEPT;
}
if (candidate === -1) {
that._selectValue(null);
}
},
_selectValue: function (dataItem) {
var that = this;
var optionLabel = that.options.optionLabel;
var idx = that.listView.select();
var value = '';
var text = '';
idx = idx[idx.length - 1];
if (idx === undefined) {
idx = -1;
}
this._resetOptionLabel(' k-state-selected');
if (dataItem) {
text = dataItem;
value = that._dataValue(dataItem);
if (optionLabel) {
idx += 1;
}
} else if (optionLabel) {
that._focus(that.optionLabel.addClass('k-state-selected'));
text = that._optionLabelText();
if (typeof optionLabel === 'string') {
value = '';
} else {
value = that._value(optionLabel);
}
idx = 0;
}
that.selectedIndex = idx;
if (value === null) {
value = '';
}
that._textAccessor(text);
that._accessor(value, idx);
that._triggerCascade();
},
_mobile: function () {
var that = this, popup = that.popup, mobileOS = support.mobileOS, root = popup.element.parents('.km-root').eq(0);
if (root.length && mobileOS) {
popup.options.animation.open.effects = mobileOS.android || mobileOS.meego ? 'fadeIn' : mobileOS.ios || mobileOS.wp ? 'slideIn:up' : popup.options.animation.open.effects;
}
},
_filterHeader: function () {
var icon;
if (this.filterInput) {
this.filterInput.off(ns).parent().remove();
this.filterInput = null;
}
if (this._isFilterEnabled()) {
icon = '
select';
this.filterInput = $('
').attr({
placeholder: this.element.attr('placeholder'),
role: 'listbox',
'aria-haspopup': true,
'aria-expanded': false
});
this.list.prepend($('
').append(this.filterInput.add(icon)));
}
},
_span: function () {
var that = this, wrapper = that.wrapper, SELECTOR = 'span.k-input', span;
span = wrapper.find(SELECTOR);
if (!span[0]) {
wrapper.append('
select').append(that.element);
span = wrapper.find(SELECTOR);
}
that.span = span;
that._inputWrapper = $(wrapper[0].firstChild);
that._arrow = wrapper.find('.k-icon');
},
_wrapper: function () {
var that = this, element = that.element, DOMelement = element[0], wrapper;
wrapper = element.parent();
if (!wrapper.is('span.k-widget')) {
wrapper = element.wrap('
').parent();
wrapper[0].style.cssText = DOMelement.style.cssText;
wrapper[0].title = DOMelement.title;
}
element.hide();
that._focused = that.wrapper = wrapper.addClass('k-widget k-dropdown k-header').addClass(DOMelement.className).css('display', '').attr({
accesskey: element.attr('accesskey'),
unselectable: 'on',
role: 'listbox',
'aria-haspopup': true,
'aria-expanded': false
});
},
_clearSelection: function (parent) {
this.select(parent.value() ? 0 : -1);
},
_inputTemplate: function () {
var that = this, template = that.options.valueTemplate;
if (!template) {
template = $.proxy(kendo.template('#:this._text(data)#', { useWithBlock: false }), that);
} else {
template = kendo.template(template);
}
that.valueTemplate = template;
if (that.hasOptionLabel() && !that.options.optionLabelTemplate) {
try {
that.valueTemplate(that._optionLabelDataItem());
} catch (e) {
throw new Error(MSG_INVALID_OPTION_LABEL);
}
}
},
_textAccessor: function (text) {
var dataItem = null;
var template = this.valueTemplate;
var options = this.options;
var optionLabel = options.optionLabel;
var span = this.span;
if (text !== undefined) {
if ($.isPlainObject(text) || text instanceof ObservableObject) {
dataItem = text;
} else if (optionLabel && this._optionLabelText() === text) {
dataItem = optionLabel;
template = this.optionLabelTemplate;
}
if (!dataItem) {
dataItem = this._assignInstance(text, this._accessor());
}
var getElements = function () {
return {
elements: span.get(),
data: [{ dataItem: dataItem }]
};
};
this.angular('cleanup', getElements);
try {
span.html(template(dataItem));
} catch (e) {
span.html('');
}
this.angular('compile', getElements);
} else {
return span.text();
}
},
_preselect: function (value, text) {
if (!value && !text) {
text = this._optionLabelText();
}
this._accessor(value);
this._textAccessor(text);
this._old = this._accessor();
this._oldIndex = this.selectedIndex;
this.listView.setValue(value);
this._initialIndex = null;
this._presetValue = true;
},
_assignInstance: function (text, value) {
var dataTextField = this.options.dataTextField;
var dataItem = {};
if (dataTextField) {
assign(dataItem, dataTextField.split('.'), text);
assign(dataItem, this.options.dataValueField.split('.'), value);
dataItem = new ObservableObject(dataItem);
} else {
dataItem = text;
}
return dataItem;
}
});
function assign(instance, fields, value) {
var idx = 0, lastIndex = fields.length - 1, field;
for (; idx < lastIndex; ++idx) {
field = fields[idx];
if (!(field in instance)) {
instance[field] = {};
}
instance = instance[field];
}
instance[fields[lastIndex]] = value;
}
function normalizeIndex(index, length) {
if (index >= length) {
index -= length;
}
return index;
}
function sameCharsOnly(word, character) {
for (var idx = 0; idx < word.length; idx++) {
if (word.charAt(idx) !== character) {
return false;
}
}
return true;
}
ui.plugin(DropDownList);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('dataviz/diagram/dom', [
'kendo.data',
'kendo.draganddrop',
'kendo.toolbar',
'kendo.editable',
'kendo.window',
'kendo.dropdownlist',
'kendo.dataviz.core',
'kendo.dataviz.themes',
'dataviz/diagram/svg',
'dataviz/diagram/services',
'dataviz/diagram/layout'
], f);
}(function () {
(function ($, undefined) {
var dataviz = kendo.dataviz, draw = kendo.drawing, geom = kendo.geometry, diagram = dataviz.diagram, Widget = kendo.ui.Widget, Class = kendo.Class, proxy = $.proxy, deepExtend = kendo.deepExtend, extend = $.extend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, Canvas = diagram.Canvas, Group = diagram.Group, Rectangle = diagram.Rectangle, Circle = diagram.Circle, CompositeTransform = diagram.CompositeTransform, Rect = diagram.Rect, Path = diagram.Path, DeleteShapeUnit = diagram.DeleteShapeUnit, DeleteConnectionUnit = diagram.DeleteConnectionUnit, TextBlock = diagram.TextBlock, Image = diagram.Image, Point = diagram.Point, Intersect = diagram.Intersect, ConnectionEditAdorner = diagram.ConnectionEditAdorner, UndoRedoService = diagram.UndoRedoService, ToolService = diagram.ToolService, Selector = diagram.Selector, ResizingAdorner = diagram.ResizingAdorner, ConnectorsAdorner = diagram.ConnectorsAdorner, Cursors = diagram.Cursors, Utils = diagram.Utils, Observable = kendo.Observable, ToBackUnit = diagram.ToBackUnit, ToFrontUnit = diagram.ToFrontUnit, PolylineRouter = diagram.PolylineRouter, CascadingRouter = diagram.CascadingRouter, isUndefined = Utils.isUndefined, isDefined = Utils.isDefined, defined = kendo.util.defined, isArray = $.isArray, isFunction = kendo.isFunction, isString = Utils.isString, isPlainObject = $.isPlainObject, math = Math;
var NS = '.kendoDiagram', CASCADING = 'cascading', ITEMBOUNDSCHANGE = 'itemBoundsChange', CHANGE = 'change', CLICK = 'click', DRAG = 'drag', DRAG_END = 'dragEnd', DRAG_START = 'dragStart', MOUSE_ENTER = 'mouseEnter', MOUSE_LEAVE = 'mouseLeave', ERROR = 'error', AUTO = 'Auto', TOP = 'Top', RIGHT = 'Right', LEFT = 'Left', BOTTOM = 'Bottom', MAXINT = 9007199254740992, SELECT = 'select', ITEMROTATE = 'itemRotate', PAN = 'pan', ZOOM_START = 'zoomStart', ZOOM_END = 'zoomEnd', NONE = 'none', DEFAULT_CANVAS_WIDTH = 600, DEFAULT_CANVAS_HEIGHT = 600, DEFAULT_SHAPE_TYPE = 'rectangle', DEFAULT_SHAPE_WIDTH = 100, DEFAULT_SHAPE_HEIGHT = 100, DEFAULT_SHAPE_MINWIDTH = 20, DEFAULT_SHAPE_MINHEIGHT = 20, DEFAULT_SHAPE_POSITION = 0, DEFAULT_CONNECTION_BACKGROUND = 'Yellow', MAX_VALUE = Number.MAX_VALUE, MIN_VALUE = -Number.MAX_VALUE, ABSOLUTE = 'absolute', TRANSFORMED = 'transformed', ROTATED = 'rotated', TRANSPARENT = 'transparent', WIDTH = 'width', HEIGHT = 'height', X = 'x', Y = 'y', MOUSEWHEEL_NS = 'DOMMouseScroll' + NS + ' mousewheel' + NS, MOBILE_ZOOM_RATE = 0.05, MOBILE_PAN_DISTANCE = 5, BUTTON_TEMPLATE = '
#=text#', CONNECTION_CONTENT_OFFSET = 5;
diagram.DefaultConnectors = [
{ name: TOP },
{ name: BOTTOM },
{ name: LEFT },
{ name: RIGHT },
{
name: AUTO,
position: function (shape) {
return shape.getPosition('center');
}
}
];
var defaultButtons = {
cancel: {
text: 'Cancel',
imageClass: 'k-cancel',
className: 'k-diagram-cancel',
iconClass: 'k-icon'
},
update: {
text: 'Update',
imageClass: 'k-update',
className: 'k-diagram-update',
iconClass: 'k-icon'
}
};
diagram.shapeDefaults = function (extra) {
var defaults = {
type: DEFAULT_SHAPE_TYPE,
path: '',
autoSize: true,
visual: null,
x: DEFAULT_SHAPE_POSITION,
y: DEFAULT_SHAPE_POSITION,
minWidth: DEFAULT_SHAPE_MINWIDTH,
minHeight: DEFAULT_SHAPE_MINHEIGHT,
width: DEFAULT_SHAPE_WIDTH,
height: DEFAULT_SHAPE_HEIGHT,
hover: {},
editable: {
connect: true,
tools: []
},
connectors: diagram.DefaultConnectors,
rotation: { angle: 0 }
};
Utils.simpleExtend(defaults, extra);
return defaults;
};
function mwDelta(e) {
var origEvent = e.originalEvent, delta = 0;
if (origEvent.wheelDelta) {
delta = -origEvent.wheelDelta / 40;
delta = delta > 0 ? math.ceil(delta) : math.floor(delta);
} else if (origEvent.detail) {
delta = origEvent.detail;
}
return delta;
}
function isAutoConnector(connector) {
return connector.options.name.toLowerCase() === AUTO.toLowerCase();
}
function closestConnector(point, shape) {
var minimumDistance = MAXINT, resCtr, ctrs = shape.connectors;
for (var i = 0; i < ctrs.length; i++) {
var ctr = ctrs[i];
if (!isAutoConnector(ctr)) {
var dist = point.distanceTo(ctr.position());
if (dist < minimumDistance) {
minimumDistance = dist;
resCtr = ctr;
}
}
}
return resCtr;
}
function indicesOfItems(group, visuals) {
var i, indices = [], visual;
var children = group.drawingContainer().children;
var length = children.length;
for (i = 0; i < visuals.length; i++) {
visual = visuals[i];
for (var j = 0; j < length; j++) {
if (children[j] == visual.drawingContainer()) {
indices.push(j);
break;
}
}
}
return indices;
}
var DiagramElement = Observable.extend({
init: function (options) {
var that = this;
that.dataItem = (options || {}).dataItem;
Observable.fn.init.call(that);
that.options = deepExtend({ id: diagram.randomId() }, that.options, options);
that.isSelected = false;
that.visual = new Group({
id: that.options.id,
autoSize: that.options.autoSize
});
that.id = that.options.id;
that._template();
},
options: {
hover: {},
cursor: Cursors.grip,
content: { align: 'center middle' },
selectable: true,
serializable: true,
enable: true
},
_getCursor: function (point) {
if (this.adorner) {
return this.adorner._getCursor(point);
}
return this.options.cursor;
},
visible: function (value) {
if (isUndefined(value)) {
return this.visual.visible();
} else {
this.visual.visible(value);
}
},
bounds: function () {
},
refresh: function () {
this.visual.redraw();
},
position: function (point) {
this.options.x = point.x;
this.options.y = point.y;
this.visual.position(point);
},
toString: function () {
return this.options.id;
},
serialize: function () {
var json = deepExtend({}, { options: this.options });
if (this.dataItem) {
json.dataItem = this.dataItem.toString();
}
return json;
},
_content: function (content) {
if (content !== undefined) {
var options = this.options;
if (diagram.Utils.isString(content)) {
options.content.text = content;
} else {
deepExtend(options.content, content);
}
var contentOptions = options.content;
var contentVisual = this._contentVisual;
if (!contentVisual) {
this._createContentVisual(contentOptions);
} else {
this._updateContentVisual(contentOptions);
}
}
return this.options.content.text;
},
_createContentVisual: function (options) {
if (options.text) {
this._contentVisual = new TextBlock(options);
this._contentVisual._includeInBBox = false;
this.visual.append(this._contentVisual);
}
},
_updateContentVisual: function (options) {
this._contentVisual.redraw(options);
},
_hitTest: function (point) {
var bounds = this.bounds();
return this.visible() && bounds.contains(point) && this.options.enable;
},
_template: function () {
var that = this;
if (that.options.content.template) {
var data = that.dataItem || {}, elementTemplate = kendo.template(that.options.content.template, { paramName: 'dataItem' });
that.options.content.text = elementTemplate(data);
}
},
_canSelect: function () {
return this.options.selectable !== false;
},
toJSON: function () {
return { id: this.options.id };
}
});
var Connector = Class.extend({
init: function (shape, options) {
this.options = deepExtend({}, this.options, options);
this.connections = [];
this.shape = shape;
},
options: {
width: 7,
height: 7,
fill: { color: DEFAULT_CONNECTION_BACKGROUND },
hover: {}
},
position: function () {
if (this.options.position) {
return this.options.position(this.shape);
} else {
return this.shape.getPosition(this.options.name);
}
},
toJSON: function () {
return {
shapeId: this.shape.toString(),
connector: this.options.name
};
}
});
Connector.parse = function (diagram, str) {
var tempStr = str.split(':'), id = tempStr[0], name = tempStr[1] || AUTO;
for (var i = 0; i < diagram.shapes.length; i++) {
var shape = diagram.shapes[i];
if (shape.options.id == id) {
return shape.getConnector(name.trim());
}
}
};
var Shape = DiagramElement.extend({
init: function (options, diagram) {
var that = this;
DiagramElement.fn.init.call(that, options);
this.diagram = diagram;
this.updateOptionsFromModel();
options = that.options;
that.connectors = [];
that.type = options.type;
that.createShapeVisual();
that.updateBounds();
that.content(that.content());
that._createConnectors();
},
options: diagram.shapeDefaults(),
_setOptionsFromModel: function (model) {
var modelOptions = filterShapeDataItem(model || this.dataItem);
this.options = deepExtend({}, this.options, modelOptions);
this.redrawVisual();
if (this.options.content) {
this._template();
this.content(this.options.content);
}
},
updateOptionsFromModel: function (model, field) {
if (this.diagram && this.diagram._isEditable) {
var modelOptions = filterShapeDataItem(model || this.dataItem);
if (model && field) {
if (!dataviz.inArray(field, [
'x',
'y',
'width',
'height'
])) {
if (this.options.visual) {
this.redrawVisual();
} else if (modelOptions.type) {
this.options = deepExtend({}, this.options, modelOptions);
this.redrawVisual();
}
if (this.options.content) {
this._template();
this.content(this.options.content);
}
} else {
var bounds = this.bounds();
bounds[field] = model[field];
this.bounds(bounds);
}
} else {
this.options = deepExtend({}, this.options, modelOptions);
}
}
},
redrawVisual: function () {
this.visual.clear();
this._contentVisual = null;
this.options.dataItem = this.dataItem;
this.createShapeVisual();
this.updateBounds();
},
updateModel: function (syncChanges) {
var diagram = this.diagram;
if (diagram && diagram._isEditable) {
var bounds = this._bounds;
var model = this.dataItem;
if (model) {
diagram._suspendModelRefresh();
if (defined(model.x) && bounds.x !== model.x) {
model.set('x', bounds.x);
}
if (defined(model.y) && bounds.y !== model.y) {
model.set('y', bounds.y);
}
if (defined(model.width) && bounds.width !== model.width) {
model.set('width', bounds.width);
}
if (defined(model.height) && bounds.height !== model.height) {
model.set('height', bounds.height);
}
this.dataItem = model;
diagram._resumeModelRefresh();
if (syncChanges) {
diagram._syncShapeChanges();
}
}
}
},
updateBounds: function () {
var bounds = this.visual._measure(true);
var options = this.options;
this.bounds(new Rect(options.x, options.y, bounds.width, bounds.height));
this._rotate();
this._alignContent();
},
content: function (content) {
var result = this._content(content);
this._alignContent();
return result;
},
_alignContent: function () {
var contentOptions = this.options.content || {};
var contentVisual = this._contentVisual;
if (contentVisual && contentOptions.align) {
var containerRect = this.visual._measure();
var aligner = new diagram.RectAlign(containerRect);
var contentBounds = contentVisual.drawingElement.bbox(null);
var contentRect = new Rect(0, 0, contentBounds.width(), contentBounds.height());
var alignedBounds = aligner.align(contentRect, contentOptions.align);
contentVisual.position(alignedBounds.topLeft());
}
},
_createConnectors: function () {
var options = this.options, length = options.connectors.length, connectorDefaults = options.connectorDefaults, connector, i;
for (i = 0; i < length; i++) {
connector = new Connector(this, deepExtend({}, connectorDefaults, options.connectors[i]));
this.connectors.push(connector);
}
},
bounds: function (value) {
var bounds;
if (value) {
if (isString(value)) {
switch (value) {
case TRANSFORMED:
bounds = this._transformedBounds();
break;
case ABSOLUTE:
bounds = this._transformedBounds();
var pan = this.diagram._pan;
bounds.x += pan.x;
bounds.y += pan.y;
break;
case ROTATED:
bounds = this._rotatedBounds();
break;
default:
bounds = this._bounds;
}
} else {
this._setBounds(value);
this._triggerBoundsChange();
if (!(this.diagram && this.diagram._layouting)) {
this.refreshConnections();
}
}
} else {
bounds = this._bounds;
}
return bounds;
},
_setBounds: function (rect) {
var options = this.options;
var topLeft = rect.topLeft();
var x = options.x = topLeft.x;
var y = options.y = topLeft.y;
var width = options.width = math.max(rect.width, options.minWidth);
var height = options.height = math.max(rect.height, options.minHeight);
this._bounds = new Rect(x, y, width, height);
this.visual.redraw({
x: x,
y: y,
width: width,
height: height
});
},
position: function (point) {
if (point) {
this.bounds(new Rect(point.x, point.y, this._bounds.width, this._bounds.height));
} else {
return this._bounds.topLeft();
}
},
clone: function () {
var json = this.serialize();
json.options.id = diagram.randomId();
if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
json.options.dataItem = cloneDataItem(this.dataItem);
}
return new Shape(json.options);
},
select: function (value) {
var diagram = this.diagram, selected, deselected;
if (isUndefined(value)) {
value = true;
}
if (this._canSelect()) {
if (this.isSelected != value) {
selected = [];
deselected = [];
this.isSelected = value;
if (this.isSelected) {
diagram._selectedItems.push(this);
selected.push(this);
} else {
Utils.remove(diagram._selectedItems, this);
deselected.push(this);
}
if (!diagram._internalSelection) {
diagram._selectionChanged(selected, deselected);
}
return true;
}
}
},
rotate: function (angle, center, undoable) {
var rotate = this.visual.rotate();
if (angle !== undefined) {
if (undoable !== false && this.diagram && this.diagram.undoRedoService && angle !== rotate.angle) {
this.diagram.undoRedoService.add(new diagram.RotateUnit(this.diagram._resizingAdorner, [this], [rotate.angle]), false);
}
var b = this.bounds(), sc = new Point(b.width / 2, b.height / 2), deltaAngle, newPosition;
if (center) {
deltaAngle = angle - rotate.angle;
newPosition = b.center().rotate(center, 360 - deltaAngle).minus(sc);
this._rotationOffset = this._rotationOffset.plus(newPosition.minus(b.topLeft()));
this.position(newPosition);
}
this.visual.rotate(angle, sc);
this.options.rotation.angle = angle;
if (this.diagram && this.diagram._connectorsAdorner) {
this.diagram._connectorsAdorner.refresh();
}
this.refreshConnections();
if (this.diagram) {
this.diagram.trigger(ITEMROTATE, { item: this });
}
}
return rotate;
},
connections: function (type) {
var result = [], i, j, con, cons, ctr;
for (i = 0; i < this.connectors.length; i++) {
ctr = this.connectors[i];
cons = ctr.connections;
for (j = 0, cons; j < cons.length; j++) {
con = cons[j];
if (type == 'out') {
var source = con.source();
if (source.shape && source.shape == this) {
result.push(con);
}
} else if (type == 'in') {
var target = con.target();
if (target.shape && target.shape == this) {
result.push(con);
}
} else {
result.push(con);
}
}
}
return result;
},
refreshConnections: function () {
$.each(this.connections(), function () {
this.refresh();
});
},
getConnector: function (nameOrPoint) {
var i, ctr;
if (isString(nameOrPoint)) {
nameOrPoint = nameOrPoint.toLocaleLowerCase();
for (i = 0; i < this.connectors.length; i++) {
ctr = this.connectors[i];
if (ctr.options.name.toLocaleLowerCase() == nameOrPoint) {
return ctr;
}
}
} else if (nameOrPoint instanceof Point) {
return closestConnector(nameOrPoint, this);
} else {
return this.connectors.length ? this.connectors[0] : null;
}
},
getPosition: function (side) {
var b = this.bounds(), fnName = side.charAt(0).toLowerCase() + side.slice(1);
if (isFunction(b[fnName])) {
return this._transformPoint(b[fnName]());
}
return b.center();
},
redraw: function (options) {
if (options) {
var shapeOptions = this.options;
var boundsChange;
this.shapeVisual.redraw(this._visualOptions(options));
if (this._diffNumericOptions(options, [
WIDTH,
HEIGHT,
X,
Y
])) {
this.bounds(new Rect(shapeOptions.x, shapeOptions.y, shapeOptions.width, shapeOptions.height));
boundsChange = true;
}
if (options.connectors) {
shapeOptions.connectors = options.connectors;
this._updateConnectors();
}
shapeOptions = deepExtend(shapeOptions, options);
if (options.rotation || boundsChange) {
this._rotate();
}
if (shapeOptions.content) {
this.content(shapeOptions.content);
}
}
},
_updateConnectors: function () {
var connections = this.connections();
this.connectors = [];
this._createConnectors();
var connection;
var source;
var target;
for (var idx = 0; idx < connections.length; idx++) {
connection = connections[idx];
source = connection.source();
target = connection.target();
if (source.shape && source.shape === this) {
connection.source(this.getConnector(source.options.name) || null);
} else if (target.shape && target.shape === this) {
connection.target(this.getConnector(target.options.name) || null);
}
connection.updateModel();
}
},
_diffNumericOptions: diagram.diffNumericOptions,
_visualOptions: function (options) {
return {
data: options.path,
source: options.source,
hover: options.hover,
fill: options.fill,
stroke: options.stroke
};
},
_triggerBoundsChange: function () {
if (this.diagram) {
this.diagram.trigger(ITEMBOUNDSCHANGE, {
item: this,
bounds: this._bounds.clone()
});
}
},
_transformPoint: function (point) {
var rotate = this.rotate(), bounds = this.bounds(), tl = bounds.topLeft();
if (rotate.angle) {
point.rotate(rotate.center().plus(tl), 360 - rotate.angle);
}
return point;
},
_transformedBounds: function () {
var bounds = this.bounds(), tl = bounds.topLeft(), br = bounds.bottomRight();
return Rect.fromPoints(this.diagram.modelToView(tl), this.diagram.modelToView(br));
},
_rotatedBounds: function () {
var bounds = this.bounds().rotatedBounds(this.rotate().angle), tl = bounds.topLeft(), br = bounds.bottomRight();
return Rect.fromPoints(tl, br);
},
_rotate: function () {
var rotation = this.options.rotation;
if (rotation && rotation.angle) {
this.rotate(rotation.angle);
}
this._rotationOffset = new Point();
},
_hover: function (value) {
var options = this.options, hover = options.hover, stroke = options.stroke, fill = options.fill;
if (value && isDefined(hover.stroke)) {
stroke = deepExtend({}, stroke, hover.stroke);
}
if (value && isDefined(hover.fill)) {
fill = hover.fill;
}
this.shapeVisual.redraw({
stroke: stroke,
fill: fill
});
if (options.editable && options.editable.connect) {
this.diagram._showConnectors(this, value);
}
},
_hitTest: function (value) {
if (this.visible()) {
var bounds = this.bounds(), rotatedPoint, angle = this.rotate().angle;
if (value.isEmpty && !value.isEmpty()) {
return Intersect.rects(value, bounds, angle ? angle : 0);
} else {
rotatedPoint = value.clone().rotate(bounds.center(), angle);
if (bounds.contains(rotatedPoint)) {
return this;
}
}
}
},
toJSON: function () {
return { shapeId: this.options.id };
},
createShapeVisual: function () {
var options = this.options;
var visualOptions = this._visualOptions(options);
var visualTemplate = options.visual;
var type = (options.type + '').toLocaleLowerCase();
var shapeVisual;
visualOptions.width = options.width;
visualOptions.height = options.height;
if (isFunction(visualTemplate)) {
shapeVisual = visualTemplate.call(this, options);
} else if (visualOptions.data) {
shapeVisual = new Path(visualOptions);
translateToOrigin(shapeVisual);
} else if (type == 'rectangle') {
shapeVisual = new Rectangle(visualOptions);
} else if (type == 'circle') {
shapeVisual = new Circle(visualOptions);
} else if (type == 'text') {
shapeVisual = new TextBlock(visualOptions);
} else if (type == 'image') {
shapeVisual = new Image(visualOptions);
} else {
shapeVisual = new Path(visualOptions);
}
this.shapeVisual = shapeVisual;
this.visual.append(this.shapeVisual);
}
});
var Connection = DiagramElement.extend({
init: function (from, to, options) {
var that = this;
DiagramElement.fn.init.call(that, options);
this.updateOptionsFromModel();
this._initRouter();
that.path = new diagram.Polyline(that.options);
that.path.fill(TRANSPARENT);
that.visual.append(that.path);
that._sourcePoint = that._targetPoint = new Point();
that._setSource(from);
that._setTarget(to);
that.content(that.options.content);
that.definers = [];
if (defined(options) && options.points) {
that.points(options.points);
}
},
options: {
hover: { stroke: {} },
startCap: NONE,
endCap: NONE,
points: [],
selectable: true,
fromConnector: AUTO,
toConenctor: AUTO
},
_setOptionsFromModel: function (model) {
this.updateOptionsFromModel(model || this.dataItem);
},
updateOptionsFromModel: function (model) {
if (this.diagram && this.diagram._isEditable) {
var dataMap = this.diagram._dataMap;
var options = filterConnectionDataItem(model || this.dataItem);
if (model) {
if (defined(options.from)) {
var from = dataMap[options.from];
if (from && defined(options.fromConnector)) {
from = from.getConnector(options.fromConnector);
}
this.source(from);
} else if (defined(options.fromX) && defined(options.fromY)) {
this.source(new Point(options.fromX, options.fromY));
}
if (defined(options.to)) {
var to = dataMap[options.to];
if (to && defined(options.toConnector)) {
to = to.getConnector(options.toConnector);
}
this.target(to);
} else if (defined(options.toX) && defined(options.toY)) {
this.target(new Point(options.toX, options.toY));
}
if (defined(options.type) && this.type() !== options.type) {
this.points([]);
this.type(options.type);
}
this.dataItem = model;
this._template();
this.redraw(this.options);
} else {
this.options = deepExtend({}, options, this.options);
}
}
},
updateModel: function (syncChanges) {
if (this.diagram && this.diagram._isEditable) {
if (this.diagram.connectionsDataSource) {
var model = this.diagram.connectionsDataSource.getByUid(this.dataItem.uid);
if (model) {
this.diagram._suspendModelRefresh();
if (defined(this.options.fromX) && this.options.fromX !== null) {
clearField('from', model);
clearField('fromConnector', model);
model.set('fromX', this.options.fromX);
model.set('fromY', this.options.fromY);
} else {
model.set('from', this.options.from);
if (defined(model.fromConnector)) {
model.set('fromConnector', this.sourceConnector ? this.sourceConnector.options.name : null);
}
clearField('fromX', model);
clearField('fromY', model);
}
if (defined(this.options.toX) && this.options.toX !== null) {
clearField('to', model);
clearField('toConnector', model);
model.set('toX', this.options.toX);
model.set('toY', this.options.toY);
} else {
model.set('to', this.options.to);
if (defined(model.toConnector)) {
model.set('toConnector', this.targetConnector ? this.targetConnector.options.name : null);
}
clearField('toX', model);
clearField('toY', model);
}
if (defined(this.options.type) && defined(model.type)) {
model.set('type', this.options.type);
}
this.dataItem = model;
this.diagram._resumeModelRefresh();
if (syncChanges) {
this.diagram._syncConnectionChanges();
}
}
}
}
},
sourcePoint: function () {
return this._resolvedSourceConnector ? this._resolvedSourceConnector.position() : this._sourcePoint;
},
_setSource: function (source) {
var shapeSource = source instanceof Shape;
var defaultConnector = this.options.fromConnector || AUTO;
var dataItem;
if (shapeSource && !source.getConnector(defaultConnector)) {
return;
}
if (source !== undefined) {
this.from = source;
}
this._removeFromSourceConnector();
if (source === null) {
if (this.sourceConnector) {
this._sourcePoint = (this._resolvedSourceConnector || this.sourceConnector).position();
this._clearSourceConnector();
this._setFromOptions(null, this._sourcePoint);
}
} else if (source instanceof Connector) {
dataItem = source.shape.dataItem;
if (dataItem) {
this._setFromOptions(dataItem.id);
}
this.sourceConnector = source;
this.sourceConnector.connections.push(this);
} else if (source instanceof Point) {
this._setFromOptions(null, source);
this._sourcePoint = source;
if (this.sourceConnector) {
this._clearSourceConnector();
}
} else if (shapeSource) {
dataItem = source.dataItem;
if (dataItem) {
this._setFromOptions(dataItem.id);
}
this.sourceConnector = source.getConnector(defaultConnector);
this.sourceConnector.connections.push(this);
}
},
source: function (source, undoable) {
if (isDefined(source)) {
if (undoable && this.diagram) {
this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, source));
}
this._setSource(source);
this.refresh();
}
return this.sourceConnector ? this.sourceConnector : this._sourcePoint;
},
_setFromOptions: function (from, fromPoint) {
this.options.from = from;
if (fromPoint) {
this.options.fromX = fromPoint.x;
this.options.fromY = fromPoint.y;
} else {
this.options.fromX = null;
this.options.fromY = null;
}
},
sourceDefiner: function (value) {
if (value) {
if (value instanceof diagram.PathDefiner) {
value.left = null;
this._sourceDefiner = value;
this.source(value.point);
} else {
throw 'The sourceDefiner needs to be a PathDefiner.';
}
} else {
if (!this._sourceDefiner) {
this._sourceDefiner = new diagram.PathDefiner(this.sourcePoint(), null, null);
}
return this._sourceDefiner;
}
},
targetPoint: function () {
return this._resolvedTargetConnector ? this._resolvedTargetConnector.position() : this._targetPoint;
},
_setTarget: function (target) {
var shapeTarget = target instanceof Shape;
var defaultConnector = this.options.toConnector || AUTO;
var dataItem;
if (shapeTarget && !target.getConnector(defaultConnector)) {
return;
}
if (target !== undefined) {
this.to = target;
}
this._removeFromTargetConnector();
if (target === null) {
if (this.targetConnector) {
this._targetPoint = (this._resolvedTargetConnector || this.targetConnector).position();
this._clearTargetConnector();
this._setToOptions(null, this._targetPoint);
}
} else if (target instanceof Connector) {
dataItem = target.shape.dataItem;
if (dataItem) {
this._setToOptions(dataItem.id);
}
this.targetConnector = target;
this.targetConnector.connections.push(this);
} else if (target instanceof Point) {
this._setToOptions(null, target);
this._targetPoint = target;
if (this.targetConnector) {
this._clearTargetConnector();
}
} else if (shapeTarget) {
dataItem = target.dataItem;
if (dataItem) {
this._setToOptions(dataItem.id);
}
this.targetConnector = target.getConnector(defaultConnector);
this.targetConnector.connections.push(this);
}
},
target: function (target, undoable) {
if (isDefined(target)) {
if (undoable && this.diagram) {
this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, undefined, target));
}
this._setTarget(target);
this.refresh();
}
return this.targetConnector ? this.targetConnector : this._targetPoint;
},
_setToOptions: function (to, toPoint) {
this.options.to = to;
if (toPoint) {
this.options.toX = toPoint.x;
this.options.toY = toPoint.y;
} else {
this.options.toX = null;
this.options.toY = null;
}
},
targetDefiner: function (value) {
if (value) {
if (value instanceof diagram.PathDefiner) {
value.right = null;
this._targetDefiner = value;
this.target(value.point);
} else {
throw 'The sourceDefiner needs to be a PathDefiner.';
}
} else {
if (!this._targetDefiner) {
this._targetDefiner = new diagram.PathDefiner(this.targetPoint(), null, null);
}
return this._targetDefiner;
}
},
_updateConnectors: function () {
this._updateConnector(this.source(), 'source');
this._updateConnector(this.target(), 'target');
},
_updateConnector: function (instance, name) {
var that = this;
var diagram = that.diagram;
if (instance instanceof Connector && !diagram.getShapeById(instance.shape.id)) {
var dataItem = instance.shape.dataItem;
var connectorName = instance.options.name;
var setNewTarget = function () {
var shape = diagram._dataMap[dataItem.id];
instance = shape.getConnector(connectorName);
that[name](instance, false);
that.updateModel();
};
if (diagram._dataMap[dataItem.id]) {
setNewTarget();
} else {
var inactiveItem = diagram._inactiveShapeItems.getByUid(dataItem.uid);
if (inactiveItem) {
diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(setNewTarget));
}
}
} else {
that[name](instance, false);
}
},
content: function (content) {
var result = this._content(content);
if (defined(content)) {
this._alignContent();
}
return result;
},
_createContentVisual: function (options) {
var visual;
if (isFunction(options.visual)) {
visual = options.visual.call(this, options);
} else if (options.text) {
visual = new TextBlock(options);
}
if (visual) {
this._contentVisual = visual;
visual._includeInBBox = false;
this.visual.append(visual);
}
return visual;
},
_updateContentVisual: function (options) {
if (isFunction(options.visual)) {
this.visual.remove(this._contentVisual);
this._createContentVisual(options);
} else {
this._contentVisual.redraw(options);
}
},
_alignContent: function () {
if (this._contentVisual) {
var offset = CONNECTION_CONTENT_OFFSET;
var points = this.allPoints();
var endIdx = math.floor(points.length / 2);
var startIdx = endIdx - 1;
while (startIdx > 0 && points[startIdx].equals(points[endIdx])) {
startIdx--;
endIdx++;
}
var endPoint = points[endIdx];
var startPoint = points[startIdx];
var boundingBox = this._contentVisual._measure();
var width = boundingBox.width;
var height = boundingBox.height;
var alignToPath = points.length % 2 === 0;
var distance = startPoint.distanceTo(endPoint);
if (alignToPath && points.length > 2 && distance > 0 && (startPoint.y === endPoint.y && distance < width || startPoint.x === endPoint.x && distance < height)) {
alignToPath = false;
offset = 0;
}
var point;
if (alignToPath) {
var angle = kendo.util.deg(math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x));
point = new Point((endPoint.x - startPoint.x) / 2 + startPoint.x, (endPoint.y - startPoint.y) / 2 + startPoint.y);
if (math.abs(angle) === 90) {
point.x += offset;
point.y -= height / 2;
} else if (angle % 180 === 0) {
point.x -= width / 2;
point.y -= height + offset;
} else if (angle < -90 || 0 < angle && angle < 90) {
point.y -= height;
} else if (angle < 0 || angle > 90) {
point.x -= width;
point.y -= height;
}
} else {
var midIdx = math.floor(points.length / 2);
point = points[midIdx].clone();
startPoint = points[midIdx - 1];
endPoint = points[midIdx + 1];
var offsetX = startPoint.x <= point.x && endPoint.x <= point.x ? offset : -boundingBox.width - offset;
var offsetY = startPoint.y <= point.y && endPoint.y <= point.y ? offset : -boundingBox.height - offset;
point.x += offsetX;
point.y += offsetY;
}
this._contentVisual.position(point);
}
},
select: function (value) {
var diagram = this.diagram, selected, deselected;
if (this._canSelect()) {
if (this.isSelected !== value) {
this.isSelected = value;
selected = [];
deselected = [];
if (this.isSelected) {
this.adorner = new ConnectionEditAdorner(this, this.options.selection);
diagram._adorn(this.adorner, true);
diagram._selectedItems.push(this);
selected.push(this);
} else {
if (this.adorner) {
diagram._adorn(this.adorner, false);
Utils.remove(diagram._selectedItems, this);
this.adorner = undefined;
deselected.push(this);
}
}
if (this.adorner) {
this.adorner.refresh();
}
if (!diagram._internalSelection) {
diagram._selectionChanged(selected, deselected);
}
return true;
}
}
},
bounds: function (value) {
if (value && !isString(value)) {
this._bounds = value;
} else {
return this._bounds;
}
},
type: function (value) {
var options = this.options;
if (value) {
if (value !== options.type) {
options.type = value;
this._initRouter();
this.refresh();
}
} else {
return options.type;
}
},
_initRouter: function () {
var type = (this.options.type || '').toLowerCase();
if (type == CASCADING) {
this._router = new CascadingRouter(this);
} else {
this._router = new PolylineRouter(this);
}
},
points: function (value) {
if (value) {
this.definers = [];
for (var i = 0; i < value.length; i++) {
var definition = value[i];
if (definition instanceof diagram.Point) {
this.definers.push(new diagram.PathDefiner(definition));
} else if (definition.hasOwnProperty('x') && definition.hasOwnProperty('y')) {
this.definers.push(new diagram.PathDefiner(new Point(definition.x, definition.y)));
} else {
throw 'A Connection point needs to be a Point or an object with x and y properties.';
}
}
} else {
var pts = [];
if (isDefined(this.definers)) {
for (var k = 0; k < this.definers.length; k++) {
pts.push(this.definers[k].point);
}
}
return pts;
}
},
allPoints: function () {
var pts = [this.sourcePoint()];
if (this.definers) {
for (var k = 0; k < this.definers.length; k++) {
pts.push(this.definers[k].point);
}
}
pts.push(this.targetPoint());
return pts;
},
refresh: function () {
this._resolveConnectors();
this._refreshPath();
this._alignContent();
if (this.adorner) {
this.adorner.refresh();
}
},
_resolveConnectors: function () {
var connection = this, sourcePoint, targetPoint, source = connection.source(), target = connection.target(), autoSourceShape, autoTargetShape;
if (source instanceof Point) {
sourcePoint = source;
} else if (source instanceof Connector) {
if (isAutoConnector(source)) {
autoSourceShape = source.shape;
} else {
connection._resolvedSourceConnector = source;
sourcePoint = source.position();
}
}
if (target instanceof Point) {
targetPoint = target;
} else if (target instanceof Connector) {
if (isAutoConnector(target)) {
autoTargetShape = target.shape;
} else {
connection._resolvedTargetConnector = target;
targetPoint = target.position();
}
}
if (sourcePoint) {
if (autoTargetShape) {
connection._resolvedTargetConnector = closestConnector(sourcePoint, autoTargetShape);
}
} else if (autoSourceShape) {
if (targetPoint) {
connection._resolvedSourceConnector = closestConnector(targetPoint, autoSourceShape);
} else if (autoTargetShape) {
this._resolveAutoConnectors(autoSourceShape, autoTargetShape);
}
}
},
_resolveAutoConnectors: function (autoSourceShape, autoTargetShape) {
var minNonConflict = MAXINT;
var minDist = MAXINT;
var sourceConnectors = autoSourceShape.connectors;
var targetConnectors;
var minNonConflictSource, minNonConflictTarget;
var sourcePoint, targetPoint;
var minSource, minTarget;
var sourceConnector, targetConnector;
var sourceIdx, targetIdx;
var dist;
for (sourceIdx = 0; sourceIdx < sourceConnectors.length; sourceIdx++) {
sourceConnector = sourceConnectors[sourceIdx];
if (!isAutoConnector(sourceConnector)) {
sourcePoint = sourceConnector.position();
targetConnectors = autoTargetShape.connectors;
for (targetIdx = 0; targetIdx < targetConnectors.length; targetIdx++) {
targetConnector = targetConnectors[targetIdx];
if (!isAutoConnector(targetConnector)) {
targetPoint = targetConnector.position();
dist = math.round(sourcePoint.distanceTo(targetPoint));
if (dist < minNonConflict && this.diagram && this._testRoutePoints(sourcePoint, targetPoint, sourceConnector, targetConnector)) {
minNonConflict = dist;
minNonConflictSource = sourceConnector;
minNonConflictTarget = targetConnector;
}
if (dist < minDist) {
minSource = sourceConnector;
minTarget = targetConnector;
minDist = dist;
}
}
}
}
}
if (minNonConflictSource) {
minSource = minNonConflictSource;
minTarget = minNonConflictTarget;
}
this._resolvedSourceConnector = minSource;
this._resolvedTargetConnector = minTarget;
},
_testRoutePoints: function (sourcePoint, targetPoint, sourceConnector, targetConnector) {
var router = this._router;
var passRoute = true;
if (router instanceof CascadingRouter) {
var points = router.routePoints(sourcePoint, targetPoint, sourceConnector, targetConnector), start, end, rect;
points.unshift(sourcePoint);
points.push(targetPoint);
for (var idx = 1; idx < points.length; idx++) {
start = points[idx - 1];
end = points[idx];
rect = new Rect(math.min(start.x, end.x), math.min(start.y, end.y), math.abs(start.x - end.x), math.abs(start.y - end.y));
if (rect.width > 0) {
rect.x++;
rect.width -= 2;
}
if (rect.height > 0) {
rect.y++;
rect.height -= 2;
}
if (!rect.isEmpty() && this.diagram._shapesQuadTree.hitTestRect(rect)) {
passRoute = false;
break;
}
}
}
return passRoute;
},
redraw: function (options) {
if (options) {
this.options = deepExtend({}, this.options, options);
var points = this.options.points;
if (defined(points) && points.length > 0) {
this.points(points);
this._refreshPath();
}
if (options && options.content || options.text) {
this.content(options.content);
}
this.path.redraw({
fill: options.fill,
stroke: options.stroke,
startCap: options.startCap,
endCap: options.endCap
});
}
},
clone: function () {
var json = this.serialize();
if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
json.options.dataItem = cloneDataItem(this.dataItem);
}
return new Connection(this.from, this.to, json.options);
},
serialize: function () {
var from = this.from.toJSON ? this.from.toJSON : this.from.toString(), to = this.to.toJSON ? this.to.toJSON : this.to.toString();
var json = deepExtend({}, {
options: this.options,
from: from,
to: to
});
if (defined(this.dataItem)) {
json.dataItem = this.dataItem.toString();
}
json.options.points = this.points();
return json;
},
_hitTest: function (value) {
if (this.visible()) {
var p = new Point(value.x, value.y), from = this.sourcePoint(), to = this.targetPoint();
if (value.isEmpty && !value.isEmpty() && value.contains(from) && value.contains(to)) {
return this;
}
if (this._router.hitTest(p)) {
return this;
}
}
},
_hover: function (value) {
var color = (this.options.stroke || {}).color;
if (value && isDefined(this.options.hover.stroke.color)) {
color = this.options.hover.stroke.color;
}
this.path.redraw({ stroke: { color: color } });
},
_refreshPath: function () {
if (!defined(this.path)) {
return;
}
this._drawPath();
this.bounds(this._router.getBounds());
},
_drawPath: function () {
if (this._router) {
this._router.route();
}
var source = this.sourcePoint();
var target = this.targetPoint();
var points = this.points();
this.path.redraw({ points: [source].concat(points, [target]) });
},
_clearSourceConnector: function () {
this.sourceConnector = undefined;
this._resolvedSourceConnector = undefined;
},
_clearTargetConnector: function () {
this.targetConnector = undefined;
this._resolvedTargetConnector = undefined;
},
_removeFromSourceConnector: function () {
if (this.sourceConnector) {
Utils.remove(this.sourceConnector.connections, this);
}
},
_removeFromTargetConnector: function () {
if (this.targetConnector) {
Utils.remove(this.targetConnector.connections, this);
}
},
toJSON: function () {
var connection = this;
var from, to, point;
if (connection.from && connection.from.toJSON) {
from = connection.from.toJSON();
} else {
point = connection._sourcePoint;
from = {
x: point.x,
y: point.y
};
}
if (connection.to && connection.to.toJSON) {
to = connection.to.toJSON();
} else {
point = connection._targetPoint;
to = {
x: point.x,
y: point.y
};
}
return {
from: from,
to: to
};
}
});
var Diagram = Widget.extend({
init: function (element, userOptions) {
var that = this;
kendo.destroy(element);
Widget.fn.init.call(that, element, userOptions);
that._initTheme();
that._initElements();
that._extendLayoutOptions(that.options);
that._initDefaults(userOptions);
that._initCanvas();
that.mainLayer = new Group({ id: 'main-layer' });
that.canvas.append(that.mainLayer);
that._shapesQuadTree = new ShapesQuadTree(that);
that._pan = new Point();
that._adorners = [];
that.adornerLayer = new Group({ id: 'adorner-layer' });
that.canvas.append(that.adornerLayer);
that._createHandlers();
that._initialize();
that._fetchFreshData();
that._createGlobalToolBar();
that._resizingAdorner = new ResizingAdorner(that, { editable: that.options.editable });
that._connectorsAdorner = new ConnectorsAdorner(that);
that._adorn(that._resizingAdorner, true);
that._adorn(that._connectorsAdorner, true);
that.selector = new Selector(that);
that._clipboard = [];
that.pauseMouseHandlers = false;
that._createOptionElements();
that.zoom(that.options.zoom);
that.canvas.draw();
},
options: {
name: 'Diagram',
theme: 'default',
layout: '',
zoomRate: 0.1,
zoom: 1,
zoomMin: 0,
zoomMax: 2,
dataSource: {},
draggable: true,
template: '',
autoBind: true,
editable: {
rotate: {},
resize: {},
text: true,
tools: [],
drag: {
snap: {
size: 10,
angle: 10
}
},
remove: true
},
pannable: { key: 'ctrl' },
selectable: { key: 'none' },
tooltip: {
enabled: true,
format: '{0}'
},
copy: {
enabled: true,
offsetX: 20,
offsetY: 20
},
shapeDefaults: diagram.shapeDefaults({ undoable: true }),
connectionDefaults: {
editable: { tools: [] },
type: CASCADING
},
shapes: [],
connections: []
},
events: [
ZOOM_END,
ZOOM_START,
PAN,
SELECT,
ITEMROTATE,
ITEMBOUNDSCHANGE,
CHANGE,
CLICK,
MOUSE_ENTER,
MOUSE_LEAVE,
'toolBarClick',
'save',
'cancel',
'edit',
'remove',
'add',
'dataBound',
DRAG_START,
DRAG,
DRAG_END
],
items: function () {
return $();
},
_createGlobalToolBar: function () {
var editable = this.options.editable;
if (editable) {
var tools = editable.tools;
if (this._isEditable && tools !== false && (!tools || tools.length === 0)) {
tools = [
'createShape',
'undo',
'redo',
'rotateClockwise',
'rotateAnticlockwise'
];
}
if (tools && tools.length) {
this.toolBar = new DiagramToolBar(this, {
tools: tools || {},
click: proxy(this._toolBarClick, this),
modal: false
});
this.toolBar.element.css({ textAlign: 'left' });
this.element.prepend(this.toolBar.element);
this._resize();
}
}
},
createShape: function () {
if (this.editor && this.editor.end() || !this.editor) {
var dataSource = this.dataSource;
var view = dataSource.view() || [];
var index = view.length;
var model = createModel(dataSource, {});
var shape = this._createShape(model, {});
if (!this.trigger('add', { shape: shape })) {
dataSource.insert(index, model);
var inactiveItem = this._inactiveShapeItems.getByUid(model.uid);
inactiveItem.element = shape;
this.edit(shape);
}
}
},
_createShape: function (dataItem, options) {
options = deepExtend({}, this.options.shapeDefaults, options);
options.dataItem = dataItem;
var shape = new Shape(options, this);
return shape;
},
createConnection: function () {
if (this.editor && this.editor.end() || !this.editor) {
var connectionsDataSource = this.connectionsDataSource;
var view = connectionsDataSource.view() || [];
var index = view.length;
var model = createModel(connectionsDataSource, {});
var connection = this._createConnection(model);
if (!this.trigger('add', { connection: connection })) {
this._connectionsDataMap[model.uid] = connection;
connectionsDataSource.insert(index, model);
this.addConnection(connection, false);
this.edit(connection);
}
}
},
_createConnection: function (dataItem, source, target) {
var options = deepExtend({}, this.options.connectionDefaults);
options.dataItem = dataItem;
var connection = new Connection(source || new Point(), target || new Point(), options);
return connection;
},
editModel: function (dataItem, editorType) {
this.cancelEdit();
var editors, template;
var editable = this.options.editable;
if (editorType == 'shape') {
editors = editable.shapeEditors;
template = editable.shapeTemplate;
} else if (editorType == 'connection') {
var connectionSelectorHandler = proxy(connectionSelector, this);
editors = deepExtend({}, {
from: connectionSelectorHandler,
to: connectionSelectorHandler
}, editable.connectionEditors);
template = editable.connectionTemplate;
} else {
return;
}
this.editor = new PopupEditor(this.element, {
update: proxy(this._update, this),
cancel: proxy(this._cancel, this),
model: dataItem,
type: editorType,
target: this,
editors: editors,
template: template
});
this.trigger('edit', this._editArgs());
},
edit: function (item) {
if (item.dataItem) {
var editorType = item instanceof Shape ? 'shape' : 'connection';
this.editModel(item.dataItem, editorType);
}
},
cancelEdit: function () {
if (this.editor) {
this._getEditDataSource().cancelChanges(this.editor.model);
this._destroyEditor();
}
},
saveEdit: function () {
if (this.editor && this.editor.end() && !this.trigger('save', this._editArgs())) {
this._getEditDataSource().sync();
}
},
_update: function () {
if (this.editor && this.editor.end() && !this.trigger('save', this._editArgs())) {
this._getEditDataSource().sync();
this._destroyEditor();
}
},
_cancel: function () {
if (this.editor && !this.trigger('cancel', this._editArgs())) {
var model = this.editor.model;
this._getEditDataSource().cancelChanges(model);
var element = this._connectionsDataMap[model.uid] || this._dataMap[model.id];
if (element) {
element._setOptionsFromModel(model);
}
this._destroyEditor();
}
},
_getEditDataSource: function () {
return this.editor.options.type === 'shape' ? this.dataSource : this.connectionsDataSource;
},
_editArgs: function () {
var result = { container: this.editor.wrapper };
result[this.editor.options.type] = this.editor.model;
return result;
},
_destroyEditor: function () {
if (this.editor) {
this.editor.close();
this.editor = null;
}
},
_initElements: function () {
this.wrapper = this.element.empty().css('position', 'relative').attr('tabindex', 0).addClass('k-widget k-diagram');
this.scrollable = $('
').appendTo(this.element);
},
_initDefaults: function (userOptions) {
var options = this.options;
var editable = options.editable;
var shapeDefaults = options.shapeDefaults;
var connectionDefaults = options.connectionDefaults;
var userShapeDefaults = (userOptions || {}).shapeDefaults;
if (editable === false) {
shapeDefaults.editable = false;
connectionDefaults.editable = false;
} else {
copyDefaultOptions(editable, shapeDefaults.editable, [
'drag',
'remove',
'connect'
]);
copyDefaultOptions(editable, connectionDefaults.editable, [
'drag',
'remove'
]);
}
if (userShapeDefaults && userShapeDefaults.connectors) {
options.shapeDefaults.connectors = userShapeDefaults.connectors;
}
},
_initCanvas: function () {
var canvasContainer = $('
').appendTo(this.scrollable)[0];
var viewPort = this.viewport();
this.canvas = new Canvas(canvasContainer, {
width: viewPort.width || DEFAULT_CANVAS_WIDTH,
height: viewPort.height || DEFAULT_CANVAS_HEIGHT
});
},
_createHandlers: function () {
var that = this;
var element = that.element;
element.on(MOUSEWHEEL_NS, proxy(that._wheel, that));
if (!kendo.support.touch && !kendo.support.mobileOS) {
that.toolService = new ToolService(that);
this.scroller.wrapper.on('mousemove' + NS, proxy(that._mouseMove, that)).on('mouseup' + NS, proxy(that._mouseUp, that)).on('mousedown' + NS, proxy(that._mouseDown, that)).on('mouseover' + NS, proxy(that._mouseover, that)).on('mouseout' + NS, proxy(that._mouseout, that));
element.on('keydown' + NS, proxy(that._keydown, that));
} else {
that._userEvents = new kendo.UserEvents(element, {
multiTouch: true,
tap: proxy(that._tap, that)
});
that._userEvents.bind([
'gesturestart',
'gesturechange',
'gestureend'
], {
gesturestart: proxy(that._gestureStart, that),
gesturechange: proxy(that._gestureChange, that),
gestureend: proxy(that._gestureEnd, that)
});
that.toolService = new ToolService(that);
if (that.options.pannable !== false) {
that.scroller.enable();
}
}
this._syncHandler = proxy(that._syncChanges, that);
that._resizeHandler = proxy(that.resize, that, false);
kendo.onResize(that._resizeHandler);
this.bind(ZOOM_START, proxy(that._destroyToolBar, that));
this.bind(PAN, proxy(that._destroyToolBar, that));
},
_tap: function (e) {
var toolService = this.toolService;
var p = this._caculateMobilePosition(e);
toolService._updateHoveredItem(p);
if (toolService.hoveredItem) {
var item = toolService.hoveredItem;
if (this.options.selectable !== false) {
this._destroyToolBar();
if (item.isSelected) {
item.select(false);
} else {
this.select(item, { addToSelection: true });
}
this._createToolBar();
}
this.trigger('click', {
item: item,
point: p
});
}
},
_caculateMobilePosition: function (e) {
return this.documentToModel(Point(e.x.location, e.y.location));
},
_gestureStart: function (e) {
this._destroyToolBar();
this.scroller.disable();
var initialCenter = this.documentToModel(new Point(e.center.x, e.center.y));
var eventArgs = {
point: initialCenter,
zoom: this.zoom()
};
if (this.trigger(ZOOM_START, eventArgs)) {
return;
}
this._gesture = e;
this._initialCenter = initialCenter;
},
_gestureChange: function (e) {
var previousGesture = this._gesture;
var initialCenter = this._initialCenter;
var center = this.documentToView(new Point(e.center.x, e.center.y));
var scaleDelta = e.distance / previousGesture.distance;
var zoom = this._zoom;
var updateZoom = false;
if (math.abs(scaleDelta - 1) >= MOBILE_ZOOM_RATE) {
this._zoom = zoom = this._getValidZoom(zoom * scaleDelta);
this.options.zoom = zoom;
this._gesture = e;
updateZoom = true;
}
var zoomedPoint = initialCenter.times(zoom);
var pan = center.minus(zoomedPoint);
if (updateZoom || this._pan.distanceTo(pan) >= MOBILE_PAN_DISTANCE) {
this._panTransform(pan);
this._updateAdorners();
}
e.preventDefault();
},
_gestureEnd: function () {
if (this.options.pannable !== false) {
this.scroller.enable();
}
this.trigger(ZOOM_END, {
point: this._initialCenter,
zoom: this.zoom()
});
},
_resize: function () {
var viewport = this.viewport();
if (this.canvas) {
this.canvas.size(viewport);
}
if (this.scrollable && this.toolBar) {
this.scrollable.height(viewport.height);
}
},
_mouseover: function (e) {
var node = e.target._kendoNode;
if (node && node.srcElement._hover) {
node.srcElement._hover(true, node.srcElement);
}
},
_mouseout: function (e) {
var node = e.target._kendoNode;
if (node && node.srcElement._hover) {
node.srcElement._hover(false, node.srcElement);
}
},
_initTheme: function () {
var that = this, themes = dataviz.ui.themes || {}, themeName = ((that.options || {}).theme || '').toLowerCase(), themeOptions = (themes[themeName] || {}).diagram;
that.options = deepExtend({}, themeOptions, that.options);
if (that.options.editable === true) {
deepExtend(that.options, { editable: (themeOptions || {}).editable });
}
},
_createOptionElements: function () {
var options = this.options;
var shapesLength = options.shapes.length;
if (shapesLength) {
this._createShapes();
}
if (options.connections.length) {
this._createConnections();
}
if (shapesLength && options.layout) {
this.layout(options.layout);
}
},
_createShapes: function () {
var that = this, options = that.options, shapes = options.shapes, shape, i;
for (i = 0; i < shapes.length; i++) {
shape = shapes[i];
that.addShape(shape);
}
},
_createConnections: function () {
var diagram = this, options = diagram.options, defaults = options.connectionDefaults, connections = options.connections, conn, source, target, i;
for (i = 0; i < connections.length; i++) {
conn = connections[i];
source = diagram._findConnectionTarget(conn.from);
target = diagram._findConnectionTarget(conn.to);
diagram.connect(source, target, deepExtend({}, defaults, conn));
}
},
_findConnectionTarget: function (options) {
var diagram = this;
var shapeId = isString(options) ? options : options.shapeId || options.id;
var target;
if (shapeId) {
target = diagram.getShapeById(shapeId);
if (options.connector) {
target = target.getConnector(options.connector);
}
} else {
target = new Point(options.x || 0, options.y || 0);
}
return target;
},
destroy: function () {
var that = this;
Widget.fn.destroy.call(that);
if (this._userEvents) {
this._userEvents.destroy();
}
kendo.unbindResize(that._resizeHandler);
that.clear();
that.element.off(NS);
that.scroller.wrapper.off(NS);
that.canvas.destroy(true);
that.canvas = undefined;
that._destroyEditor();
that.destroyScroller();
that._destroyGlobalToolBar();
that._destroyToolBar();
},
destroyScroller: function () {
var scroller = this.scroller;
if (!scroller) {
return;
}
scroller.destroy();
scroller.element.remove();
this.scroller = null;
},
save: function () {
var json = {
shapes: [],
connections: []
};
var i, connection, shape;
for (i = 0; i < this.shapes.length; i++) {
shape = this.shapes[i];
if (shape.options.serializable) {
json.shapes.push(shape.options);
}
}
for (i = 0; i < this.connections.length; i++) {
connection = this.connections[i];
json.connections.push(deepExtend({}, connection.options, connection.toJSON()));
}
return json;
},
focus: function () {
if (!this.element.is(kendo._activeElement())) {
var element = this.element, scrollContainer = element[0], containers = [], offsets = [], documentElement = document.documentElement, i;
do {
scrollContainer = scrollContainer.parentNode;
if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
containers.push(scrollContainer);
offsets.push(scrollContainer.scrollTop);
}
} while (scrollContainer != documentElement);
element.focus();
for (i = 0; i < containers.length; i++) {
containers[i].scrollTop = offsets[i];
}
}
},
load: function (options) {
this.clear();
this.setOptions(options);
this._createShapes();
this._createConnections();
},
setOptions: function (options) {
deepExtend(this.options, options);
},
clear: function () {
var that = this;
that.select(false);
that.mainLayer.clear();
that._shapesQuadTree.clear();
that._initialize();
},
connect: function (source, target, options) {
var connection;
if (this.connectionsDataSource && this._isEditable) {
var dataItem = this.connectionsDataSource.add({});
connection = this._connectionsDataMap[dataItem.uid];
connection.source(source);
connection.target(target);
connection.redraw(options);
connection.updateModel();
} else {
connection = new Connection(source, target, deepExtend({}, this.options.connectionDefaults, options));
this.addConnection(connection);
}
return connection;
},
connected: function (source, target) {
for (var i = 0; i < this.connections.length; i++) {
var c = this.connections[i];
if (c.from == source && c.to == target) {
return true;
}
}
return false;
},
addConnection: function (connection, undoable) {
if (undoable !== false) {
this.undoRedoService.add(new diagram.AddConnectionUnit(connection, this), false);
}
connection.diagram = this;
connection._setOptionsFromModel();
connection.refresh();
this.mainLayer.append(connection.visual);
this.connections.push(connection);
this.trigger(CHANGE, {
added: [connection],
removed: []
});
return connection;
},
_addConnection: function (connection, undoable) {
var connectionsDataSource = this.connectionsDataSource;
var dataItem;
if (connectionsDataSource && this._isEditable) {
dataItem = createModel(connectionsDataSource, cloneDataItem(connection.dataItem));
connection.dataItem = dataItem;
connection.updateModel();
if (!this.trigger('add', { connection: connection })) {
this._connectionsDataMap[dataItem.uid] = connection;
connectionsDataSource.add(dataItem);
this.addConnection(connection, undoable);
connection._updateConnectors();
return connection;
}
} else if (!this.trigger('add', { connection: connection })) {
this.addConnection(connection, undoable);
connection._updateConnectors();
return connection;
}
},
addShape: function (item, undoable) {
var shape, shapeDefaults = this.options.shapeDefaults;
if (item instanceof Shape) {
shape = item;
} else if (!(item instanceof kendo.Class)) {
shapeDefaults = deepExtend({}, shapeDefaults, item || {});
shape = new Shape(shapeDefaults, this);
} else {
return;
}
if (undoable !== false) {
this.undoRedoService.add(new diagram.AddShapeUnit(shape, this), false);
}
this.shapes.push(shape);
if (shape.diagram !== this) {
this._shapesQuadTree.insert(shape);
shape.diagram = this;
}
this.mainLayer.append(shape.visual);
this.trigger(CHANGE, {
added: [shape],
removed: []
});
return shape;
},
_addShape: function (shape, undoable) {
var that = this;
var dataSource = that.dataSource;
var dataItem;
if (dataSource && this._isEditable) {
dataItem = createModel(dataSource, cloneDataItem(shape.dataItem));
shape.dataItem = dataItem;
shape.updateModel();
if (!this.trigger('add', { shape: shape })) {
this.dataSource.add(dataItem);
var inactiveItem = this._inactiveShapeItems.getByUid(dataItem.uid);
inactiveItem.element = shape;
inactiveItem.undoable = undoable;
return shape;
}
} else if (!this.trigger('add', { shape: shape })) {
return this.addShape(shape, undoable);
}
},
remove: function (items, undoable) {
items = isArray(items) ? items.slice(0) : [items];
var elements = splitDiagramElements(items);
var shapes = elements.shapes;
var connections = elements.connections;
var i;
if (!defined(undoable)) {
undoable = true;
}
if (undoable) {
this.undoRedoService.begin();
}
this._suspendModelRefresh();
for (i = shapes.length - 1; i >= 0; i--) {
this._removeItem(shapes[i], undoable, connections);
}
for (i = connections.length - 1; i >= 0; i--) {
this._removeItem(connections[i], undoable);
}
this._resumeModelRefresh();
if (undoable) {
this.undoRedoService.commit(false);
}
this.trigger(CHANGE, {
added: [],
removed: items
});
},
_removeShapeDataItem: function (item) {
if (this._isEditable) {
this.dataSource.remove(item.dataItem);
delete this._dataMap[item.dataItem.id];
}
},
_removeConnectionDataItem: function (item) {
if (this._isEditable) {
this.connectionsDataSource.remove(item.dataItem);
delete this._connectionsDataMap[item.dataItem.uid];
}
},
_triggerRemove: function (items) {
var toRemove = [];
var item, args, editable;
for (var idx = 0; idx < items.length; idx++) {
item = items[idx];
editable = item.options.editable;
if (item instanceof Shape) {
args = { shape: item };
} else {
args = { connection: item };
}
if (editable && editable.remove !== false && !this.trigger('remove', args)) {
toRemove.push(item);
}
}
return toRemove;
},
undo: function () {
this.undoRedoService.undo();
},
redo: function () {
this.undoRedoService.redo();
},
select: function (item, options) {
if (isDefined(item)) {
options = deepExtend({ addToSelection: false }, options);
var addToSelection = options.addToSelection, items = [], selected = [], i, element;
if (!addToSelection) {
this.deselect();
}
this._internalSelection = true;
if (item instanceof Array) {
items = item;
} else if (item instanceof DiagramElement) {
items = [item];
}
for (i = 0; i < items.length; i++) {
element = items[i];
if (element.select(true)) {
selected.push(element);
}
}
this._selectionChanged(selected, []);
this._internalSelection = false;
} else {
return this._selectedItems;
}
},
selectAll: function () {
this.select(this.shapes.concat(this.connections));
},
selectArea: function (rect) {
var i, items, item;
this._internalSelection = true;
var selected = [];
if (rect instanceof Rect) {
items = this.shapes.concat(this.connections);
for (i = 0; i < items.length; i++) {
item = items[i];
if ((!rect || item._hitTest(rect)) && item.options.enable) {
if (item.select(true)) {
selected.push(item);
}
}
}
}
this._selectionChanged(selected, []);
this._internalSelection = false;
},
deselect: function (item) {
this._internalSelection = true;
var deselected = [], items = [], element, i;
if (item instanceof Array) {
items = item;
} else if (item instanceof DiagramElement) {
items.push(item);
} else if (!isDefined(item)) {
items = this._selectedItems.slice(0);
}
for (i = 0; i < items.length; i++) {
element = items[i];
if (element.select(false)) {
deselected.push(element);
}
}
this._selectionChanged([], deselected);
this._internalSelection = false;
},
toFront: function (items, undoable) {
if (!items) {
items = this._selectedItems.slice();
}
var result = this._getDiagramItems(items), indices;
if (!defined(undoable) || undoable) {
indices = indicesOfItems(this.mainLayer, result.visuals);
var unit = new ToFrontUnit(this, items, indices);
this.undoRedoService.add(unit);
} else {
this.mainLayer.toFront(result.visuals);
this._fixOrdering(result, true);
}
},
toBack: function (items, undoable) {
if (!items) {
items = this._selectedItems.slice();
}
var result = this._getDiagramItems(items), indices;
if (!defined(undoable) || undoable) {
indices = indicesOfItems(this.mainLayer, result.visuals);
var unit = new ToBackUnit(this, items, indices);
this.undoRedoService.add(unit);
} else {
this.mainLayer.toBack(result.visuals);
this._fixOrdering(result, false);
}
},
bringIntoView: function (item, options) {
var viewport = this.viewport();
var aligner = new diagram.RectAlign(viewport);
var current, rect, original, newPan;
if (viewport.width === 0 || viewport.height === 0) {
return;
}
options = deepExtend({
animate: false,
align: 'center middle'
}, options);
if (options.align == 'none') {
options.align = 'center middle';
}
if (item instanceof DiagramElement) {
rect = item.bounds(TRANSFORMED);
} else if (isArray(item)) {
rect = this.boundingBox(item);
} else if (item instanceof Rect) {
rect = item.clone();
}
original = rect.clone();
rect.zoom(this._zoom);
if (rect.width > viewport.width || rect.height > viewport.height) {
this._zoom = this._getValidZoom(math.min(viewport.width / original.width, viewport.height / original.height));
rect = original.clone().zoom(this._zoom);
}
this._zoomMainLayer();
current = rect.clone();
aligner.align(rect, options.align);
newPan = rect.topLeft().minus(current.topLeft());
this.pan(newPan.times(-1), options.animate);
},
alignShapes: function (direction) {
if (isUndefined(direction)) {
direction = 'Left';
}
var items = this.select(), val, item, i;
if (items.length === 0) {
return;
}
switch (direction.toLowerCase()) {
case 'left':
case 'top':
val = MAX_VALUE;
break;
case 'right':
case 'bottom':
val = MIN_VALUE;
break;
}
for (i = 0; i < items.length; i++) {
item = items[i];
if (item instanceof Shape) {
switch (direction.toLowerCase()) {
case 'left':
val = math.min(val, item.options.x);
break;
case 'top':
val = math.min(val, item.options.y);
break;
case 'right':
val = math.max(val, item.options.x);
break;
case 'bottom':
val = math.max(val, item.options.y);
break;
}
}
}
var undoStates = [];
var shapes = [];
for (i = 0; i < items.length; i++) {
item = items[i];
if (item instanceof Shape) {
shapes.push(item);
undoStates.push(item.bounds());
switch (direction.toLowerCase()) {
case 'left':
case 'right':
item.position(new Point(val, item.options.y));
break;
case 'top':
case 'bottom':
item.position(new Point(item.options.x, val));
break;
}
}
}
var unit = new diagram.TransformUnit(shapes, undoStates);
this.undoRedoService.add(unit, false);
},
zoom: function (zoom, options) {
if (zoom) {
var staticPoint = options ? options.point : new diagram.Point(0, 0);
zoom = this._zoom = this._getValidZoom(zoom);
if (!isUndefined(staticPoint)) {
staticPoint = new diagram.Point(math.round(staticPoint.x), math.round(staticPoint.y));
var zoomedPoint = staticPoint.times(zoom);
var viewportVector = this.modelToView(staticPoint);
var raw = viewportVector.minus(zoomedPoint);
this._storePan(new diagram.Point(math.round(raw.x), math.round(raw.y)));
}
if (options) {
options.zoom = zoom;
}
this._panTransform();
this._updateAdorners();
}
return this._zoom;
},
_getPan: function (pan) {
var canvas = this.canvas;
if (!canvas.translate) {
pan = pan.plus(this._pan);
}
return pan;
},
pan: function (pan, animate) {
if (pan instanceof Point) {
var that = this;
var scroller = that.scroller;
pan = that._getPan(pan);
pan = pan.times(-1);
if (animate) {
scroller.animatedScrollTo(pan.x, pan.y, function () {
that._updateAdorners();
});
} else {
scroller.scrollTo(pan.x, pan.y);
that._updateAdorners();
}
}
},
viewport: function () {
var element = this.element;
var width = element.width();
var height = element.height();
if (this.toolBar) {
height -= this.toolBar.element.outerHeight();
}
return new Rect(0, 0, width, height);
},
copy: function () {
if (this.options.copy.enabled) {
this._clipboard = [];
this._copyOffset = 1;
for (var i = 0; i < this._selectedItems.length; i++) {
var item = this._selectedItems[i];
this._clipboard.push(item);
}
}
},
cut: function () {
if (this.options.copy.enabled) {
this._clipboard = [];
this._copyOffset = 0;
for (var i = 0; i < this._selectedItems.length; i++) {
var item = this._selectedItems[i];
this._clipboard.push(item);
}
this.remove(this._clipboard, true);
}
},
paste: function () {
if (this._clipboard.length > 0) {
var item, copied, i;
var mapping = {};
var elements = splitDiagramElements(this._clipboard);
var connections = elements.connections;
var shapes = elements.shapes;
var offset = {
x: this._copyOffset * this.options.copy.offsetX,
y: this._copyOffset * this.options.copy.offsetY
};
this.deselect();
for (i = 0; i < shapes.length; i++) {
item = shapes[i];
copied = item.clone();
mapping[item.id] = copied;
copied.position(new Point(item.options.x + offset.x, item.options.y + offset.y));
copied.diagram = this;
copied = this._addShape(copied);
if (copied) {
copied.select();
}
}
for (i = 0; i < connections.length; i++) {
item = connections[i];
copied = this._addConnection(item.clone());
if (copied) {
this._updateCopiedConnection(copied, item, 'source', mapping, offset);
this._updateCopiedConnection(copied, item, 'target', mapping, offset);
copied.select(true);
copied.updateModel();
}
}
this._syncChanges();
this._copyOffset += 1;
}
},
_updateCopiedConnection: function (connection, sourceConnection, connectorName, mapping, offset) {
var onActivate, inactiveItem, targetShape;
var target = sourceConnection[connectorName]();
var diagram = this;
if (target instanceof Connector && mapping[target.shape.id]) {
targetShape = mapping[target.shape.id];
if (diagram.getShapeById(targetShape.id)) {
connection[connectorName](targetShape.getConnector(target.options.name));
} else {
inactiveItem = diagram._inactiveShapeItems.getByUid(targetShape.dataItem.uid);
if (inactiveItem) {
onActivate = function (item) {
targetShape = diagram._dataMap[item.id];
connection[connectorName](targetShape.getConnector(target.options.name));
connection.updateModel();
};
diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(onActivate));
}
}
} else {
connection[connectorName](new Point(sourceConnection[connectorName + 'Point']().x + offset.x, sourceConnection[connectorName + 'Point']().y + offset.y));
}
},
boundingBox: function (items, origin) {
var rect = Rect.empty(), temp, di = isDefined(items) ? this._getDiagramItems(items) : { shapes: this.shapes };
if (di.shapes.length > 0) {
var item = di.shapes[0];
rect = item.bounds(ROTATED);
for (var i = 1; i < di.shapes.length; i++) {
item = di.shapes[i];
temp = item.bounds(ROTATED);
if (origin === true) {
temp.x -= item._rotationOffset.x;
temp.y -= item._rotationOffset.y;
}
rect = rect.union(temp);
}
}
return rect;
},
_containerOffset: function () {
var containerOffset = this.element.offset();
if (this.toolBar) {
containerOffset.top += this.toolBar.element.outerHeight();
}
return containerOffset;
},
documentToView: function (point) {
var containerOffset = this._containerOffset();
return new Point(point.x - containerOffset.left, point.y - containerOffset.top);
},
viewToDocument: function (point) {
var containerOffset = this._containerOffset();
return new Point(point.x + containerOffset.left, point.y + containerOffset.top);
},
viewToModel: function (point) {
return this._transformWithMatrix(point, this._matrixInvert);
},
modelToView: function (point) {
return this._transformWithMatrix(point, this._matrix);
},
modelToLayer: function (point) {
return this._transformWithMatrix(point, this._layerMatrix);
},
layerToModel: function (point) {
return this._transformWithMatrix(point, this._layerMatrixInvert);
},
documentToModel: function (point) {
var viewPoint = this.documentToView(point);
if (!this.canvas.translate) {
viewPoint.x = viewPoint.x + this.scroller.scrollLeft;
viewPoint.y = viewPoint.y + this.scroller.scrollTop;
}
return this.viewToModel(viewPoint);
},
modelToDocument: function (point) {
return this.viewToDocument(this.modelToView(point));
},
_transformWithMatrix: function (point, matrix) {
var result = point;
if (point instanceof Point) {
if (matrix) {
result = matrix.apply(point);
}
} else {
var tl = this._transformWithMatrix(point.topLeft(), matrix), br = this._transformWithMatrix(point.bottomRight(), matrix);
result = Rect.fromPoints(tl, br);
}
return result;
},
setDataSource: function (dataSource) {
this.options.dataSource = dataSource;
this._dataSource();
if (this.options.autoBind) {
this.dataSource.fetch();
}
},
setConnectionsDataSource: function (dataSource) {
this.options.connectionsDataSource = dataSource;
this._connectionDataSource();
if (this.options.autoBind) {
this.connectionsDataSource.fetch();
}
},
layout: function (options) {
this._layouting = true;
var type;
if (isUndefined(options)) {
options = this.options.layout;
}
if (isUndefined(options) || isUndefined(options.type)) {
type = 'Tree';
} else {
type = options.type;
}
var l;
switch (type.toLowerCase()) {
case 'tree':
l = new diagram.TreeLayout(this);
break;
case 'layered':
l = new diagram.LayeredLayout(this);
break;
case 'forcedirected':
case 'force':
case 'spring':
case 'springembedder':
l = new diagram.SpringLayout(this);
break;
default:
throw 'Layout algorithm \'' + type + '\' is not supported.';
}
var initialState = new diagram.LayoutState(this);
var finalState = l.layout(options);
if (finalState) {
var unit = new diagram.LayoutUndoUnit(initialState, finalState, options ? options.animate : null);
this.undoRedoService.add(unit);
}
this._layouting = false;
this._redrawConnections();
},
getShapeById: function (id) {
var found;
found = Utils.first(this.shapes, function (s) {
return s.visual.id === id;
});
if (found) {
return found;
}
found = Utils.first(this.connections, function (c) {
return c.visual.id === id;
});
return found;
},
_extendLayoutOptions: function (options) {
if (options.layout) {
options.layout = deepExtend(diagram.LayoutBase.fn.defaultOptions || {}, options.layout);
}
},
_selectionChanged: function (selected, deselected) {
if (selected.length || deselected.length) {
this.trigger(SELECT, {
selected: selected,
deselected: deselected
});
}
},
_getValidZoom: function (zoom) {
return math.min(math.max(zoom, this.options.zoomMin), this.options.zoomMax);
},
_panTransform: function (pos) {
var diagram = this, pan = pos || diagram._pan;
if (diagram.canvas.translate) {
diagram.scroller.scrollTo(pan.x, pan.y);
diagram._zoomMainLayer();
} else {
diagram._storePan(pan);
diagram._transformMainLayer();
}
},
_finishPan: function () {
this.trigger(PAN, {
total: this._pan,
delta: Number.NaN
});
},
_storePan: function (pan) {
this._pan = pan;
this._storeViewMatrix();
},
_zoomMainLayer: function () {
var zoom = this._zoom;
var transform = new CompositeTransform(0, 0, zoom, zoom);
transform.render(this.mainLayer);
this._storeLayerMatrix(transform);
this._storeViewMatrix();
},
_transformMainLayer: function () {
var pan = this._pan, zoom = this._zoom;
var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
transform.render(this.mainLayer);
this._storeLayerMatrix(transform);
this._storeViewMatrix();
},
_storeLayerMatrix: function (canvasTransform) {
this._layerMatrix = canvasTransform.toMatrix();
this._layerMatrixInvert = canvasTransform.invert().toMatrix();
},
_storeViewMatrix: function () {
var pan = this._pan, zoom = this._zoom;
var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
this._matrix = transform.toMatrix();
this._matrixInvert = transform.invert().toMatrix();
},
_toIndex: function (items, indices) {
var result = this._getDiagramItems(items);
this.mainLayer.toIndex(result.visuals, indices);
this._fixOrdering(result, false);
},
_fixOrdering: function (result, toFront) {
var shapePos = toFront ? this.shapes.length - 1 : 0, conPos = toFront ? this.connections.length - 1 : 0, i, item;
for (i = 0; i < result.shapes.length; i++) {
item = result.shapes[i];
Utils.remove(this.shapes, item);
Utils.insert(this.shapes, item, shapePos);
}
for (i = 0; i < result.cons.length; i++) {
item = result.cons[i];
Utils.remove(this.connections, item);
Utils.insert(this.connections, item, conPos);
}
},
_getDiagramItems: function (items) {
var i, result = {}, args = items;
result.visuals = [];
result.shapes = [];
result.cons = [];
if (!items) {
args = this._selectedItems.slice();
} else if (!isArray(items)) {
args = [items];
}
for (i = 0; i < args.length; i++) {
var item = args[i];
if (item instanceof Shape) {
result.shapes.push(item);
result.visuals.push(item.visual);
} else if (item instanceof Connection) {
result.cons.push(item);
result.visuals.push(item.visual);
}
}
return result;
},
_removeItem: function (item, undoable, removedConnections) {
item.select(false);
if (item instanceof Shape) {
this._removeShapeDataItem(item);
this._removeShape(item, undoable, removedConnections);
} else if (item instanceof Connection) {
this._removeConnectionDataItem(item);
this._removeConnection(item, undoable);
}
this.mainLayer.remove(item.visual);
},
_removeShape: function (shape, undoable, removedConnections) {
var i, connection, connector, sources = [], targets = [];
this.toolService._removeHover();
if (undoable) {
this.undoRedoService.addCompositeItem(new DeleteShapeUnit(shape));
}
Utils.remove(this.shapes, shape);
this._shapesQuadTree.remove(shape);
for (i = 0; i < shape.connectors.length; i++) {
connector = shape.connectors[i];
for (var j = 0; j < connector.connections.length; j++) {
connection = connector.connections[j];
if (!removedConnections || !dataviz.inArray(connection, removedConnections)) {
if (connection.sourceConnector == connector) {
sources.push(connection);
} else if (connection.targetConnector == connector) {
targets.push(connection);
}
}
}
}
for (i = 0; i < sources.length; i++) {
sources[i].source(null, undoable);
sources[i].updateModel();
}
for (i = 0; i < targets.length; i++) {
targets[i].target(null, undoable);
targets[i].updateModel();
}
},
_removeConnection: function (connection, undoable) {
if (connection.sourceConnector) {
Utils.remove(connection.sourceConnector.connections, connection);
}
if (connection.targetConnector) {
Utils.remove(connection.targetConnector.connections, connection);
}
if (undoable) {
this.undoRedoService.addCompositeItem(new DeleteConnectionUnit(connection));
}
Utils.remove(this.connections, connection);
},
_removeDataItems: function (items, recursive) {
var item, children, shape, idx;
items = isArray(items) ? items : [items];
while (items.length) {
item = items.shift();
shape = this._dataMap[item.uid];
if (shape) {
this._removeShapeConnections(shape);
this._removeItem(shape, false);
delete this._dataMap[item.uid];
if (recursive && item.hasChildren && item.loaded()) {
children = item.children.data();
for (idx = 0; idx < children.length; idx++) {
items.push(children[idx]);
}
}
}
}
},
_removeShapeConnections: function (shape) {
var connections = shape.connections();
var idx;
if (connections) {
for (idx = 0; idx < connections.length; idx++) {
this._removeItem(connections[idx], false);
}
}
},
_addDataItem: function (dataItem, undoable) {
if (!defined(dataItem)) {
return;
}
var shape = this._dataMap[dataItem.id];
if (shape) {
return shape;
}
var options = deepExtend({}, this.options.shapeDefaults);
options.dataItem = dataItem;
shape = new Shape(options, this);
this.addShape(shape, undoable !== false);
this._dataMap[dataItem.id] = shape;
return shape;
},
_addDataItemByUid: function (dataItem) {
if (!defined(dataItem)) {
return;
}
var shape = this._dataMap[dataItem.uid];
if (shape) {
return shape;
}
var options = deepExtend({}, this.options.shapeDefaults);
options.dataItem = dataItem;
shape = new Shape(options, this);
this.addShape(shape);
this._dataMap[dataItem.uid] = shape;
return shape;
},
_addDataItems: function (items, parent) {
var item, idx, shape, parentShape, connection;
for (idx = 0; idx < items.length; idx++) {
item = items[idx];
shape = this._addDataItemByUid(item);
parentShape = this._addDataItemByUid(parent);
if (parentShape && !this.connected(parentShape, shape)) {
connection = this.connect(parentShape, shape);
}
}
},
_refreshSource: function (e) {
var that = this, node = e.node, action = e.action, items = e.items, options = that.options, idx, dataBound;
if (e.field) {
return;
}
if (action == 'remove') {
this._removeDataItems(e.items, true);
} else {
if ((!action || action === 'itemloaded') && !this._bindingRoots) {
this._bindingRoots = true;
dataBound = true;
}
if (!action && !node) {
that.clear();
}
this._addDataItems(items, node);
for (idx = 0; idx < items.length; idx++) {
items[idx].load();
}
}
if (options.layout && (dataBound || action == 'remove' || action == 'add')) {
that.layout(options.layout);
}
if (dataBound) {
this.trigger('dataBound');
this._bindingRoots = false;
}
},
_mouseDown: function (e) {
var p = this._calculatePosition(e);
if (e.which == 1 && this.toolService.start(p, this._meta(e))) {
this._destroyToolBar();
e.preventDefault();
}
},
_addItem: function (item) {
if (item instanceof Shape) {
this.addShape(item);
} else if (item instanceof Connection) {
this.addConnection(item);
}
},
_mouseUp: function (e) {
var p = this._calculatePosition(e);
if (e.which == 1 && this.toolService.end(p, this._meta(e))) {
this._createToolBar();
e.preventDefault();
}
},
_createToolBar: function () {
var diagram = this.toolService.diagram;
if (!this.singleToolBar && diagram.select().length === 1) {
var element = diagram.select()[0];
if (element && element.options.editable !== false) {
var editable = element.options.editable;
var tools = editable.tools;
if (this._isEditable && tools.length === 0) {
if (element instanceof Shape) {
tools = [
'edit',
'rotateClockwise',
'rotateAnticlockwise'
];
} else if (element instanceof Connection) {
tools = ['edit'];
}
if (editable && editable.remove !== false) {
tools.push('delete');
}
}
if (tools && tools.length) {
var padding = 20;
var point;
this.singleToolBar = new DiagramToolBar(diagram, {
tools: tools,
click: proxy(this._toolBarClick, this),
modal: true
});
var popupWidth = this.singleToolBar._popup.element.outerWidth();
var popupHeight = this.singleToolBar._popup.element.outerHeight();
if (element instanceof Shape) {
var shapeBounds = this.modelToView(element.bounds(ROTATED));
point = Point(shapeBounds.x, shapeBounds.y).minus(Point((popupWidth - shapeBounds.width) / 2, popupHeight + padding));
} else if (element instanceof Connection) {
var connectionBounds = this.modelToView(element.bounds());
point = Point(connectionBounds.x, connectionBounds.y).minus(Point((popupWidth - connectionBounds.width - 20) / 2, popupHeight + padding));
}
if (point) {
if (!this.canvas.translate) {
point = point.minus(Point(this.scroller.scrollLeft, this.scroller.scrollTop));
}
point = this.viewToDocument(point);
point = Point(math.max(point.x, 0), math.max(point.y, 0));
this.singleToolBar.showAt(point);
} else {
this._destroyToolBar();
}
}
}
}
},
_toolBarClick: function (e) {
this.trigger('toolBarClick', e);
this._destroyToolBar();
},
_mouseMove: function (e) {
if (this.pauseMouseHandlers) {
return;
}
var p = this._calculatePosition(e);
if ((e.which === 0 || e.which == 1) && this.toolService.move(p, this._meta(e))) {
e.preventDefault();
}
},
_keydown: function (e) {
if (this.toolService.keyDown(e.keyCode, this._meta(e))) {
e.preventDefault();
}
},
_wheel: function (e) {
var delta = mwDelta(e), p = this._calculatePosition(e), meta = deepExtend(this._meta(e), { delta: delta });
if (this.toolService.wheel(p, meta)) {
e.preventDefault();
}
},
_meta: function (e) {
return {
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
altKey: e.altKey,
shiftKey: e.shiftKey
};
},
_calculatePosition: function (e) {
var pointEvent = e.pageX === undefined ? e.originalEvent : e, point = new Point(pointEvent.pageX, pointEvent.pageY), offset = this.documentToModel(point);
return offset;
},
_normalizePointZoom: function (point) {
return point.times(1 / this.zoom());
},
_initialize: function () {
this.shapes = [];
this._selectedItems = [];
this.connections = [];
this._dataMap = {};
this._connectionsDataMap = {};
this._inactiveShapeItems = new InactiveItemsCollection();
this._deferredConnectionUpdates = [];
this.undoRedoService = new UndoRedoService({
undone: this._syncHandler,
redone: this._syncHandler
});
this.id = diagram.randomId();
},
_fetchFreshData: function () {
var that = this;
that._dataSource();
if (that._isEditable) {
that._connectionDataSource();
}
if (that.options.autoBind) {
if (that._isEditable) {
this._loadingShapes = true;
this._loadingConnections = true;
that.dataSource.fetch();
that.connectionsDataSource.fetch();
} else {
that.dataSource.fetch();
}
}
},
_dataSource: function () {
if (defined(this.options.connectionsDataSource)) {
this._isEditable = true;
var dsOptions = this.options.dataSource || {};
var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;
if (this.dataSource && this._shapesRefreshHandler) {
this.dataSource.unbind('change', this._shapesRefreshHandler).unbind('requestStart', this._shapesRequestStartHandler).unbind('error', this._shapesErrorHandler);
} else {
this._shapesRefreshHandler = proxy(this._refreshShapes, this);
this._shapesRequestStartHandler = proxy(this._shapesRequestStart, this);
this._shapesErrorHandler = proxy(this._error, this);
}
this.dataSource = kendo.data.DataSource.create(ds).bind('change', this._shapesRefreshHandler).bind('requestStart', this._shapesRequestStartHandler).bind('error', this._shapesErrorHandler);
} else {
this._treeDataSource();
this._isEditable = false;
}
},
_connectionDataSource: function () {
var dsOptions = this.options.connectionsDataSource;
if (dsOptions) {
var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;
if (this.connectionsDataSource && this._connectionsRefreshHandler) {
this.connectionsDataSource.unbind('change', this._connectionsRefreshHandler).unbind('requestStart', this._connectionsRequestStartHandler).unbind('error', this._connectionsErrorHandler);
} else {
this._connectionsRefreshHandler = proxy(this._refreshConnections, this);
this._connectionsRequestStartHandler = proxy(this._connectionsRequestStart, this);
this._connectionsErrorHandler = proxy(this._connectionsError, this);
}
this.connectionsDataSource = kendo.data.DataSource.create(ds).bind('change', this._connectionsRefreshHandler).bind('requestStart', this._connectionsRequestStartHandler).bind('error', this._connectionsErrorHandler);
}
},
_shapesRequestStart: function (e) {
if (e.type == 'read') {
this._loadingShapes = true;
}
},
_connectionsRequestStart: function (e) {
if (e.type == 'read') {
this._loadingConnections = true;
}
},
_error: function () {
this._loadingShapes = false;
},
_connectionsError: function () {
this._loadingConnections = false;
},
_refreshShapes: function (e) {
if (e.action === 'remove') {
if (this._shouldRefresh()) {
this._removeShapes(e.items);
}
} else if (e.action === 'itemchange') {
if (this._shouldRefresh()) {
this._updateShapes(e.items, e.field);
}
} else if (e.action === 'add') {
this._inactiveShapeItems.add(e.items);
} else if (e.action === 'sync') {
this._syncShapes(e.items);
} else {
this.refresh();
}
},
_shouldRefresh: function () {
return !this._suspended;
},
_suspendModelRefresh: function () {
this._suspended = (this._suspended || 0) + 1;
},
_resumeModelRefresh: function () {
this._suspended = math.max((this._suspended || 0) - 1, 0);
},
refresh: function () {
this._loadingShapes = false;
if (!this._loadingConnections) {
this._rebindShapesAndConnections();
}
},
_rebindShapesAndConnections: function () {
this.clear();
this._addShapes(this.dataSource.view());
if (this.connectionsDataSource) {
this._addConnections(this.connectionsDataSource.view(), false);
}
if (this.options.layout) {
this.layout(this.options.layout);
} else {
this._redrawConnections();
}
this.trigger('dataBound');
},
refreshConnections: function () {
this._loadingConnections = false;
if (!this._loadingShapes) {
this._rebindShapesAndConnections();
}
},
_redrawConnections: function () {
var connections = this.connections;
for (var idx = 0; idx < connections.length; idx++) {
connections[idx].refresh();
}
},
_removeShapes: function (items) {
var dataMap = this._dataMap;
var item, i;
for (i = 0; i < items.length; i++) {
item = items[i];
if (dataMap[item.id]) {
this.remove(dataMap[item.id], false);
dataMap[item.id] = null;
}
}
},
_syncShapes: function () {
var diagram = this;
var inactiveItems = diagram._inactiveShapeItems;
inactiveItems.forEach(function (inactiveItem) {
var dataItem = inactiveItem.dataItem;
var shape = inactiveItem.element;
if (!dataItem.isNew()) {
if (shape) {
shape._setOptionsFromModel();
diagram.addShape(shape, inactiveItem.undoable);
diagram._dataMap[dataItem.id] = shape;
} else {
diagram._addDataItem(dataItem);
}
inactiveItem.activate();
inactiveItems.remove(dataItem);
}
});
},
_updateShapes: function (items, field) {
for (var i = 0; i < items.length; i++) {
var dataItem = items[i];
var shape = this._dataMap[dataItem.id];
if (shape) {
shape.updateOptionsFromModel(dataItem, field);
}
}
},
_addShapes: function (dataItems) {
for (var i = 0; i < dataItems.length; i++) {
this._addDataItem(dataItems[i], false);
}
},
_refreshConnections: function (e) {
if (e.action === 'remove') {
if (this._shouldRefresh()) {
this._removeConnections(e.items);
}
} else if (e.action === 'add') {
this._addConnections(e.items);
} else if (e.action === 'sync') {
} else if (e.action === 'itemchange') {
if (this._shouldRefresh()) {
this._updateConnections(e.items);
}
} else {
this.refreshConnections();
}
},
_removeConnections: function (items) {
for (var i = 0; i < items.length; i++) {
this.remove(this._connectionsDataMap[items[i].uid], false);
this._connectionsDataMap[items[i].uid] = null;
}
},
_updateConnections: function (items) {
for (var i = 0; i < items.length; i++) {
var dataItem = items[i];
var connection = this._connectionsDataMap[dataItem.uid];
connection.updateOptionsFromModel(dataItem);
}
},
_addConnections: function (connections, undoable) {
var length = connections.length;
for (var i = 0; i < length; i++) {
var dataItem = connections[i];
this._addConnectionDataItem(dataItem, undoable);
}
},
_addConnectionDataItem: function (dataItem, undoable) {
if (!this._connectionsDataMap[dataItem.uid]) {
var from = this._validateConnector(dataItem.from);
if (!defined(from) || from === null) {
from = new Point(dataItem.fromX, dataItem.fromY);
}
var to = this._validateConnector(dataItem.to);
if (!defined(to) || to === null) {
to = new Point(dataItem.toX, dataItem.toY);
}
if (defined(from) && defined(to)) {
var options = deepExtend({}, this.options.connectionDefaults);
options.dataItem = dataItem;
var connection = new Connection(from, to, options);
this._connectionsDataMap[dataItem.uid] = connection;
this.addConnection(connection, undoable);
}
}
},
_validateConnector: function (value) {
var connector;
if (defined(value) && value !== null) {
connector = this._dataMap[value];
}
return connector;
},
_treeDataSource: function () {
var that = this, options = that.options, dataSource = options.dataSource;
dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
if (!dataSource.fields) {
dataSource.fields = [
{ field: 'text' },
{ field: 'url' },
{ field: 'spriteCssClass' },
{ field: 'imageUrl' }
];
}
if (that.dataSource && that._refreshHandler) {
that._unbindDataSource();
}
that._refreshHandler = proxy(that._refreshSource, that);
that._errorHandler = proxy(that._error, that);
that.dataSource = HierarchicalDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(ERROR, that._errorHandler);
},
_unbindDataSource: function () {
var that = this;
that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(ERROR, that._errorHandler);
},
_adorn: function (adorner, isActive) {
if (isActive !== undefined && adorner) {
if (isActive) {
this._adorners.push(adorner);
this.adornerLayer.append(adorner.visual);
} else {
Utils.remove(this._adorners, adorner);
this.adornerLayer.remove(adorner.visual);
}
}
},
_showConnectors: function (shape, value) {
if (value) {
this._connectorsAdorner.show(shape);
} else {
this._connectorsAdorner.destroy();
}
},
_updateAdorners: function () {
var adorners = this._adorners;
for (var i = 0; i < adorners.length; i++) {
var adorner = adorners[i];
if (adorner.refreshBounds) {
adorner.refreshBounds();
}
adorner.refresh();
}
},
_refresh: function () {
for (var i = 0; i < this.connections.length; i++) {
this.connections[i].refresh();
}
},
_destroyToolBar: function () {
if (this.singleToolBar) {
this.singleToolBar.hide();
this.singleToolBar.destroy();
this.singleToolBar = null;
}
},
_destroyGlobalToolBar: function () {
if (this.toolBar) {
this.toolBar.hide();
this.toolBar.destroy();
this.toolBar = null;
}
},
exportDOMVisual: function () {
var viewBox = this.canvas._viewBox;
var scrollOffset = geom.transform().translate(-viewBox.x, -viewBox.y);
var viewRect = new geom.Rect([
0,
0
], [
viewBox.width,
viewBox.height
]);
var clipPath = draw.Path.fromRect(viewRect);
var wrap = new draw.Group({ transform: scrollOffset });
var clipWrap = new draw.Group({ clip: clipPath });
var root = this.canvas.drawingElement.children[0];
clipWrap.append(wrap);
wrap.children.push(root);
return clipWrap;
},
exportVisual: function () {
var scale = geom.transform().scale(1 / this._zoom);
var wrap = new draw.Group({ transform: scale });
var root = this.mainLayer.drawingElement;
wrap.children.push(root);
return wrap;
},
_syncChanges: function () {
this._syncShapeChanges();
this._syncConnectionChanges();
},
_syncShapeChanges: function () {
if (this.dataSource && this._isEditable) {
this.dataSource.sync();
}
},
_syncConnectionChanges: function () {
var that = this;
if (that.connectionsDataSource && that._isEditable) {
$.when.apply($, that._deferredConnectionUpdates).then(function () {
that.connectionsDataSource.sync();
});
that.deferredConnectionUpdates = [];
}
}
});
dataviz.ExportMixin.extend(Diagram.fn, true);
if (kendo.PDFMixin) {
kendo.PDFMixin.extend(Diagram.fn);
}
function filterShapeDataItem(dataItem) {
var result = {};
dataItem = dataItem || {};
if (defined(dataItem.text) && dataItem.text !== null) {
result.text = dataItem.text;
}
if (defined(dataItem.x) && dataItem.x !== null) {
result.x = dataItem.x;
}
if (defined(dataItem.y) && dataItem.y !== null) {
result.y = dataItem.y;
}
if (defined(dataItem.width) && dataItem.width !== null) {
result.width = dataItem.width;
}
if (defined(dataItem.height) && dataItem.height !== null) {
result.height = dataItem.height;
}
if (defined(dataItem.type) && dataItem.type !== null) {
result.type = dataItem.type;
}
return result;
}
function filterConnectionDataItem(dataItem) {
var result = {};
dataItem = dataItem || {};
if (defined(dataItem.text) && dataItem.text !== null) {
result.content = dataItem.text;
}
if (defined(dataItem.type) && dataItem.type !== null) {
result.type = dataItem.type;
}
if (defined(dataItem.from) && dataItem.from !== null) {
result.from = dataItem.from;
}
if (defined(dataItem.fromConnector) && dataItem.fromConnector !== null) {
result.fromConnector = dataItem.fromConnector;
}
if (defined(dataItem.fromX) && dataItem.fromX !== null) {
result.fromX = dataItem.fromX;
}
if (defined(dataItem.fromY) && dataItem.fromY !== null) {
result.fromY = dataItem.fromY;
}
if (defined(dataItem.to) && dataItem.to !== null) {
result.to = dataItem.to;
}
if (defined(dataItem.toConnector) && dataItem.toConnector !== null) {
result.toConnector = dataItem.toConnector;
}
if (defined(dataItem.toX) && dataItem.toX !== null) {
result.toX = dataItem.toX;
}
if (defined(dataItem.toY) && dataItem.toY !== null) {
result.toY = dataItem.toY;
}
return result;
}
var DiagramToolBar = kendo.Observable.extend({
init: function (diagram, options) {
kendo.Observable.fn.init.call(this);
this.diagram = diagram;
this.options = deepExtend({}, this.options, options);
this._tools = [];
this.createToolBar();
this.createTools();
this.appendTools();
if (this.options.modal) {
this.createPopup();
}
this.bind(this.events, options);
},
events: ['click'],
createPopup: function () {
this.container = $('
').append(this.element);
this._popup = this.container.kendoPopup({}).getKendoPopup();
},
appendTools: function () {
for (var i = 0; i < this._tools.length; i++) {
var tool = this._tools[i];
if (tool.buttons && tool.buttons.length || !defined(tool.buttons)) {
this._toolBar.add(tool);
}
}
},
createToolBar: function () {
this.element = $('
');
this._toolBar = this.element.kendoToolBar({
click: proxy(this.click, this),
resizable: false
}).getKendoToolBar();
this.element.css('border', 'none');
},
createTools: function () {
for (var i = 0; i < this.options.tools.length; i++) {
this.createTool(this.options.tools[i]);
}
},
createTool: function (tool) {
var toolName = (isPlainObject(tool) ? tool.name : tool) + 'Tool';
if (this[toolName]) {
this[toolName](tool);
} else {
this._tools.push(tool);
}
},
showAt: function (point) {
if (this._popup) {
this._popup.open(point.x, point.y);
}
},
hide: function () {
if (this._popup) {
this._popup.close();
}
},
newGroup: function () {
return {
type: 'buttonGroup',
buttons: []
};
},
editTool: function () {
this._tools.push({
spriteCssClass: 'k-icon k-i-pencil',
showText: 'overflow',
type: 'button',
text: 'Edit',
attributes: this._setAttributes({ action: 'edit' })
});
},
deleteTool: function () {
this._tools.push({
spriteCssClass: 'k-icon k-i-close',
showText: 'overflow',
type: 'button',
text: 'Delete',
attributes: this._setAttributes({ action: 'delete' })
});
},
rotateAnticlockwiseTool: function (options) {
this._appendGroup('rotate');
this._rotateGroup.buttons.push({
spriteCssClass: 'k-icon k-i-rotateccw',
showText: 'overflow',
text: 'RotateAnticlockwise',
group: 'rotate',
attributes: this._setAttributes({
action: 'rotateAnticlockwise',
step: options.step
})
});
},
rotateClockwiseTool: function (options) {
this._appendGroup('rotate');
this._rotateGroup.buttons.push({
spriteCssClass: 'k-icon k-i-rotatecw',
attributes: this._setAttributes({
action: 'rotateClockwise',
step: options.step
}),
showText: 'overflow',
text: 'RotateClockwise',
group: 'rotate'
});
},
createShapeTool: function () {
this._appendGroup('create');
this._createGroup.buttons.push({
spriteCssClass: 'k-icon k-i-shape',
showText: 'overflow',
text: 'CreateShape',
group: 'create',
attributes: this._setAttributes({ action: 'createShape' })
});
},
createConnectionTool: function () {
this._appendGroup('create');
this._createGroup.buttons.push({
spriteCssClass: 'k-icon k-i-connector',
showText: 'overflow',
text: 'CreateConnection',
group: 'create',
attributes: this._setAttributes({ action: 'createConnection' })
});
},
undoTool: function () {
this._appendGroup('history');
this._historyGroup.buttons.push({
spriteCssClass: 'k-icon k-i-undo',
showText: 'overflow',
text: 'Undo',
group: 'history',
attributes: this._setAttributes({ action: 'undo' })
});
},
redoTool: function () {
this._appendGroup('history');
this._historyGroup.buttons.push({
spriteCssClass: 'k-icon k-i-redo',
showText: 'overflow',
text: 'Redo',
group: 'history',
attributes: this._setAttributes({ action: 'redo' })
});
},
_appendGroup: function (name) {
var prop = '_' + name + 'Group';
if (!this[prop]) {
this[prop] = this.newGroup();
this._tools.push(this[prop]);
}
},
_setAttributes: function (attributes) {
var attr = {};
if (attributes.action) {
attr[kendo.attr('action')] = attributes.action;
}
if (attributes.step) {
attr[kendo.attr('step')] = attributes.step;
}
return attr;
},
_getAttributes: function (element) {
var attr = {};
var action = element.attr(kendo.attr('action'));
if (action) {
attr.action = action;
}
var step = element.attr(kendo.attr('step'));
if (step) {
attr.step = step;
}
return attr;
},
click: function (e) {
var attributes = this._getAttributes($(e.target));
var action = attributes.action;
if (action) {
this[action](attributes);
}
this.trigger('click', this.eventData(action));
},
eventData: function (action) {
var element = this.selectedElements(), shapes = [], connections = [];
if (element instanceof Shape) {
shapes.push(element);
} else {
connections.push(element);
}
return {
shapes: shapes,
connections: connections,
action: action
};
},
'delete': function () {
var diagram = this.diagram;
var toRemove = diagram._triggerRemove(this.selectedElements());
if (toRemove.length) {
this.diagram.remove(toRemove, true);
this.diagram._syncChanges();
}
},
edit: function () {
this.diagram.edit(this.selectedElements()[0]);
},
rotateClockwise: function (options) {
var angle = parseFloat(options.step || 90);
this._rotate(angle);
},
rotateAnticlockwise: function (options) {
var angle = parseFloat(options.step || 90);
this._rotate(-angle);
},
_rotate: function (angle) {
var adorner = this.diagram._resizingAdorner;
adorner.angle(adorner.angle() + angle);
adorner.rotate();
},
selectedElements: function () {
return this.diagram.select();
},
createShape: function () {
this.diagram.createShape();
},
createConnection: function () {
this.diagram.createConnection();
},
undo: function () {
this.diagram.undo();
},
redo: function () {
this.diagram.redo();
},
destroy: function () {
this.diagram = null;
this.element = null;
this.options = null;
if (this._toolBar) {
this._toolBar.destroy();
}
if (this._popup) {
this._popup.destroy();
}
}
});
var Editor = kendo.Observable.extend({
init: function (element, options) {
kendo.Observable.fn.init.call(this);
this.options = extend(true, {}, this.options, options);
this.element = element;
this.model = this.options.model;
this.fields = this._getFields();
this._initContainer();
this.createEditable();
},
options: { editors: {} },
_initContainer: function () {
this.wrapper = this.element;
},
createEditable: function () {
var options = this.options;
this.editable = new kendo.ui.Editable(this.wrapper, {
fields: this.fields,
target: options.target,
clearContainer: false,
model: this.model
});
},
_isEditable: function (field) {
return this.model.editable && this.model.editable(field);
},
_getFields: function () {
var fields = [];
var modelFields = this.model.fields;
for (var field in modelFields) {
var result = {};
if (this._isEditable(field)) {
var editor = this.options.editors[field];
if (editor) {
result.editor = editor;
}
result.field = field;
fields.push(result);
}
}
return fields;
},
end: function () {
return this.editable.end();
},
destroy: function () {
this.editable.destroy();
this.editable.element.find('[' + kendo.attr('container-for') + ']').empty();
this.model = this.wrapper = this.element = this.columns = this.editable = null;
}
});
var PopupEditor = Editor.extend({
init: function (element, options) {
Editor.fn.init.call(this, element, options);
this.bind(this.events, this.options);
this.open();
},
events: [
'update',
'cancel'
],
options: {
window: {
modal: true,
resizable: false,
draggable: true,
title: 'Edit',
visible: false
}
},
_initContainer: function () {
var that = this;
this.wrapper = $('').attr(kendo.attr('uid'), this.model.uid);
var formContent = '';
if (this.options.template) {
formContent += this._renderTemplate();
this.fields = [];
} else {
formContent += this._renderFields();
}
formContent += this._renderButtons();
this.wrapper.append($('
').append(formContent));
this.window = new kendo.ui.Window(this.wrapper.appendTo(this.element), this.options.window);
this.window.bind('close', function (e) {
if (e.userTriggered) {
e.sender.element.focus();
that._cancelClick(e);
}
});
this._attachButtonEvents();
},
_renderTemplate: function () {
var template = this.options.template;
if (typeof template === 'string') {
template = window.unescape(template);
}
template = kendo.template(template)(this.model);
return template;
},
_renderFields: function () {
var form = '';
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
form += '
';
if (this._isEditable(field.field)) {
form += '
';
}
}
return form;
},
_renderButtons: function () {
var form = '
';
form += this._createButton('update');
form += this._createButton('cancel');
form += '
';
return form;
},
_createButton: function (name) {
return kendo.template(BUTTON_TEMPLATE)(defaultButtons[name]);
},
_attachButtonEvents: function () {
this._cancelClickHandler = proxy(this._cancelClick, this);
this.window.element.on(CLICK + NS, 'a.k-diagram-cancel', this._cancelClickHandler);
this._updateClickHandler = proxy(this._updateClick, this);
this.window.element.on(CLICK + NS, 'a.k-diagram-update', this._updateClickHandler);
},
_updateClick: function (e) {
e.preventDefault();
this.trigger('update');
},
_cancelClick: function (e) {
e.preventDefault();
this.trigger('cancel');
},
open: function () {
this.window.center().open();
},
close: function () {
this.window.bind('deactivate', proxy(this.destroy, this)).close();
},
destroy: function () {
this.window.close().destroy();
this.window.element.off(CLICK + NS, 'a.k-diagram-cancel', this._cancelClickHandler);
this.window.element.off(CLICK + NS, 'a.k-diagram-update', this._updateClickHandler);
this._cancelClickHandler = null;
this._editUpdateClickHandler = null;
this.window = null;
Editor.fn.destroy.call(this);
}
});
function connectionSelector(container, options) {
var model = this.dataSource.reader.model;
if (model) {
var textField = model.fn.fields.text ? 'text' : model.idField;
$('
').appendTo(container).kendoDropDownList({
dataValueField: model.idField,
dataTextField: textField,
dataSource: this.dataSource.data().toJSON(),
optionLabel: ' ',
valuePrimitive: true
});
}
}
function InactiveItem(dataItem) {
this.dataItem = dataItem;
this.callbacks = [];
}
InactiveItem.fn = InactiveItem.prototype = {
onActivate: function (callback) {
var deffered = $.Deferred();
this.callbacks.push({
callback: callback,
deferred: deffered
});
return deffered;
},
activate: function () {
var callbacks = this.callbacks;
var item;
for (var idx = 0; idx < callbacks.length; idx++) {
item = this.callbacks[idx];
item.callback(this.dataItem);
item.deferred.resolve();
}
this.callbacks = [];
}
};
function InactiveItemsCollection() {
this.items = {};
}
InactiveItemsCollection.fn = InactiveItemsCollection.prototype = {
add: function (items) {
for (var idx = 0; idx < items.length; idx++) {
this.items[items[idx].uid] = new InactiveItem(items[idx]);
}
},
forEach: function (callback) {
for (var uid in this.items) {
callback(this.items[uid]);
}
},
getByUid: function (uid) {
return this.items[uid];
},
remove: function (item) {
delete this.items[item.uid];
}
};
var QuadRoot = Class.extend({
init: function () {
this.shapes = [];
},
_add: function (shape, bounds) {
this.shapes.push({
bounds: bounds,
shape: shape
});
shape._quadNode = this;
},
insert: function (shape, bounds) {
this._add(shape, bounds);
},
remove: function (shape) {
var shapes = this.shapes;
var length = shapes.length;
for (var idx = 0; idx < length; idx++) {
if (shapes[idx].shape === shape) {
shapes.splice(idx, 1);
break;
}
}
},
hitTestRect: function (rect) {
var shapes = this.shapes;
var length = shapes.length;
for (var i = 0; i < length; i++) {
if (this._testRect(shapes[i].shape, rect)) {
return true;
}
}
},
_testRect: function (shape, rect) {
var angle = shape.rotate().angle;
var bounds = shape.bounds();
var hit;
if (!angle) {
hit = bounds.overlaps(rect);
} else {
hit = Intersect.rects(rect, bounds, -angle);
}
return hit;
}
});
var QuadNode = QuadRoot.extend({
init: function (rect) {
QuadRoot.fn.init.call(this);
this.children = [];
this.rect = rect;
},
inBounds: function (rect) {
var nodeRect = this.rect;
var nodeBottomRight = nodeRect.bottomRight();
var bottomRight = rect.bottomRight();
var inBounds = nodeRect.x <= rect.x && nodeRect.y <= rect.y && bottomRight.x <= nodeBottomRight.x && bottomRight.y <= nodeBottomRight.y;
return inBounds;
},
overlapsBounds: function (rect) {
return this.rect.overlaps(rect);
},
insert: function (shape, bounds) {
var inserted = false;
var children = this.children;
var length = children.length;
if (this.inBounds(bounds)) {
if (!length && this.shapes.length < 4) {
this._add(shape, bounds);
} else {
if (!length) {
this._initChildren();
}
for (var idx = 0; idx < children.length; idx++) {
if (children[idx].insert(shape, bounds)) {
inserted = true;
break;
}
}
if (!inserted) {
this._add(shape, bounds);
}
}
inserted = true;
}
return inserted;
},
_initChildren: function () {
var rect = this.rect, children = this.children, shapes = this.shapes, center = rect.center(), halfWidth = rect.width / 2, halfHeight = rect.height / 2, childIdx, shapeIdx;
children.push(new QuadNode(new Rect(rect.x, rect.y, halfWidth, halfHeight)), new QuadNode(new Rect(center.x, rect.y, halfWidth, halfHeight)), new QuadNode(new Rect(rect.x, center.y, halfWidth, halfHeight)), new QuadNode(new Rect(center.x, center.y, halfWidth, halfHeight)));
for (shapeIdx = shapes.length - 1; shapeIdx >= 0; shapeIdx--) {
for (childIdx = 0; childIdx < children.length; childIdx++) {
if (children[childIdx].insert(shapes[shapeIdx].shape, shapes[shapeIdx].bounds)) {
shapes.splice(shapeIdx, 1);
break;
}
}
}
},
hitTestRect: function (rect) {
var idx;
var children = this.children;
var length = children.length;
var hit = false;
if (this.overlapsBounds(rect)) {
if (QuadRoot.fn.hitTestRect.call(this, rect)) {
hit = true;
} else {
for (idx = 0; idx < length; idx++) {
if (children[idx].hitTestRect(rect)) {
hit = true;
break;
}
}
}
}
return hit;
}
});
var ShapesQuadTree = Class.extend({
ROOT_SIZE: 1000,
init: function (diagram) {
var boundsChangeHandler = proxy(this._boundsChange, this);
diagram.bind(ITEMBOUNDSCHANGE, boundsChangeHandler);
diagram.bind(ITEMROTATE, boundsChangeHandler);
this.initRoots();
},
initRoots: function () {
this.rootMap = {};
this.root = new QuadRoot();
},
clear: function () {
this.initRoots();
},
_boundsChange: function (e) {
if (e.item._quadNode) {
e.item._quadNode.remove(e.item);
}
this.insert(e.item);
},
insert: function (shape) {
var bounds = shape.bounds(ROTATED);
var rootSize = this.ROOT_SIZE;
var sectors = this.getSectors(bounds);
var x = sectors[0][0];
var y = sectors[1][0];
if (this.inRoot(sectors)) {
this.root.insert(shape, bounds);
} else {
if (!this.rootMap[x]) {
this.rootMap[x] = {};
}
if (!this.rootMap[x][y]) {
this.rootMap[x][y] = new QuadNode(new Rect(x * rootSize, y * rootSize, rootSize, rootSize));
}
this.rootMap[x][y].insert(shape, bounds);
}
},
remove: function (shape) {
if (shape._quadNode) {
shape._quadNode.remove(shape);
}
},
inRoot: function (sectors) {
return sectors[0].length > 1 || sectors[1].length > 1;
},
getSectors: function (rect) {
var rootSize = this.ROOT_SIZE;
var bottomRight = rect.bottomRight();
var bottomX = math.floor(bottomRight.x / rootSize);
var bottomY = math.floor(bottomRight.y / rootSize);
var sectors = [
[],
[]
];
for (var x = math.floor(rect.x / rootSize); x <= bottomX; x++) {
sectors[0].push(x);
}
for (var y = math.floor(rect.y / rootSize); y <= bottomY; y++) {
sectors[1].push(y);
}
return sectors;
},
hitTestRect: function (rect) {
var sectors = this.getSectors(rect);
var xIdx, yIdx, x, y;
var root;
if (this.root.hitTestRect(rect)) {
return true;
}
for (xIdx = 0; xIdx < sectors[0].length; xIdx++) {
x = sectors[0][xIdx];
for (yIdx = 0; yIdx < sectors[1].length; yIdx++) {
y = sectors[1][yIdx];
root = (this.rootMap[x] || {})[y];
if (root && root.hitTestRect(rect)) {
return true;
}
}
}
return false;
}
});
function cloneDataItem(dataItem) {
var result = dataItem;
if (dataItem instanceof kendo.data.Model) {
result = dataItem.toJSON();
result[dataItem.idField] = dataItem._defaultId;
}
return result;
}
function splitDiagramElements(elements) {
var connections = [];
var shapes = [];
var element, idx;
for (idx = 0; idx < elements.length; idx++) {
element = elements[idx];
if (element instanceof Shape) {
shapes.push(element);
} else {
connections.push(element);
}
}
return {
shapes: shapes,
connections: connections
};
}
function createModel(dataSource, model) {
if (dataSource.reader.model) {
return new dataSource.reader.model(model);
}
return new kendo.data.ObservableObject(model);
}
function clearField(field, model) {
if (defined(model[field])) {
model.set(field, null);
}
}
function copyDefaultOptions(mainOptions, elementOptions, fields) {
var field;
for (var idx = 0; idx < fields.length; idx++) {
field = fields[idx];
if (elementOptions && !defined(elementOptions[field])) {
elementOptions[field] = mainOptions[field];
}
}
}
function translateToOrigin(visual) {
var bbox = visual.drawingContainer().clippedBBox(null);
if (bbox.origin.x !== 0 || bbox.origin.y !== 0) {
visual.position(-bbox.origin.x, -bbox.origin.y);
}
}
dataviz.ui.plugin(Diagram);
deepExtend(diagram, {
Shape: Shape,
Connection: Connection,
Connector: Connector,
DiagramToolBar: DiagramToolBar,
QuadNode: QuadNode,
QuadRoot: QuadRoot,
ShapesQuadTree: ShapesQuadTree,
PopupEditor: PopupEditor
});
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dataviz.diagram', [
'kendo.data',
'kendo.draganddrop',
'kendo.userevents',
'kendo.mobile.scroller',
'kendo.drawing',
'dataviz/diagram/utils',
'dataviz/diagram/math',
'dataviz/diagram/svg',
'dataviz/diagram/services',
'dataviz/diagram/layout',
'dataviz/diagram/dom'
], f);
}(function () {
var __meta__ = {
id: 'dataviz.diagram',
name: 'Diagram',
category: 'dataviz',
description: 'The Kendo DataViz Diagram ',
depends: [
'data',
'userevents',
'mobile.scroller',
'draganddrop',
'drawing',
'dataviz.core',
'dataviz.themes',
'toolbar'
],
features: [
{
id: 'dataviz.diagram-pdf-export',
name: 'PDF export',
description: 'Export Diagram as PDF',
depends: ['pdf']
},
{
id: 'dataviz.diagram-editing',
name: 'Editing',
description: 'Support for model editing',
depends: [
'editable',
'window',
'dropdownlist'
]
}
]
};
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dataviz.treemap', [
'kendo.data',
'kendo.userevents',
'kendo.dataviz.themes'
], f);
}(function () {
var __meta__ = {
id: 'dataviz.treeMap',
name: 'TreeMap',
category: 'dataviz',
description: 'The Kendo DataViz TreeMap',
depends: [
'data',
'userevents',
'dataviz.themes'
]
};
(function ($, undefined) {
var math = Math, proxy = $.proxy, isArray = $.isArray, kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, template = kendo.template, deepExtend = kendo.deepExtend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, getter = kendo.getter, dataviz = kendo.dataviz;
var NS = '.kendoTreeMap', CHANGE = 'change', DATA_BOUND = 'dataBound', ITEM_CREATED = 'itemCreated', MAX_VALUE = Number.MAX_VALUE, MOUSEOVER_NS = 'mouseover' + NS, MOUSELEAVE_NS = 'mouseleave' + NS, UNDEFINED = 'undefined';
var TreeMap = Widget.extend({
init: function (element, options) {
kendo.destroy(element);
$(element).empty();
Widget.fn.init.call(this, element, options);
this.wrapper = this.element;
this._initTheme(this.options);
this.element.addClass('k-widget k-treemap');
this._setLayout();
this._originalOptions = deepExtend({}, this.options);
this._initDataSource();
this._attachEvents();
kendo.notify(this, dataviz.ui);
},
options: {
name: 'TreeMap',
theme: 'default',
autoBind: true,
textField: 'text',
valueField: 'value',
colorField: 'color'
},
events: [
DATA_BOUND,
ITEM_CREATED
],
_initTheme: function (options) {
var that = this, themes = dataviz.ui.themes || {}, themeName = ((options || {}).theme || '').toLowerCase(), themeOptions = (themes[themeName] || {}).treeMap;
that.options = deepExtend({}, themeOptions, options);
},
_attachEvents: function () {
this.element.on(MOUSEOVER_NS, proxy(this._mouseover, this)).on(MOUSELEAVE_NS, proxy(this._mouseleave, this));
this._resizeHandler = proxy(this.resize, this, false);
kendo.onResize(this._resizeHandler);
},
_setLayout: function () {
if (this.options.type === 'horizontal') {
this._layout = new SliceAndDice(false);
this._view = new SliceAndDiceView(this, this.options);
} else if (this.options.type === 'vertical') {
this._layout = new SliceAndDice(true);
this._view = new SliceAndDiceView(this, this.options);
} else {
this._layout = new Squarified();
this._view = new SquarifiedView(this, this.options);
}
},
_initDataSource: function () {
var that = this, options = that.options, dataSource = options.dataSource;
that._dataChangeHandler = proxy(that._onDataChange, that);
that.dataSource = HierarchicalDataSource.create(dataSource).bind(CHANGE, that._dataChangeHandler);
if (dataSource) {
if (that.options.autoBind) {
that.dataSource.fetch();
}
}
},
setDataSource: function (dataSource) {
var that = this;
that.dataSource.unbind(CHANGE, that._dataChangeHandler);
that.dataSource = dataSource.bind(CHANGE, that._dataChangeHandler);
if (dataSource) {
if (that.options.autoBind) {
that.dataSource.fetch();
}
}
},
_onDataChange: function (e) {
var node = e.node;
var items = e.items;
var options = this.options;
var item, i;
if (!node) {
this._cleanItems();
this.element.empty();
item = this._wrapItem(items[0]);
this._layout.createRoot(item, this.element.outerWidth(), this.element.outerHeight(), this.options.type === 'vertical');
this._view.createRoot(item);
this._root = item;
this._colorIdx = 0;
} else {
if (items.length) {
var root = this._getByUid(node.uid);
root.children = [];
items = new kendo.data.Query(items)._sortForGrouping(options.valueField, 'desc');
for (i = 0; i < items.length; i++) {
item = items[i];
root.children.push(this._wrapItem(item));
}
var htmlSize = this._view.htmlSize(root);
this._layout.compute(root.children, root.coord, htmlSize);
this._setColors(root.children);
this._view.render(root);
}
}
for (i = 0; i < items.length; i++) {
items[i].load();
}
if (node) {
this.trigger(DATA_BOUND, { node: node });
}
},
_cleanItems: function () {
var that = this;
that.angular('cleanup', function () {
return { elements: that.element.find('.k-leaf div,.k-treemap-title,.k-treemap-title-vertical') };
});
},
_setColors: function (items) {
var colors = this.options.colors;
var colorIdx = this._colorIdx;
var color = colors[colorIdx % colors.length];
var colorRange, item;
if (isArray(color)) {
colorRange = colorsByLength(color[0], color[1], items.length);
}
var leafNodes = false;
for (var i = 0; i < items.length; i++) {
item = items[i];
if (!defined(item.color)) {
if (colorRange) {
item.color = colorRange[i];
} else {
item.color = color;
}
}
if (!item.dataItem.hasChildren) {
leafNodes = true;
}
}
if (leafNodes) {
this._colorIdx++;
}
},
_contentSize: function (root) {
this.view.renderHeight(root);
},
_wrapItem: function (item) {
var wrap = {};
if (defined(this.options.valueField)) {
wrap.value = getField(this.options.valueField, item);
}
if (defined(this.options.colorField)) {
wrap.color = getField(this.options.colorField, item);
}
if (defined(this.options.textField)) {
wrap.text = getField(this.options.textField, item);
}
wrap.level = item.level();
wrap.dataItem = item;
return wrap;
},
_getByUid: function (uid) {
var items = [this._root];
var item;
while (items.length) {
item = items.pop();
if (item.dataItem.uid === uid) {
return item;
}
if (item.children) {
items = items.concat(item.children);
}
}
},
dataItem: function (node) {
var uid = $(node).attr(kendo.attr('uid')), dataSource = this.dataSource;
return dataSource && dataSource.getByUid(uid);
},
findByUid: function (uid) {
return this.element.find('.k-treemap-tile[' + kendo.attr('uid') + '=\'' + uid + '\']');
},
_mouseover: function (e) {
var target = $(e.target);
if (target.hasClass('k-leaf')) {
this._removeActiveState();
target.removeClass('k-state-hover').addClass('k-state-hover');
}
},
_removeActiveState: function () {
this.element.find('.k-state-hover').removeClass('k-state-hover');
},
_mouseleave: function () {
this._removeActiveState();
},
destroy: function () {
Widget.fn.destroy.call(this);
this.element.off(NS);
if (this.dataSource) {
this.dataSource.unbind(CHANGE, this._dataChangeHandler);
}
this._root = null;
kendo.unbindResize(this._resizeHandler);
kendo.destroy(this.element);
},
items: function () {
return $();
},
getSize: function () {
return kendo.dimensions(this.element);
},
_resize: function () {
var root = this._root;
if (root) {
var element = this.element;
var rootElement = element.children();
root.coord.width = element.outerWidth();
root.coord.height = element.outerHeight();
rootElement.css({
width: root.coord.width,
height: root.coord.height
});
this._resizeItems(root, rootElement);
}
},
_resizeItems: function (root, element) {
if (root.children && root.children.length) {
var elements = element.children('.k-treemap-wrap').children();
var child, childElement;
this._layout.compute(root.children, root.coord, { text: this._view.titleSize(root, element) });
for (var idx = 0; idx < root.children.length; idx++) {
child = root.children[idx];
childElement = elements.filter('[' + kendo.attr('uid') + '=\'' + child.dataItem.uid + '\']');
this._view.setItemSize(child, childElement);
this._resizeItems(child, childElement);
}
}
},
setOptions: function (options) {
var dataSource = options.dataSource;
options.dataSource = undefined;
this._originalOptions = deepExtend(this._originalOptions, options);
this.options = deepExtend({}, this._originalOptions);
this._setLayout();
this._initTheme(this.options);
Widget.fn._setEvents.call(this, options);
if (dataSource) {
this.setDataSource(HierarchicalDataSource.create(dataSource));
}
if (this.options.autoBind) {
this.dataSource.fetch();
}
}
});
var Squarified = Class.extend({
createRoot: function (root, width, height) {
root.coord = {
width: width,
height: height,
top: 0,
left: 0
};
},
leaf: function (tree) {
return !tree.children;
},
layoutChildren: function (items, coord) {
var parentArea = coord.width * coord.height;
var totalArea = 0, itemsArea = [], i;
for (i = 0; i < items.length; i++) {
itemsArea[i] = parseFloat(items[i].value);
totalArea += itemsArea[i];
}
for (i = 0; i < itemsArea.length; i++) {
items[i].area = parentArea * itemsArea[i] / totalArea;
}
var minimumSideValue = this.layoutHorizontal() ? coord.height : coord.width;
var firstElement = [items[0]];
var tail = items.slice(1);
this.squarify(tail, firstElement, minimumSideValue, coord);
},
squarify: function (tail, initElement, width, coord) {
this.computeDim(tail, initElement, width, coord);
},
computeDim: function (tail, initElement, width, coord) {
if (tail.length + initElement.length == 1) {
var element = tail.length == 1 ? tail : initElement;
this.layoutLast(element, width, coord);
return;
}
if (tail.length >= 2 && initElement.length === 0) {
initElement = [tail[0]];
tail = tail.slice(1);
}
if (tail.length === 0) {
if (initElement.length > 0) {
this.layoutRow(initElement, width, coord);
}
return;
}
var firstElement = tail[0];
if (this.worstAspectRatio(initElement, width) >= this.worstAspectRatio([firstElement].concat(initElement), width)) {
this.computeDim(tail.slice(1), initElement.concat([firstElement]), width, coord);
} else {
var newCoords = this.layoutRow(initElement, width, coord);
this.computeDim(tail, [], newCoords.dim, newCoords);
}
},
layoutLast: function (items, w, coord) {
items[0].coord = coord;
},
layoutRow: function (items, width, coord) {
if (this.layoutHorizontal()) {
return this.layoutV(items, width, coord);
} else {
return this.layoutH(items, width, coord);
}
},
orientation: 'h',
layoutVertical: function () {
return this.orientation === 'v';
},
layoutHorizontal: function () {
return this.orientation === 'h';
},
layoutChange: function () {
this.orientation = this.layoutVertical() ? 'h' : 'v';
},
worstAspectRatio: function (items, width) {
if (!items || items.length === 0) {
return MAX_VALUE;
}
var areaSum = 0, maxArea = 0, minArea = MAX_VALUE;
for (var i = 0; i < items.length; i++) {
var area = items[i].area;
areaSum += area;
minArea = minArea < area ? minArea : area;
maxArea = maxArea > area ? maxArea : area;
}
return math.max(width * width * maxArea / (areaSum * areaSum), areaSum * areaSum / (width * width * minArea));
},
compute: function (children, rootCoord, htmlSize) {
if (!(rootCoord.width >= rootCoord.height && this.layoutHorizontal())) {
this.layoutChange();
}
if (children && children.length > 0) {
var newRootCoord = {
width: rootCoord.width,
height: rootCoord.height - htmlSize.text,
top: 0,
left: 0
};
this.layoutChildren(children, newRootCoord);
}
},
layoutV: function (items, width, coord) {
var totalArea = this._totalArea(items), top = 0;
width = round(totalArea / width);
for (var i = 0; i < items.length; i++) {
var height = round(items[i].area / width);
items[i].coord = {
height: height,
width: width,
top: coord.top + top,
left: coord.left
};
top += height;
}
var ans = {
height: coord.height,
width: coord.width - width,
top: coord.top,
left: coord.left + width
};
ans.dim = math.min(ans.width, ans.height);
if (ans.dim != ans.height) {
this.layoutChange();
}
return ans;
},
layoutH: function (items, width, coord) {
var totalArea = this._totalArea(items);
var height = round(totalArea / width), top = coord.top, left = 0;
for (var i = 0; i < items.length; i++) {
items[i].coord = {
height: height,
width: round(items[i].area / height),
top: top,
left: coord.left + left
};
left += items[i].coord.width;
}
var ans = {
height: coord.height - height,
width: coord.width,
top: coord.top + height,
left: coord.left
};
ans.dim = math.min(ans.width, ans.height);
if (ans.dim != ans.width) {
this.layoutChange();
}
return ans;
},
_totalArea: function (items) {
var total = 0;
for (var i = 0; i < items.length; i++) {
total += items[i].area;
}
return total;
}
});
var SquarifiedView = Class.extend({
init: function (treeMap, options) {
this.options = deepExtend({}, this.options, options);
this.treeMap = treeMap;
this.element = $(treeMap.element);
this.offset = 0;
},
titleSize: function (item, element) {
var text = element.children('.k-treemap-title');
return text.height();
},
htmlSize: function (root) {
var rootElement = this._getByUid(root.dataItem.uid);
var htmlSize = { text: 0 };
if (root.children) {
this._clean(rootElement);
var text = this._getText(root);
if (text) {
var title = this._createTitle(root);
rootElement.append(title);
this._compile(title, root.dataItem);
htmlSize.text = title.height();
}
rootElement.append(this._createWrap());
this.offset = (rootElement.outerWidth() - rootElement.innerWidth()) / 2;
}
return htmlSize;
},
_compile: function (element, dataItem) {
this.treeMap.angular('compile', function () {
return {
elements: element,
data: [{ dataItem: dataItem }]
};
});
},
_getByUid: function (uid) {
return this.element.find('.k-treemap-tile[' + kendo.attr('uid') + '=\'' + uid + '\']');
},
render: function (root) {
var rootElement = this._getByUid(root.dataItem.uid);
var children = root.children;
if (children) {
var rootWrap = rootElement.find('.k-treemap-wrap');
for (var i = 0; i < children.length; i++) {
var leaf = children[i];
var htmlElement = this._createLeaf(leaf);
rootWrap.append(htmlElement);
this._compile(htmlElement.children(), leaf.dataItem);
this.treeMap.trigger(ITEM_CREATED, { element: htmlElement });
}
}
},
createRoot: function (root) {
var htmlElement = this._createLeaf(root);
this.element.append(htmlElement);
this._compile(htmlElement.children(), root.dataItem);
this.treeMap.trigger(ITEM_CREATED, { element: htmlElement });
},
_clean: function (root) {
this.treeMap.angular('cleanup', function () {
return { elements: root.children(':not(.k-treemap-wrap)') };
});
root.css('background-color', '');
root.removeClass('k-leaf');
root.removeClass('k-inverse');
root.empty();
},
_createLeaf: function (item) {
return this._createTile(item).css('background-color', item.color).addClass('k-leaf').toggleClass('k-inverse', this._tileColorBrightness(item) > 180).append($('
').html(this._getText(item)));
},
_createTile: function (item) {
var tile = $('
');
this.setItemSize(item, tile);
if (defined(item.dataItem) && defined(item.dataItem.uid)) {
tile.attr(kendo.attr('uid'), item.dataItem.uid);
}
return tile;
},
_itemCoordinates: function (item) {
var coordinates = {
width: item.coord.width,
height: item.coord.height,
left: item.coord.left,
top: item.coord.top
};
if (coordinates.left && this.offset) {
coordinates.width += this.offset * 2;
} else {
coordinates.width += this.offset;
}
if (coordinates.top) {
coordinates.height += this.offset * 2;
} else {
coordinates.height += this.offset;
}
return coordinates;
},
setItemSize: function (item, element) {
var coordinates = this._itemCoordinates(item);
element.css({
width: coordinates.width,
height: coordinates.height,
left: coordinates.left,
top: coordinates.top
});
},
_getText: function (item) {
var text = item.text;
if (this.options.template) {
text = this._renderTemplate(item);
}
return text;
},
_renderTemplate: function (item) {
var titleTemplate = template(this.options.template);
return titleTemplate({
dataItem: item.dataItem,
text: item.text
});
},
_createTitle: function (item) {
return $('
').append($('
').html(this._getText(item)));
},
_createWrap: function () {
return $('
');
},
_tileColorBrightness: function (item) {
return colorBrightness(item.color);
}
});
var SliceAndDice = Class.extend({
createRoot: function (root, width, height, vertical) {
root.coord = {
width: width,
height: height,
top: 0,
left: 0
};
root.vertical = vertical;
},
init: function (vertical) {
this.vertical = vertical;
this.quotient = vertical ? 1 : 0;
},
compute: function (children, rootCoord, htmlSize) {
if (children.length > 0) {
var width = rootCoord.width;
var height = rootCoord.height;
if (this.vertical) {
height -= htmlSize.text;
} else {
width -= htmlSize.text;
}
var newRootCoord = {
width: width,
height: height,
top: 0,
left: 0
};
this.layoutChildren(children, newRootCoord);
}
},
layoutChildren: function (items, coord) {
var parentArea = coord.width * coord.height;
var totalArea = 0;
var itemsArea = [];
var i;
for (i = 0; i < items.length; i++) {
var item = items[i];
itemsArea[i] = parseFloat(items[i].value);
totalArea += itemsArea[i];
item.vertical = this.vertical;
}
for (i = 0; i < itemsArea.length; i++) {
items[i].area = parentArea * itemsArea[i] / totalArea;
}
this.sliceAndDice(items, coord);
},
sliceAndDice: function (items, coord) {
var totalArea = this._totalArea(items);
if (items[0].level % 2 === this.quotient) {
this.layoutHorizontal(items, coord, totalArea);
} else {
this.layoutVertical(items, coord, totalArea);
}
},
layoutHorizontal: function (items, coord, totalArea) {
var left = 0;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var width = item.area / (totalArea / coord.width);
item.coord = {
height: coord.height,
width: width,
top: coord.top,
left: coord.left + left
};
left += width;
}
},
layoutVertical: function (items, coord, totalArea) {
var top = 0;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var height = item.area / (totalArea / coord.height);
item.coord = {
height: height,
width: coord.width,
top: coord.top + top,
left: coord.left
};
top += height;
}
},
_totalArea: function (items) {
var total = 0;
for (var i = 0; i < items.length; i++) {
total += items[i].area;
}
return total;
}
});
var SliceAndDiceView = SquarifiedView.extend({
htmlSize: function (root) {
var rootElement = this._getByUid(root.dataItem.uid);
var htmlSize = {
text: 0,
offset: 0
};
if (root.children) {
this._clean(rootElement);
var text = this._getText(root);
if (text) {
var title = this._createTitle(root);
rootElement.append(title);
this._compile(title, root.dataItem);
if (root.vertical) {
htmlSize.text = title.height();
} else {
htmlSize.text = title.width();
}
}
rootElement.append(this._createWrap());
this.offset = (rootElement.outerWidth() - rootElement.innerWidth()) / 2;
}
return htmlSize;
},
titleSize: function (item, element) {
var size;
if (item.vertical) {
size = element.children('.k-treemap-title').height();
} else {
size = element.children('.k-treemap-title-vertical').width();
}
return size;
},
_createTitle: function (item) {
var title;
if (item.vertical) {
title = $('
');
} else {
title = $('
');
}
return title.append($('
').html(this._getText(item)));
}
});
function getField(field, row) {
if (row === null) {
return row;
}
var get = getter(field, true);
return get(row);
}
function defined(value) {
return typeof value !== UNDEFINED;
}
function colorsByLength(min, max, length) {
var minRGBtoDecimal = rgbToDecimal(min);
var maxRGBtoDecimal = rgbToDecimal(max);
var isDarker = colorBrightness(min) - colorBrightness(max) < 0;
var colors = [];
colors.push(min);
for (var i = 0; i < length; i++) {
var rgbColor = {
r: colorByIndex(minRGBtoDecimal.r, maxRGBtoDecimal.r, i, length, isDarker),
g: colorByIndex(minRGBtoDecimal.g, maxRGBtoDecimal.g, i, length, isDarker),
b: colorByIndex(minRGBtoDecimal.b, maxRGBtoDecimal.b, i, length, isDarker)
};
colors.push(buildColorFromRGB(rgbColor));
}
colors.push(max);
return colors;
}
function colorByIndex(min, max, index, length, isDarker) {
var minColor = math.min(math.abs(min), math.abs(max));
var maxColor = math.max(math.abs(min), math.abs(max));
var step = (maxColor - minColor) / (length + 1);
var currentStep = step * (index + 1);
var color;
if (isDarker) {
color = minColor + currentStep;
} else {
color = maxColor - currentStep;
}
return color;
}
function buildColorFromRGB(color) {
return '#' + decimalToRgb(color.r) + decimalToRgb(color.g) + decimalToRgb(color.b);
}
function rgbToDecimal(color) {
color = color.replace('#', '');
var rgbColor = colorToRGB(color);
return {
r: rgbToHex(rgbColor.r),
g: rgbToHex(rgbColor.g),
b: rgbToHex(rgbColor.b)
};
}
function decimalToRgb(number) {
var result = math.round(number).toString(16).toUpperCase();
if (result.length === 1) {
result = '0' + result;
}
return result;
}
function colorToRGB(color) {
var colorLength = color.length;
var rgbColor = {};
if (colorLength === 3) {
rgbColor.r = color[0];
rgbColor.g = color[1];
rgbColor.b = color[2];
} else {
rgbColor.r = color.substring(0, 2);
rgbColor.g = color.substring(2, 4);
rgbColor.b = color.substring(4, 6);
}
return rgbColor;
}
function rgbToHex(rgb) {
return parseInt(rgb.toString(16), 16);
}
function colorBrightness(color) {
var brightness = 0;
if (color) {
color = rgbToDecimal(color);
brightness = math.sqrt(0.241 * color.r * color.r + 0.691 * color.g * color.g + 0.068 * color.b * color.b);
}
return brightness;
}
function round(value) {
var power = math.pow(10, 4);
return math.round(value * power) / power;
}
dataviz.ui.plugin(TreeMap);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.angular', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'angular',
name: 'AngularJS Directives',
category: 'framework',
description: 'Adds Kendo UI for AngularJS directives',
depends: ['core'],
defer: true
};
(function ($, angular, undefined) {
'use strict';
if (!angular || !angular.injector) {
return;
}
var module = angular.module('kendo.directives', []), $injector = angular.injector(['ng']), $parse = $injector.get('$parse'), $timeout = $injector.get('$timeout'), $defaultCompile, $log = $injector.get('$log');
function withoutTimeout(f) {
var save = $timeout;
try {
$timeout = function (f) {
return f();
};
return f();
} finally {
$timeout = save;
}
}
var OPTIONS_NOW;
var createDataSource = function () {
var types = {
TreeList: 'TreeListDataSource',
TreeView: 'HierarchicalDataSource',
Scheduler: 'SchedulerDataSource',
PanelBar: '$PLAIN',
Menu: '$PLAIN',
ContextMenu: '$PLAIN'
};
var toDataSource = function (dataSource, type) {
if (type == '$PLAIN') {
return dataSource;
}
return kendo.data[type].create(dataSource);
};
return function (scope, element, role, source) {
var type = types[role] || 'DataSource';
var current = scope.$eval(source);
var ds = toDataSource(current, type);
scope.$watch(source, function (mew) {
var widget = kendoWidgetInstance(element);
if (widget && typeof widget.setDataSource == 'function') {
if (mew !== current) {
var ds = toDataSource(mew, type);
widget.setDataSource(ds);
current = mew;
}
}
});
return ds;
};
}();
var ignoredAttributes = {
kDataSource: true,
kOptions: true,
kRebind: true,
kNgModel: true,
kNgDelay: true
};
var ignoredOwnProperties = {
name: true,
title: true,
style: true
};
function createWidget(scope, element, attrs, widget, origAttr, controllers) {
if (!(element instanceof jQuery)) {
throw new Error('The Kendo UI directives require jQuery to be available before AngularJS. Please include jquery before angular in the document.');
}
var kNgDelay = attrs.kNgDelay, delayValue = scope.$eval(kNgDelay);
controllers = controllers || [];
var ngModel = controllers[0], ngForm = controllers[1];
var ctor = $(element)[widget];
if (!ctor) {
window.console.error('Could not find: ' + widget);
return null;
}
var parsed = parseOptions(scope, element, attrs, widget, ctor);
var options = parsed.options;
if (parsed.unresolved.length) {
var promises = [];
for (var i = 0, len = parsed.unresolved.length; i < len; i++) {
var unresolved = parsed.unresolved[i];
var promise = $.Deferred(function (d) {
var unwatch = scope.$watch(unresolved.path, function (newValue) {
if (newValue !== undefined) {
unwatch();
d.resolve();
}
});
}).promise();
promises.push(promise);
}
$.when.apply(null, promises).then(createIt);
return;
}
if (kNgDelay && !delayValue) {
var root = scope.$root || scope;
var register = function () {
var unregister = scope.$watch(kNgDelay, function (newValue) {
if (newValue !== undefined) {
unregister();
element.removeAttr(attrs.$attr.kNgDelay);
kNgDelay = null;
$timeout(createIt);
}
});
};
if (/^\$(digest|apply)$/.test(root.$$phase)) {
register();
} else {
scope.$apply(register);
}
return;
} else {
return createIt();
}
function createIt() {
var originalElement;
if (attrs.kRebind) {
originalElement = $($(element)[0].cloneNode(true));
}
options = parseOptions(scope, element, attrs, widget, ctor).options;
if (element.is('select')) {
(function (options) {
if (options.length > 0) {
var first = $(options[0]);
if (!/\S/.test(first.text()) && /^\?/.test(first.val())) {
first.remove();
}
}
}(element[0].options));
}
var object = ctor.call(element, OPTIONS_NOW = options).data(widget);
exposeWidget(object, scope, attrs, widget, origAttr);
scope.$emit('kendoWidgetCreated', object);
var destroyRegister = destroyWidgetOnScopeDestroy(scope, object);
if (attrs.kRebind) {
setupRebind(object, scope, element, originalElement, attrs.kRebind, destroyRegister, attrs);
}
if (attrs.kNgDisabled) {
var kNgDisabled = attrs.kNgDisabled;
var isDisabled = scope.$eval(kNgDisabled);
if (isDisabled) {
object.enable(!isDisabled);
}
bindToKNgDisabled(object, scope, element, kNgDisabled);
}
if (attrs.kNgReadonly) {
var kNgReadonly = attrs.kNgReadonly;
var isReadonly = scope.$eval(kNgReadonly);
if (isReadonly) {
object.readonly(isReadonly);
}
bindToKNgReadonly(object, scope, element, kNgReadonly);
}
if (attrs.kNgModel) {
bindToKNgModel(object, scope, attrs.kNgModel);
}
if (ngModel) {
bindToNgModel(object, scope, element, ngModel, ngForm);
}
if (object) {
propagateClassToWidgetWrapper(object, element);
}
return object;
}
}
function parseOptions(scope, element, attrs, widget, ctor) {
var role = widget.replace(/^kendo/, '');
var unresolved = [];
var optionsPath = attrs.kOptions || attrs.options;
var optionsValue = scope.$eval(optionsPath);
if (optionsPath && optionsValue === undefined) {
unresolved.push({
option: 'options',
path: optionsPath
});
}
var options = angular.extend({}, attrs.defaultOptions, optionsValue);
function addOption(name, value) {
var scopeValue = angular.copy(scope.$eval(value));
if (scopeValue === undefined) {
unresolved.push({
option: name,
path: value
});
} else {
options[name] = scopeValue;
}
}
var widgetOptions = ctor.widget.prototype.options;
var widgetEvents = ctor.widget.prototype.events;
$.each(attrs, function (name, value) {
if (name === 'source' || name === 'kDataSource' || name === 'kScopeField' || name === 'scopeField') {
return;
}
var dataName = 'data' + name.charAt(0).toUpperCase() + name.slice(1);
if (name.indexOf('on') === 0) {
var eventKey = name.replace(/^on./, function (prefix) {
return prefix.charAt(2).toLowerCase();
});
if (widgetEvents.indexOf(eventKey) > -1) {
options[eventKey] = value;
}
}
if (widgetOptions.hasOwnProperty(dataName)) {
addOption(dataName, value);
} else if (widgetOptions.hasOwnProperty(name) && !ignoredOwnProperties[name]) {
addOption(name, value);
} else if (!ignoredAttributes[name]) {
var match = name.match(/^k(On)?([A-Z].*)/);
if (match) {
var optionName = match[2].charAt(0).toLowerCase() + match[2].slice(1);
if (match[1] && name != 'kOnLabel') {
options[optionName] = value;
} else {
if (name == 'kOnLabel') {
optionName = 'onLabel';
}
addOption(optionName, value);
}
}
}
});
var dataSource = attrs.kDataSource || attrs.source;
if (dataSource) {
options.dataSource = createDataSource(scope, element, role, dataSource);
}
options.$angular = [scope];
return {
options: options,
unresolved: unresolved
};
}
function bindToKNgDisabled(widget, scope, element, kNgDisabled) {
if (kendo.ui.PanelBar && widget instanceof kendo.ui.PanelBar || kendo.ui.Menu && widget instanceof kendo.ui.Menu) {
$log.warn('k-ng-disabled specified on a widget that does not have the enable() method: ' + widget.options.name);
return;
}
scope.$watch(kNgDisabled, function (newValue, oldValue) {
if (newValue != oldValue) {
widget.enable(!newValue);
}
});
}
function bindToKNgReadonly(widget, scope, element, kNgReadonly) {
if (typeof widget.readonly != 'function') {
$log.warn('k-ng-readonly specified on a widget that does not have the readonly() method: ' + widget.options.name);
return;
}
scope.$watch(kNgReadonly, function (newValue, oldValue) {
if (newValue != oldValue) {
widget.readonly(newValue);
}
});
}
function exposeWidget(widget, scope, attrs, kendoWidget, origAttr) {
if (attrs[origAttr]) {
var set = $parse(attrs[origAttr]).assign;
if (set) {
set(scope, widget);
} else {
throw new Error(origAttr + ' attribute used but expression in it is not assignable: ' + attrs[kendoWidget]);
}
}
}
function formValue(element) {
if (/checkbox|radio/i.test(element.attr('type'))) {
return element.prop('checked');
}
return element.val();
}
var formRegExp = /^(input|select|textarea)$/i;
function isForm(element) {
return formRegExp.test(element[0].tagName);
}
function bindToNgModel(widget, scope, element, ngModel, ngForm) {
if (!widget.value) {
return;
}
var value;
if (isForm(element)) {
value = function () {
return formValue(element);
};
} else {
value = function () {
return widget.value();
};
}
ngModel.$render = function () {
var val = ngModel.$viewValue;
if (val === undefined) {
val = ngModel.$modelValue;
}
if (val === undefined) {
val = null;
}
setTimeout(function () {
if (widget) {
var kNgModel = scope[widget.element.attr('k-ng-model')];
if (kNgModel) {
val = kNgModel;
}
if (widget.options.autoBind === false && !widget.listView.bound()) {
if (val) {
widget.value(val);
}
} else {
widget.value(val);
}
}
}, 0);
};
var haveChangeOnElement = false;
if (isForm(element)) {
element.on('change', function () {
haveChangeOnElement = true;
});
}
var onChange = function (pristine) {
return function () {
var formPristine;
if (haveChangeOnElement) {
return;
}
if (pristine && ngForm) {
formPristine = ngForm.$pristine;
}
ngModel.$setViewValue(value());
if (pristine) {
ngModel.$setPristine();
if (formPristine) {
ngForm.$setPristine();
}
}
digest(scope);
};
};
widget.first('change', onChange(false));
if (!(kendo.ui.AutoComplete && widget instanceof kendo.ui.AutoComplete)) {
widget.first('dataBound', onChange(true));
}
var currentVal = value();
if (!isNaN(ngModel.$viewValue) && currentVal != ngModel.$viewValue) {
if (!ngModel.$isEmpty(ngModel.$viewValue)) {
widget.value(ngModel.$viewValue);
} else if (currentVal != null && currentVal !== '' && currentVal != ngModel.$viewValue) {
ngModel.$setViewValue(currentVal);
}
}
ngModel.$setPristine();
}
function bindToKNgModel(widget, scope, kNgModel) {
if (typeof widget.value != 'function') {
$log.warn('k-ng-model specified on a widget that does not have the value() method: ' + widget.options.name);
return;
}
var form = $(widget.element).parents('form');
var ngForm = scope[form.attr('name')];
var getter = $parse(kNgModel);
var setter = getter.assign;
var updating = false;
var valueIsCollection = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect;
var length = function (value) {
return valueIsCollection ? value.length : 0;
};
var currentValueLength = length(getter(scope));
widget.$angular_setLogicValue(getter(scope));
var watchHandler = function (newValue, oldValue) {
if (newValue === undefined) {
newValue = null;
}
if (updating || newValue == oldValue && length(newValue) == currentValueLength) {
return;
}
currentValueLength = length(newValue);
widget.$angular_setLogicValue(newValue);
};
if (valueIsCollection) {
scope.$watchCollection(kNgModel, watchHandler);
} else {
scope.$watch(kNgModel, watchHandler);
}
widget.first('change', function () {
updating = true;
if (ngForm && ngForm.$pristine) {
ngForm.$setDirty();
}
digest(scope, function () {
setter(scope, widget.$angular_getLogicValue());
currentValueLength = length(getter(scope));
});
updating = false;
});
}
function destroyWidgetOnScopeDestroy(scope, widget) {
var deregister = scope.$on('$destroy', function () {
deregister();
if (widget) {
if (widget.element) {
widget.destroy();
}
widget = null;
}
});
return deregister;
}
function propagateClassToWidgetWrapper(widget, element) {
if (!(window.MutationObserver && widget.wrapper)) {
return;
}
var prevClassList = [].slice.call($(element)[0].classList);
var mo = new MutationObserver(function (changes) {
suspend();
if (!widget) {
return;
}
changes.forEach(function (chg) {
var w = $(widget.wrapper)[0];
switch (chg.attributeName) {
case 'class':
var currClassList = [].slice.call(chg.target.classList);
currClassList.forEach(function (cls) {
if (prevClassList.indexOf(cls) < 0) {
w.classList.add(cls);
if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
widget.input[0].classList.add(cls);
}
}
});
prevClassList.forEach(function (cls) {
if (currClassList.indexOf(cls) < 0) {
w.classList.remove(cls);
if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
widget.input[0].classList.remove(cls);
}
}
});
prevClassList = currClassList;
break;
case 'disabled':
if (typeof widget.enable == 'function' && !widget.element.attr('readonly')) {
widget.enable(!$(chg.target).attr('disabled'));
}
break;
case 'readonly':
if (typeof widget.readonly == 'function' && !widget.element.attr('disabled')) {
widget.readonly(!!$(chg.target).attr('readonly'));
}
break;
}
});
resume();
});
function suspend() {
mo.disconnect();
}
function resume() {
mo.observe($(element)[0], { attributes: true });
}
resume();
widget.first('destroy', suspend);
}
function setupRebind(widget, scope, element, originalElement, rebindAttr, destroyRegister, attrs) {
var unregister = scope.$watch(rebindAttr, function (newValue, oldValue) {
if (!widget._muteRebind && newValue !== oldValue) {
unregister();
var templateOptions = WIDGET_TEMPLATE_OPTIONS[widget.options.name];
if (templateOptions) {
templateOptions.forEach(function (name) {
var templateContents = scope.$eval(attrs['k' + name]);
if (templateContents) {
originalElement.append($(templateContents).attr(kendo.toHyphens('k' + name), ''));
}
});
}
var _wrapper = $(widget.wrapper)[0];
var _element = $(widget.element)[0];
var isUpload = widget.options.name === 'Upload';
if (isUpload) {
element = $(_element);
}
var compile = element.injector().get('$compile');
widget._destroy();
if (destroyRegister) {
destroyRegister();
}
widget = null;
if (_element) {
if (_wrapper) {
_wrapper.parentNode.replaceChild(_element, _wrapper);
}
$(element).replaceWith(originalElement);
}
compile(originalElement)(scope);
}
}, true);
digest(scope);
}
module.factory('directiveFactory', [
'$compile',
function (compile) {
var kendoRenderedTimeout;
var RENDERED = false;
$defaultCompile = compile;
var create = function (role, origAttr) {
return {
restrict: 'AC',
require: [
'?ngModel',
'^?form'
],
scope: false,
controller: [
'$scope',
'$attrs',
'$element',
function ($scope, $attrs) {
var that = this;
that.template = function (key, value) {
$attrs[key] = kendo.stringify(value);
};
$scope.$on('$destroy', function () {
that.template = null;
that = null;
});
}
],
link: function (scope, element, attrs, controllers) {
var $element = $(element);
var roleattr = role.replace(/([A-Z])/g, '-$1');
$element.attr(roleattr, $element.attr('data-' + roleattr));
$element[0].removeAttribute('data-' + roleattr);
var widget = createWidget(scope, element, attrs, role, origAttr, controllers);
if (!widget) {
return;
}
if (kendoRenderedTimeout) {
clearTimeout(kendoRenderedTimeout);
}
kendoRenderedTimeout = setTimeout(function () {
scope.$emit('kendoRendered');
if (!RENDERED) {
RENDERED = true;
$('form').each(function () {
var form = $(this).controller('form');
if (form) {
form.$setPristine();
}
});
}
});
}
};
};
return { create: create };
}
]);
var TAGNAMES = {
Editor: 'textarea',
NumericTextBox: 'input',
DatePicker: 'input',
DateTimePicker: 'input',
TimePicker: 'input',
AutoComplete: 'input',
ColorPicker: 'input',
MaskedTextBox: 'input',
MultiSelect: 'input',
Upload: 'input',
Validator: 'form',
Button: 'button',
MobileButton: 'a',
MobileBackButton: 'a',
MobileDetailButton: 'a',
ListView: 'ul',
MobileListView: 'ul',
TreeView: 'ul',
Menu: 'ul',
ContextMenu: 'ul',
ActionSheet: 'ul'
};
var SKIP_SHORTCUTS = [
'MobileView',
'MobileDrawer',
'MobileLayout',
'MobileSplitView',
'MobilePane',
'MobileModalView'
];
var MANUAL_DIRECTIVES = [
'MobileApplication',
'MobileView',
'MobileModalView',
'MobileLayout',
'MobileActionSheet',
'MobileDrawer',
'MobileSplitView',
'MobilePane',
'MobileScrollView',
'MobilePopOver'
];
angular.forEach([
'MobileNavBar',
'MobileButton',
'MobileBackButton',
'MobileDetailButton',
'MobileTabStrip',
'MobileScrollView',
'MobileScroller'
], function (widget) {
MANUAL_DIRECTIVES.push(widget);
widget = 'kendo' + widget;
module.directive(widget, function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
createWidget(scope, element, attrs, widget, widget);
}
};
});
});
function createDirectives(klass, isMobile) {
function make(directiveName, widgetName) {
module.directive(directiveName, [
'directiveFactory',
function (directiveFactory) {
return directiveFactory.create(widgetName, directiveName);
}
]);
}
var name = isMobile ? 'Mobile' : '';
name += klass.fn.options.name;
var className = name;
var shortcut = 'kendo' + name.charAt(0) + name.substr(1).toLowerCase();
name = 'kendo' + name;
var dashed = name.replace(/([A-Z])/g, '-$1');
if (SKIP_SHORTCUTS.indexOf(name.replace('kendo', '')) == -1) {
var names = name === shortcut ? [name] : [
name,
shortcut
];
angular.forEach(names, function (directiveName) {
module.directive(directiveName, function () {
return {
restrict: 'E',
replace: true,
template: function (element, attributes) {
var tag = TAGNAMES[className] || 'div';
var scopeField = attributes.kScopeField || attributes.scopeField;
return '<' + tag + ' ' + dashed + (scopeField ? '="' + scopeField + '"' : '') + '>' + element.html() + '' + tag + '>';
}
};
});
});
}
if (MANUAL_DIRECTIVES.indexOf(name.replace('kendo', '')) > -1) {
return;
}
make(name, name);
if (shortcut != name) {
make(shortcut, name);
}
}
function kendoWidgetInstance(el) {
el = $(el);
return kendo.widgetInstance(el, kendo.ui) || kendo.widgetInstance(el, kendo.mobile.ui) || kendo.widgetInstance(el, kendo.dataviz.ui);
}
function digest(scope, func) {
var root = scope.$root || scope;
var isDigesting = /^\$(digest|apply)$/.test(root.$$phase);
if (func) {
if (isDigesting) {
func();
} else {
root.$apply(func);
}
} else if (!isDigesting) {
root.$digest();
}
}
function destroyScope(scope, el) {
scope.$destroy();
if (el) {
$(el).removeData('$scope').removeData('$$kendoScope').removeData('$isolateScope').removeData('$isolateScopeNoTemplate').removeClass('ng-scope');
}
}
var pendingPatches = [];
function defadvice(klass, methodName, func) {
if ($.isArray(klass)) {
return angular.forEach(klass, function (klass) {
defadvice(klass, methodName, func);
});
}
if (typeof klass == 'string') {
var a = klass.split('.');
var x = kendo;
while (x && a.length > 0) {
x = x[a.shift()];
}
if (!x) {
pendingPatches.push([
klass,
methodName,
func
]);
return false;
}
klass = x.prototype;
}
var origMethod = klass[methodName];
klass[methodName] = function () {
var self = this, args = arguments;
return func.apply({
self: self,
next: function () {
return origMethod.apply(self, arguments.length > 0 ? arguments : args);
}
}, args);
};
return true;
}
kendo.onWidgetRegistered(function (entry) {
pendingPatches = $.grep(pendingPatches, function (args) {
return !defadvice.apply(null, args);
});
createDirectives(entry.widget, entry.prefix == 'Mobile');
});
defadvice([
'ui.Widget',
'mobile.ui.Widget'
], 'angular', function (cmd, arg) {
var self = this.self;
if (cmd == 'init') {
if (!arg && OPTIONS_NOW) {
arg = OPTIONS_NOW;
}
OPTIONS_NOW = null;
if (arg && arg.$angular) {
self.$angular_scope = arg.$angular[0];
self.$angular_init(self.element, arg);
}
return;
}
var scope = self.$angular_scope;
if (scope) {
withoutTimeout(function () {
var x = arg(), elements = x.elements, data = x.data;
if (elements.length > 0) {
switch (cmd) {
case 'cleanup':
angular.forEach(elements, function (el) {
var itemScope = $(el).data('$$kendoScope');
if (itemScope && itemScope !== scope && itemScope.$$kendoScope) {
destroyScope(itemScope, el);
}
});
break;
case 'compile':
var injector = self.element.injector();
var compile = injector ? injector.get('$compile') : $defaultCompile;
angular.forEach(elements, function (el, i) {
var itemScope;
if (x.scopeFrom) {
itemScope = x.scopeFrom;
} else {
var vars = data && data[i];
if (vars !== undefined) {
itemScope = $.extend(scope.$new(), vars);
itemScope.$$kendoScope = true;
} else {
itemScope = scope;
}
}
$(el).data('$$kendoScope', itemScope);
compile(el)(itemScope);
});
digest(scope);
break;
}
}
});
}
});
defadvice('ui.Widget', '$angular_getLogicValue', function () {
return this.self.value();
});
defadvice('ui.Widget', '$angular_setLogicValue', function (val) {
this.self.value(val);
});
defadvice('ui.Select', '$angular_getLogicValue', function () {
var item = this.self.dataItem(), valueField = this.self.options.dataValueField;
if (item) {
if (this.self.options.valuePrimitive) {
if (!!valueField) {
return item[valueField];
} else {
return item;
}
} else {
return item.toJSON();
}
} else {
return null;
}
});
defadvice('ui.Select', '$angular_setLogicValue', function (val) {
var self = this.self;
var options = self.options;
var valueField = options.dataValueField;
var text = options.text || '';
if (val === undefined) {
val = '';
}
if (valueField && !options.valuePrimitive && val) {
text = val[options.dataTextField] || '';
val = val[valueField || options.dataTextField];
}
if (self.options.autoBind === false && !self.listView.bound()) {
if (!text && val && options.valuePrimitive) {
self.value(val);
} else {
self._preselect(val, text);
}
} else {
self.value(val);
}
});
defadvice('ui.MultiSelect', '$angular_getLogicValue', function () {
var value = this.self.dataItems().slice(0);
var valueField = this.self.options.dataValueField;
if (valueField && this.self.options.valuePrimitive) {
value = $.map(value, function (item) {
return item[valueField];
});
}
return value;
});
defadvice('ui.MultiSelect', '$angular_setLogicValue', function (val) {
if (val == null) {
val = [];
}
var self = this.self;
var options = self.options;
var valueField = options.dataValueField;
var data = val;
if (valueField && !options.valuePrimitive) {
val = $.map(val, function (item) {
return item[valueField];
});
}
if (options.autoBind === false && !options.valuePrimitive && !self.listView.bound()) {
self._preselect(data, val);
} else {
self.value(val);
}
});
defadvice('ui.AutoComplete', '$angular_getLogicValue', function () {
var options = this.self.options;
var values = this.self.value().split(options.separator);
var valuePrimitive = options.valuePrimitive;
var data = this.self.dataSource.data();
var dataItems = [];
for (var idx = 0, length = data.length; idx < length; idx++) {
var item = data[idx];
var dataValue = options.dataTextField ? item[options.dataTextField] : item;
for (var j = 0; j < values.length; j++) {
if (dataValue === values[j]) {
if (valuePrimitive) {
dataItems.push(dataValue);
} else {
dataItems.push(item.toJSON());
}
break;
}
}
}
return dataItems;
});
defadvice('ui.AutoComplete', '$angular_setLogicValue', function (value) {
if (value == null) {
value = [];
}
var self = this.self, dataTextField = self.options.dataTextField;
if (dataTextField && !self.options.valuePrimitive) {
if (value.length !== undefined) {
value = $.map(value, function (item) {
return item[dataTextField];
});
} else {
value = value[dataTextField];
}
}
self.value(value);
});
defadvice('ui.Widget', '$angular_init', function (element, options) {
var self = this.self;
if (options && !$.isArray(options)) {
var scope = self.$angular_scope;
for (var i = self.events.length; --i >= 0;) {
var event = self.events[i];
var handler = options[event];
if (handler && typeof handler == 'string') {
options[event] = self.$angular_makeEventHandler(event, scope, handler);
}
}
}
});
defadvice('ui.Widget', '$angular_makeEventHandler', function (event, scope, handler) {
handler = $parse(handler);
return function (e) {
digest(scope, function () {
handler(scope, { kendoEvent: e });
});
};
});
defadvice([
'ui.Grid',
'ui.ListView',
'ui.TreeView'
], '$angular_makeEventHandler', function (event, scope, handler) {
if (event != 'change') {
return this.next();
}
handler = $parse(handler);
return function (ev) {
var widget = ev.sender;
var options = widget.options;
var cell, multiple, locals = { kendoEvent: ev }, elems, items, columns, colIdx;
if (angular.isString(options.selectable)) {
cell = options.selectable.indexOf('cell') !== -1;
multiple = options.selectable.indexOf('multiple') !== -1;
}
elems = locals.selected = this.select();
items = locals.data = [];
columns = locals.columns = [];
for (var i = 0; i < elems.length; i++) {
var item = cell ? elems[i].parentNode : elems[i];
var dataItem = widget.dataItem(item);
if (cell) {
if (angular.element.inArray(dataItem, items) < 0) {
items.push(dataItem);
}
colIdx = angular.element(elems[i]).index();
if (angular.element.inArray(colIdx, columns) < 0) {
columns.push(colIdx);
}
} else {
items.push(dataItem);
}
}
if (!multiple) {
locals.dataItem = locals.data = items[0];
locals.angularDataItem = kendo.proxyModelSetters(locals.dataItem);
locals.selected = elems[0];
}
digest(scope, function () {
handler(scope, locals);
});
};
});
defadvice('ui.Grid', '$angular_init', function (element, options) {
this.next();
if (options.columns) {
var settings = $.extend({}, kendo.Template, options.templateSettings);
angular.forEach(options.columns, function (col) {
if (col.field && !col.template && !col.format && !col.values && (col.encoded === undefined || col.encoded)) {
col.template = '
#: ' + kendo.expr(col.field, settings.paramName) + '#';
}
});
}
});
{
defadvice('mobile.ui.ButtonGroup', 'value', function (mew) {
var self = this.self;
if (mew != null) {
self.select(self.element.children('li.km-button').eq(mew));
self.trigger('change');
self.trigger('select', { index: self.selectedIndex });
}
return self.selectedIndex;
});
defadvice('mobile.ui.ButtonGroup', '_select', function () {
this.next();
this.self.trigger('change');
});
}
module.directive('kendoMobileApplication', function () {
return {
terminal: true,
link: function (scope, element, attrs) {
createWidget(scope, element, attrs, 'kendoMobileApplication', 'kendoMobileApplication');
}
};
}).directive('kendoMobileView', function () {
return {
scope: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
attrs._instance = createWidget(scope, element, attrs, 'kendoMobileView', 'kendoMobileView');
},
post: function (scope, element, attrs) {
attrs._instance._layout();
attrs._instance._scroller();
}
}
};
}).directive('kendoMobileDrawer', function () {
return {
scope: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
attrs._instance = createWidget(scope, element, attrs, 'kendoMobileDrawer', 'kendoMobileDrawer');
},
post: function (scope, element, attrs) {
attrs._instance._layout();
attrs._instance._scroller();
}
}
};
}).directive('kendoMobileModalView', function () {
return {
scope: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
attrs._instance = createWidget(scope, element, attrs, 'kendoMobileModalView', 'kendoMobileModalView');
},
post: function (scope, element, attrs) {
attrs._instance._layout();
attrs._instance._scroller();
}
}
};
}).directive('kendoMobileSplitView', function () {
return {
terminal: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
attrs._instance = createWidget(scope, element, attrs, 'kendoMobileSplitView', 'kendoMobileSplitView');
},
post: function (scope, element, attrs) {
attrs._instance._layout();
}
}
};
}).directive('kendoMobilePane', function () {
return {
terminal: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
createWidget(scope, element, attrs, 'kendoMobilePane', 'kendoMobilePane');
}
}
};
}).directive('kendoMobileLayout', function () {
return {
link: {
pre: function (scope, element, attrs) {
createWidget(scope, element, attrs, 'kendoMobileLayout', 'kendoMobileLayout');
}
}
};
}).directive('kendoMobileActionSheet', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.find('a[k-action]').each(function () {
$(this).attr('data-' + kendo.ns + 'action', $(this).attr('k-action'));
});
createWidget(scope, element, attrs, 'kendoMobileActionSheet', 'kendoMobileActionSheet');
}
};
}).directive('kendoMobilePopOver', function () {
return {
terminal: true,
link: {
pre: function (scope, element, attrs) {
attrs.defaultOptions = scope.viewOptions;
createWidget(scope, element, attrs, 'kendoMobilePopOver', 'kendoMobilePopOver');
}
}
};
}).directive('kendoViewTitle', function () {
return {
restrict: 'E',
replace: true,
template: function (element) {
return '
' + element.html() + '';
}
};
}).directive('kendoMobileHeader', function () {
return {
restrict: 'E',
link: function (scope, element) {
element.addClass('km-header').attr('data-role', 'header');
}
};
}).directive('kendoMobileFooter', function () {
return {
restrict: 'E',
link: function (scope, element) {
element.addClass('km-footer').attr('data-role', 'footer');
}
};
}).directive('kendoMobileScrollViewPage', function () {
return {
restrict: 'E',
replace: true,
template: function (element) {
return '
' + element.html() + '
';
}
};
});
angular.forEach([
'align',
'icon',
'rel',
'transition',
'actionsheetContext'
], function (attr) {
var kAttr = 'k' + attr.slice(0, 1).toUpperCase() + attr.slice(1);
module.directive(kAttr, function () {
return {
restrict: 'A',
priority: 2,
link: function (scope, element, attrs) {
element.attr(kendo.attr(kendo.toHyphens(attr)), scope.$eval(attrs[kAttr]));
}
};
});
});
var WIDGET_TEMPLATE_OPTIONS = {
'TreeMap': ['Template'],
'MobileListView': [
'HeaderTemplate',
'Template'
],
'MobileScrollView': [
'EmptyTemplate',
'Template'
],
'Grid': [
'AltRowTemplate',
'DetailTemplate',
'RowTemplate'
],
'ListView': [
'EditTemplate',
'Template',
'AltTemplate'
],
'Pager': [
'SelectTemplate',
'LinkTemplate'
],
'PivotGrid': [
'ColumnHeaderTemplate',
'DataCellTemplate',
'RowHeaderTemplate'
],
'Scheduler': [
'AllDayEventTemplate',
'DateHeaderTemplate',
'EventTemplate',
'MajorTimeHeaderTemplate',
'MinorTimeHeaderTemplate'
],
'TreeView': ['Template'],
'Validator': ['ErrorTemplate']
};
(function () {
var templateDirectives = {};
angular.forEach(WIDGET_TEMPLATE_OPTIONS, function (templates, widget) {
angular.forEach(templates, function (template) {
if (!templateDirectives[template]) {
templateDirectives[template] = [];
}
templateDirectives[template].push('?^^kendo' + widget);
});
});
angular.forEach(templateDirectives, function (parents, directive) {
var templateName = 'k' + directive;
var attrName = kendo.toHyphens(templateName);
module.directive(templateName, function () {
return {
restrict: 'A',
require: parents,
terminal: true,
compile: function ($element, $attrs) {
if ($attrs[templateName] !== '') {
return;
}
$element.removeAttr(attrName);
var template = $element[0].outerHTML;
return function (scope, element, attrs, controllers) {
var controller;
while (!controller && controllers.length) {
controller = controllers.shift();
}
if (!controller) {
$log.warn(attrName + ' without a matching parent widget found. It can be one of the following: ' + parents.join(', '));
} else {
controller.template(templateName, template);
$element.remove();
}
};
}
};
});
});
}());
}(window.kendo.jQuery, window.angular));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.webcomponents', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'webcomponents',
name: 'Web Components',
category: 'framework',
description: 'Adds Kendo UI custom elements for Web Components',
depends: ['core']
};
(function ($, angular, undefined) {
if (!kendo.support.customElements || kendo.webComponents.length) {
return;
}
if (angular && (angular.version.major == 1 || angular.injector)) {
return;
}
var TAGNAMES = {
editor: 'textarea',
numerictextbox: 'input',
datepicker: 'input',
datetimepicker: 'input',
timepicker: 'input',
autocomplete: 'input',
colorpicker: 'input',
maskedtextbox: 'input',
dropdownlist: 'select',
multiselect: 'select',
upload: 'input',
validator: 'form',
button: 'button',
mobilebutton: 'a',
mobilebackbutton: 'a',
mobiledetailbutton: 'a',
listview: 'ul',
mobilelistview: 'ul',
treeview: 'ul',
menu: 'ul',
contextmenu: 'ul',
actionsheet: 'ul'
};
var EVENT_PREFIX = 'on-';
var registered = [];
kendo.onWidgetRegistered(function (entry) {
var elementName = entry.prefix + entry.widget.prototype.options.name.toLowerCase();
if (registered.indexOf(elementName) === -1) {
registered.push(elementName);
registerElement(elementName, entry.widget);
}
});
var jsonRegExp = /^\s*(?:\{(?:.|\r\n|\n)*\}|\[(?:.|\r\n|\n)*\])\s*$/;
var jsonFormatRegExp = /^\{(\d+)(:[^\}]+)?\}|^\[[A-Za-z_]*\]$/;
var numberRegExp = /^(\+|-?)\d+(\.?)\d*$/;
function parseOption(element, option) {
var value = element.getAttribute(option);
if (value === null) {
value = undefined;
} else if (value === 'null') {
value = null;
} else if (value === 'true') {
value = true;
} else if (value === 'false') {
value = false;
} else if (numberRegExp.test(value)) {
value = parseFloat(value);
} else if (jsonRegExp.test(value) && !jsonFormatRegExp.test(value)) {
value = new Function('return (' + value + ')')();
}
return value;
}
function parseOptions(element, options) {
var result = {};
Object.keys(options).concat('dataSource').forEach(function (name) {
if (element.hasAttribute(kendo.toHyphens(name))) {
result[name] = parseOption(element, kendo.toHyphens(name));
}
});
return result;
}
function cloneEvent(e) {
var result = {};
Object.keys(e).forEach(function (key) {
if (key[0] != '_') {
result[key] = e[key];
}
});
return result;
}
function eventHandler(eventName, e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent(eventName, false, true, cloneEvent(e));
this.dispatchEvent(event);
if (event.defaultPrevented) {
e.preventDefault();
}
}
function expose(component, obj) {
var props = Object.keys(obj);
for (var idx = 0; idx <= props.length; idx++) {
if (typeof obj[props[idx]] === 'function') {
if (!component[props[idx]]) {
component[props[idx]] = obj[props[idx]].bind(component.widget);
}
} else {
if (props[idx] === 'options') {
continue;
}
component[props[idx]] = component[props[idx]] || obj[props[idx]];
}
}
}
function registerElement(name, widget) {
var options = widget.prototype.options;
var prototype = Object.create(HTMLElement.prototype);
Object.defineProperty(prototype, 'options', {
get: function () {
return this.widget.options;
},
set: function (options) {
var instance = this.widget;
options = $.extend(true, {}, instance.options, options);
var _wrapper = $(instance.wrapper)[0];
var _element = $(instance.element)[0];
instance._destroy();
var newElement = document.createElement(TAGNAMES[name] || 'div');
if (_wrapper && _element) {
_wrapper.parentNode.replaceChild(_element, _wrapper);
$(_element).replaceWith(newElement);
}
if (instance.value) {
options.value = instance.value();
}
instance.init(newElement, options);
this.bindEvents();
}
});
prototype.bindEvents = function () {
widget.prototype.events.forEach(function (eventName) {
this.widget.bind(eventName, eventHandler.bind(this, eventName));
if (this.hasAttribute(EVENT_PREFIX + eventName)) {
this.bind(eventName, function (e) {
window[this.getAttribute(EVENT_PREFIX + eventName)].call(this, e);
}.bind(this));
}
}.bind(this));
};
prototype.attachedCallback = function () {
var that = this;
var element = document.createElement(TAGNAMES[name] || 'div');
$(element).append(that.childNodes);
$(element).attr('class', $(that).attr('class'));
$(element).attr('style', $(that).attr('style'));
that.appendChild(element);
that.widget = new widget(element, parseOptions(that, options));
var obj = that.widget;
do {
expose(that, obj);
} while (obj = Object.getPrototypeOf(obj));
this.bindEvents();
};
prototype.detachedCallback = function () {
kendo.destroy(this.element);
};
kendo.webComponents.push('kendo-' + name);
document.registerElement('kendo-' + name, { prototype: prototype });
}
}(window.kendo.jQuery, window.angular));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.angular2', [
'kendo.core',
'kendo.webcomponents'
], f);
}(function () {
var __meta__ = {
id: 'angular2',
name: 'Angular 2',
category: 'framework',
description: 'Supports angular2 value accessors',
depends: ['core']
};
(function (kendo, System) {
if (!System || !System.register) {
return;
}
var __decorate = this && this.__decorate || function (decorators, target, key, desc) {
if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') {
return Reflect.decorate(decorators, target, key, desc);
}
switch (arguments.length) {
case 2:
return decorators.reduceRight(function (o, d) {
return d && d(o) || o;
}, target);
case 3:
return decorators.reduceRight(function (o, d) {
return d && d(target, key), void 0;
}, void 0);
case 4:
return decorators.reduceRight(function (o, d) {
return d && d(target, key, o) || o;
}, desc);
}
};
var __metadata = this && this.__metadata || function (k, v) {
if (typeof Reflect === 'object' && typeof Reflect.metadata === 'function') {
return Reflect.metadata(k, v);
}
};
System.register('kendo/angular2', ['angular2/angular2'], function (exports_1) {
var angular2_1;
var KendoValueAccessor;
return {
setters: [function (_angular2_1) {
angular2_1 = _angular2_1;
}],
execute: function () {
KendoValueAccessor = function () {
function KendoValueAccessor(cd, elementRef) {
var _this = this;
this.elementRef = elementRef;
this.onChange = function (_) {
};
this.onTouched = function () {
};
this.element = elementRef.nativeElement;
this.element.addEventListener('change', function () {
_this.onChange(_this.element.value());
});
this.element.addEventListener('spin', function () {
_this.onChange(_this.element.value());
});
cd.valueAccessor = this;
this.cd = cd;
cd.valueAccessor = this;
}
KendoValueAccessor.prototype.writeValue = function (value) {
this.element.value(value);
};
KendoValueAccessor.prototype.registerOnChange = function (fn) {
this.onChange = fn;
};
KendoValueAccessor.prototype.registerOnTouched = function (fn) {
this.onTouched = fn;
};
KendoValueAccessor = __decorate([
angular2_1.Directive({ selector: kendo.webComponents.join(',') }),
__metadata('design:paramtypes', [
angular2_1.NgControl,
angular2_1.ElementRef
])
], KendoValueAccessor);
return KendoValueAccessor;
}();
exports_1('KendoValueAccessor', KendoValueAccessor);
}
};
});
}(window.kendo, window.System));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dataviz', [
'kendo.core',
'kendo.fx',
'kendo.router',
'kendo.view',
'kendo.data.odata',
'kendo.data.xml',
'kendo.data',
'kendo.data.signalr',
'kendo.binder',
'kendo.userevents',
'kendo.draganddrop',
'kendo.mobile.scroller',
'kendo.popup',
'kendo.tooltip',
'kendo.drawing',
'kendo.dataviz.core',
'kendo.dataviz.themes',
'kendo.dataviz.chart',
'kendo.dataviz.chart.polar',
'kendo.dataviz.chart.funnel',
'kendo.dataviz.gauge',
'kendo.dataviz.barcode',
'kendo.dataviz.qrcode',
'kendo.dataviz.stock',
'kendo.dataviz.sparkline',
'kendo.dataviz.map',
'kendo.dataviz.diagram',
'kendo.dataviz.treemap',
'kendo.angular',
'kendo.webcomponents',
'kendo.angular2'
], f);
}(function () {
'bundle all';
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.touch', [
'kendo.core',
'kendo.userevents'
], f);
}(function () {
var __meta__ = {
id: 'touch',
name: 'Touch',
category: 'mobile',
description: 'The kendo Touch widget provides a cross-platform compatible API for handling user-initiated touch events, multi-touch gestures and event sequences (drag, swipe, etc.). ',
depends: [
'core',
'userevents'
]
};
(function ($, undefined) {
var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, abs = Math.abs, MAX_DOUBLE_TAP_DISTANCE = 20;
var Touch = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
options = that.options;
element = that.element;
that.wrapper = element;
function eventProxy(name) {
return function (e) {
that._triggerTouch(name, e);
};
}
function gestureEventProxy(name) {
return function (e) {
that.trigger(name, {
touches: e.touches,
distance: e.distance,
center: e.center,
event: e.event
});
};
}
that.events = new kendo.UserEvents(element, {
filter: options.filter,
surface: options.surface,
minHold: options.minHold,
multiTouch: options.multiTouch,
allowSelection: true,
fastTap: options.fastTap,
press: eventProxy('touchstart'),
hold: eventProxy('hold'),
tap: proxy(that, '_tap'),
gesturestart: gestureEventProxy('gesturestart'),
gesturechange: gestureEventProxy('gesturechange'),
gestureend: gestureEventProxy('gestureend')
});
if (options.enableSwipe) {
that.events.bind('start', proxy(that, '_swipestart'));
that.events.bind('move', proxy(that, '_swipemove'));
} else {
that.events.bind('start', proxy(that, '_dragstart'));
that.events.bind('move', eventProxy('drag'));
that.events.bind('end', eventProxy('dragend'));
}
kendo.notify(that);
},
events: [
'touchstart',
'dragstart',
'drag',
'dragend',
'tap',
'doubletap',
'hold',
'swipe',
'gesturestart',
'gesturechange',
'gestureend'
],
options: {
name: 'Touch',
surface: null,
global: false,
fastTap: false,
multiTouch: false,
enableSwipe: false,
minXDelta: 30,
maxYDelta: 20,
maxDuration: 1000,
minHold: 800,
doubleTapTimeout: 800
},
cancel: function () {
this.events.cancel();
},
_triggerTouch: function (type, e) {
if (this.trigger(type, {
touch: e.touch,
event: e.event
})) {
e.preventDefault();
}
},
_tap: function (e) {
var that = this, lastTap = that.lastTap, touch = e.touch;
if (lastTap && touch.endTime - lastTap.endTime < that.options.doubleTapTimeout && kendo.touchDelta(touch, lastTap).distance < MAX_DOUBLE_TAP_DISTANCE) {
that._triggerTouch('doubletap', e);
that.lastTap = null;
} else {
that._triggerTouch('tap', e);
that.lastTap = touch;
}
},
_dragstart: function (e) {
this._triggerTouch('dragstart', e);
},
_swipestart: function (e) {
if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
e.sender.capture();
}
},
_swipemove: function (e) {
var that = this, options = that.options, touch = e.touch, duration = e.event.timeStamp - touch.startTime, direction = touch.x.initialDelta > 0 ? 'right' : 'left';
if (abs(touch.x.initialDelta) >= options.minXDelta && abs(touch.y.initialDelta) < options.maxYDelta && duration < options.maxDuration) {
that.trigger('swipe', {
direction: direction,
touch: e.touch
});
touch.cancel();
}
}
});
kendo.ui.plugin(Touch);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.view', [
'kendo.core',
'kendo.fx',
'kendo.mobile.scroller',
'kendo.view'
], f);
}(function () {
var __meta__ = {
id: 'mobile.view',
name: 'View',
category: 'mobile',
description: 'Mobile View',
depends: [
'core',
'fx',
'mobile.scroller',
'view'
],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, attr = kendo.attr, Widget = ui.Widget, ViewClone = kendo.ViewClone, INIT = 'init', UI_OVERLAY = '
', BEFORE_SHOW = 'beforeShow', SHOW = 'show', AFTER_SHOW = 'afterShow', BEFORE_HIDE = 'beforeHide', TRANSITION_END = 'transitionEnd', TRANSITION_START = 'transitionStart', HIDE = 'hide', DESTROY = 'destroy', attrValue = kendo.attrValue, roleSelector = kendo.roleSelector, directiveSelector = kendo.directiveSelector, compileMobileDirective = kendo.compileMobileDirective;
function initPopOvers(element) {
var popovers = element.find(roleSelector('popover')), idx, length, roles = ui.roles;
for (idx = 0, length = popovers.length; idx < length; idx++) {
kendo.initWidget(popovers[idx], {}, roles);
}
}
function preventScrollIfNotInput(e) {
if (!kendo.triggeredByInput(e)) {
e.preventDefault();
}
}
var View = Widget.extend({
init: function (element, options) {
Widget.fn.init.call(this, element, options);
this.params = {};
$.extend(this, options);
this.transition = this.transition || this.defaultTransition;
this._id();
if (!this.options.$angular) {
this._layout();
this._overlay();
this._scroller();
this._model();
} else {
this._overlay();
}
},
events: [
INIT,
BEFORE_SHOW,
SHOW,
AFTER_SHOW,
BEFORE_HIDE,
HIDE,
DESTROY,
TRANSITION_START,
TRANSITION_END
],
options: {
name: 'View',
title: '',
layout: null,
getLayout: $.noop,
reload: false,
transition: '',
defaultTransition: '',
useNativeScrolling: false,
stretch: false,
zoom: false,
model: null,
modelScope: window,
scroller: {},
initWidgets: true
},
enable: function (enable) {
if (typeof enable == 'undefined') {
enable = true;
}
if (enable) {
this.overlay.hide();
} else {
this.overlay.show();
}
},
destroy: function () {
if (this.layout) {
this.layout.detach(this);
}
this.trigger(DESTROY);
Widget.fn.destroy.call(this);
if (this.scroller) {
this.scroller.destroy();
}
if (this.options.$angular) {
this.element.scope().$destroy();
}
kendo.destroy(this.element);
},
purge: function () {
this.destroy();
this.element.remove();
},
triggerBeforeShow: function () {
if (this.trigger(BEFORE_SHOW, { view: this })) {
return false;
}
return true;
},
triggerBeforeHide: function () {
if (this.trigger(BEFORE_HIDE, { view: this })) {
return false;
}
return true;
},
showStart: function () {
var element = this.element;
element.css('display', '');
if (!this.inited) {
this.inited = true;
this.trigger(INIT, { view: this });
} else {
this._invokeNgController();
}
if (this.layout) {
this.layout.attach(this);
}
this._padIfNativeScrolling();
this.trigger(SHOW, { view: this });
kendo.resize(element);
},
showEnd: function () {
this.trigger(AFTER_SHOW, { view: this });
this._padIfNativeScrolling();
},
hideEnd: function () {
var that = this;
that.element.hide();
that.trigger(HIDE, { view: that });
if (that.layout) {
that.layout.trigger(HIDE, {
view: that,
layout: that.layout
});
}
},
beforeTransition: function (type) {
this.trigger(TRANSITION_START, { type: type });
},
afterTransition: function (type) {
this.trigger(TRANSITION_END, { type: type });
},
_padIfNativeScrolling: function () {
if (mobile.appLevelNativeScrolling()) {
var isAndroid = kendo.support.mobileOS && kendo.support.mobileOS.android, skin = mobile.application.skin() || '', isAndroidForced = mobile.application.os.android || skin.indexOf('android') > -1, hasPlatformIndependentSkin = skin === 'flat' || skin.indexOf('material') > -1, topContainer = (isAndroid || isAndroidForced) && !hasPlatformIndependentSkin ? 'footer' : 'header', bottomContainer = (isAndroid || isAndroidForced) && !hasPlatformIndependentSkin ? 'header' : 'footer';
this.content.css({
paddingTop: this[topContainer].height(),
paddingBottom: this[bottomContainer].height()
});
}
},
contentElement: function () {
var that = this;
return that.options.stretch ? that.content : that.scrollerContent;
},
clone: function () {
return new ViewClone(this);
},
_scroller: function () {
var that = this;
if (mobile.appLevelNativeScrolling()) {
return;
}
if (that.options.stretch) {
that.content.addClass('km-stretched-view');
} else {
that.content.kendoMobileScroller($.extend(that.options.scroller, {
zoom: that.options.zoom,
useNative: that.options.useNativeScrolling
}));
that.scroller = that.content.data('kendoMobileScroller');
that.scrollerContent = that.scroller.scrollElement;
}
if (kendo.support.kineticScrollNeeded) {
$(that.element).on('touchmove', '.km-header', preventScrollIfNotInput);
if (!that.options.useNativeScrolling && !that.options.stretch) {
$(that.element).on('touchmove', '.km-content', preventScrollIfNotInput);
}
}
},
_model: function () {
var that = this, element = that.element, model = that.options.model;
if (typeof model === 'string') {
model = kendo.getter(model)(that.options.modelScope);
}
that.model = model;
initPopOvers(element);
that.element.css('display', '');
if (that.options.initWidgets) {
if (model) {
kendo.bind(element, model, ui, kendo.ui, kendo.dataviz.ui);
} else {
mobile.init(element.children());
}
}
that.element.css('display', 'none');
},
_id: function () {
var element = this.element, idAttrValue = element.attr('id') || '';
this.id = attrValue(element, 'url') || '#' + idAttrValue;
if (this.id == '#') {
this.id = kendo.guid();
element.attr('id', this.id);
}
},
_layout: function () {
var contentSelector = roleSelector('content'), element = this.element;
element.addClass('km-view');
this.header = element.children(roleSelector('header')).addClass('km-header');
this.footer = element.children(roleSelector('footer')).addClass('km-footer');
if (!element.children(contentSelector)[0]) {
element.wrapInner('
');
}
this.content = element.children(roleSelector('content')).addClass('km-content');
this.element.prepend(this.header).append(this.footer);
this.layout = this.options.getLayout(this.layout);
if (this.layout) {
this.layout.setup(this);
}
},
_overlay: function () {
this.overlay = $(UI_OVERLAY).appendTo(this.element);
},
_invokeNgController: function () {
var controller, scope;
if (this.options.$angular) {
controller = this.element.controller();
scope = this.options.$angular[0];
if (controller) {
var callback = $.proxy(this, '_callController', controller, scope);
if (/^\$(digest|apply)$/.test(scope.$$phase)) {
callback();
} else {
scope.$apply(callback);
}
}
}
},
_callController: function (controller, scope) {
this.element.injector().invoke(controller.constructor, controller, { $scope: scope });
}
});
function initWidgets(collection) {
collection.each(function () {
kendo.initWidget($(this), {}, ui.roles);
});
}
var Layout = Widget.extend({
init: function (element, options) {
Widget.fn.init.call(this, element, options);
element = this.element;
this.header = element.children(this._locate('header')).addClass('km-header');
this.footer = element.children(this._locate('footer')).addClass('km-footer');
this.elements = this.header.add(this.footer);
initPopOvers(element);
if (!this.options.$angular) {
kendo.mobile.init(this.element.children());
}
this.element.detach();
this.trigger(INIT, { layout: this });
},
_locate: function (selectors) {
return this.options.$angular ? directiveSelector(selectors) : roleSelector(selectors);
},
options: {
name: 'Layout',
id: null,
platform: null
},
events: [
INIT,
SHOW,
HIDE
],
setup: function (view) {
if (!view.header[0]) {
view.header = this.header;
}
if (!view.footer[0]) {
view.footer = this.footer;
}
},
detach: function (view) {
var that = this;
if (view.header === that.header && that.header[0]) {
view.element.prepend(that.header.detach()[0].cloneNode(true));
}
if (view.footer === that.footer && that.footer.length) {
view.element.append(that.footer.detach()[0].cloneNode(true));
}
},
attach: function (view) {
var that = this, previousView = that.currentView;
if (previousView) {
that.detach(previousView);
}
if (view.header === that.header) {
that.header.detach();
view.element.children(roleSelector('header')).remove();
view.element.prepend(that.header);
}
if (view.footer === that.footer) {
that.footer.detach();
view.element.children(roleSelector('footer')).remove();
view.element.append(that.footer);
}
that.trigger(SHOW, {
layout: that,
view: view
});
that.currentView = view;
}
});
var Observable = kendo.Observable, bodyRegExp = /]*>(([\u000a\u000d\u2028\u2029]|.)*)<\/body>/i, LOAD_START = 'loadStart', LOAD_COMPLETE = 'loadComplete', SHOW_START = 'showStart', SAME_VIEW_REQUESTED = 'sameViewRequested', VIEW_SHOW = 'viewShow', VIEW_TYPE_DETERMINED = 'viewTypeDetermined', AFTER = 'after';
var ViewEngine = Observable.extend({
init: function (options) {
var that = this, views, errorMessage, container, collection;
Observable.fn.init.call(that);
$.extend(that, options);
that.sandbox = $('
');
container = that.container;
views = that._hideViews(container);
that.rootView = views.first();
if (!that.rootView[0] && options.rootNeeded) {
if (container[0] == kendo.mobile.application.element[0]) {
errorMessage = 'Your kendo mobile application element does not contain any direct child elements with data-role="view" attribute set. Make sure that you instantiate the mobile application using the correct container.';
} else {
errorMessage = 'Your pane element does not contain any direct child elements with data-role="view" attribute set.';
}
throw new Error(errorMessage);
}
that.layouts = {};
that.viewContainer = new kendo.ViewContainer(that.container);
that.viewContainer.bind('accepted', function (e) {
e.view.params = that.params;
});
that.viewContainer.bind('complete', function (e) {
that.trigger(VIEW_SHOW, { view: e.view });
});
that.viewContainer.bind(AFTER, function () {
that.trigger(AFTER);
});
this.getLayoutProxy = $.proxy(this, '_getLayout');
that._setupLayouts(container);
collection = container.children(that._locate('modalview drawer'));
if (that.$angular) {
that.$angular[0].viewOptions = {
defaultTransition: that.transition,
loader: that.loader,
container: that.container,
getLayout: that.getLayoutProxy
};
collection.each(function (idx, element) {
compileMobileDirective($(element), options.$angular[0]);
});
} else {
initWidgets(collection);
}
this.bind(this.events, options);
},
events: [
SHOW_START,
AFTER,
VIEW_SHOW,
LOAD_START,
LOAD_COMPLETE,
SAME_VIEW_REQUESTED,
VIEW_TYPE_DETERMINED
],
destroy: function () {
kendo.destroy(this.container);
for (var id in this.layouts) {
this.layouts[id].destroy();
}
},
view: function () {
return this.viewContainer.view;
},
showView: function (url, transition, params) {
url = url.replace(new RegExp('^' + this.remoteViewURLPrefix), '');
if (url === '' && this.remoteViewURLPrefix) {
url = '/';
}
if (url.replace(/^#/, '') === this.url) {
this.trigger(SAME_VIEW_REQUESTED);
return false;
}
this.trigger(SHOW_START);
var that = this, showClosure = function (view) {
return that.viewContainer.show(view, transition, url);
}, element = that._findViewElement(url), view = kendo.widgetInstance(element);
that.url = url.replace(/^#/, '');
that.params = params;
if (view && view.reload) {
view.purge();
element = [];
}
this.trigger(VIEW_TYPE_DETERMINED, {
remote: element.length === 0,
url: url
});
if (element[0]) {
if (!view) {
view = that._createView(element);
}
return showClosure(view);
} else {
if (this.serverNavigation) {
location.href = url;
} else {
that._loadView(url, showClosure);
}
return true;
}
},
append: function (html, url) {
var sandbox = this.sandbox, urlPath = (url || '').split('?')[0], container = this.container, views, modalViews, view;
if (bodyRegExp.test(html)) {
html = RegExp.$1;
}
sandbox[0].innerHTML = html;
container.append(sandbox.children('script, style'));
views = this._hideViews(sandbox);
view = views.first();
if (!view.length) {
views = view = sandbox.wrapInner('
').children();
}
if (urlPath) {
view.hide().attr(attr('url'), urlPath);
}
this._setupLayouts(sandbox);
modalViews = sandbox.children(this._locate('modalview drawer'));
container.append(sandbox.children(this._locate('layout modalview drawer')).add(views));
initWidgets(modalViews);
return this._createView(view);
},
_locate: function (selectors) {
return this.$angular ? directiveSelector(selectors) : roleSelector(selectors);
},
_findViewElement: function (url) {
var element, urlPath = url.split('?')[0];
if (!urlPath) {
return this.rootView;
}
element = this.container.children('[' + attr('url') + '=\'' + urlPath + '\']');
if (!element[0] && urlPath.indexOf('/') === -1) {
element = this.container.children(urlPath.charAt(0) === '#' ? urlPath : '#' + urlPath);
}
return element;
},
_createView: function (element) {
if (this.$angular) {
return compileMobileDirective(element, this.$angular[0]);
} else {
return kendo.initWidget(element, {
defaultTransition: this.transition,
loader: this.loader,
container: this.container,
getLayout: this.getLayoutProxy,
modelScope: this.modelScope,
reload: attrValue(element, 'reload')
}, ui.roles);
}
},
_getLayout: function (name) {
if (name === '') {
return null;
}
return name ? this.layouts[name] : this.layouts[this.layout];
},
_loadView: function (url, callback) {
if (this._xhr) {
this._xhr.abort();
}
this.trigger(LOAD_START);
this._xhr = $.get(kendo.absoluteURL(url, this.remoteViewURLPrefix), 'html').always($.proxy(this, '_xhrComplete', callback, url));
},
_xhrComplete: function (callback, url, response) {
var success = true;
if (typeof response === 'object') {
if (response.status === 0) {
if (response.responseText && response.responseText.length > 0) {
success = true;
response = response.responseText;
} else {
return;
}
}
}
this.trigger(LOAD_COMPLETE);
if (success) {
callback(this.append(response, url));
}
},
_hideViews: function (container) {
return container.children(this._locate('view splitview')).hide();
},
_setupLayouts: function (element) {
var that = this, layout;
element.children(that._locate('layout')).each(function () {
if (that.$angular) {
layout = compileMobileDirective($(this), that.$angular[0]);
} else {
layout = kendo.initWidget($(this), {}, ui.roles);
}
var platform = layout.options.platform;
if (!platform || platform === mobile.application.os.name) {
that.layouts[layout.options.id] = layout;
} else {
layout.destroy();
}
});
}
});
kendo.mobile.ViewEngine = ViewEngine;
ui.plugin(View);
ui.plugin(Layout);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.loader', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'mobile.loader',
name: 'Loader',
category: 'mobile',
description: 'Mobile Loader',
depends: ['core'],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, CAPTURE_EVENTS = $.map(kendo.eventMap, function (value) {
return value;
}).join(' ').split(' ');
var Loader = Widget.extend({
init: function (container, options) {
var that = this, element = $('
');
Widget.fn.init.call(that, element, options);
that.container = container;
that.captureEvents = false;
that._attachCapture();
element.append(that.options.loading).hide().appendTo(container);
},
options: {
name: 'Loader',
loading: '
Loading...
',
timeout: 100
},
show: function () {
var that = this;
clearTimeout(that._loading);
if (that.options.loading === false) {
return;
}
that.captureEvents = true;
that._loading = setTimeout(function () {
that.element.show();
}, that.options.timeout);
},
hide: function () {
this.captureEvents = false;
clearTimeout(this._loading);
this.element.hide();
},
changeMessage: function (message) {
this.options.loading = message;
this.element.find('>h1').html(message);
},
transition: function () {
this.captureEvents = true;
this.container.css('pointer-events', 'none');
},
transitionDone: function () {
this.captureEvents = false;
this.container.css('pointer-events', '');
},
_attachCapture: function () {
var that = this;
that.captureEvents = false;
function capture(e) {
if (that.captureEvents) {
e.preventDefault();
}
}
for (var i = 0; i < CAPTURE_EVENTS.length; i++) {
that.container[0].addEventListener(CAPTURE_EVENTS[i], capture, true);
}
}
});
ui.plugin(Loader);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.pane', [
'kendo.mobile.view',
'kendo.mobile.loader'
], f);
}(function () {
var __meta__ = {
id: 'mobile.pane',
name: 'Pane',
category: 'mobile',
description: 'Mobile Pane',
depends: [
'mobile.view',
'mobile.loader'
],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, roleSelector = kendo.roleSelector, ui = mobile.ui, Widget = ui.Widget, ViewEngine = mobile.ViewEngine, View = ui.View, Loader = mobile.ui.Loader, EXTERNAL = 'external', HREF = 'href', DUMMY_HREF = '#!', NAVIGATE = 'navigate', VIEW_SHOW = 'viewShow', SAME_VIEW_REQUESTED = 'sameViewRequested', OS = kendo.support.mobileOS, SKIP_TRANSITION_ON_BACK_BUTTON = OS.ios && !OS.appMode && OS.flatVersion >= 700, WIDGET_RELS = /popover|actionsheet|modalview|drawer/, BACK = '#:back', attrValue = kendo.attrValue;
var Pane = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
options = that.options;
element = that.element;
element.addClass('km-pane');
if (that.options.collapsible) {
element.addClass('km-collapsible-pane');
}
this.history = [];
this.historyCallback = function (url, params, backButtonPressed) {
var transition = that.transition;
that.transition = null;
if (SKIP_TRANSITION_ON_BACK_BUTTON && backButtonPressed) {
transition = 'none';
}
return that.viewEngine.showView(url, transition, params);
};
this._historyNavigate = function (url) {
if (url === BACK) {
if (that.history.length === 1) {
return;
}
that.history.pop();
url = that.history[that.history.length - 1];
} else {
that.history.push(url);
}
that.historyCallback(url, kendo.parseQueryStringParams(url));
};
this._historyReplace = function (url) {
var params = kendo.parseQueryStringParams(url);
that.history[that.history.length - 1] = url;
that.historyCallback(url, params);
};
that.loader = new Loader(element, { loading: that.options.loading });
that.viewEngine = new ViewEngine({
container: element,
transition: options.transition,
modelScope: options.modelScope,
rootNeeded: !options.initial,
serverNavigation: options.serverNavigation,
remoteViewURLPrefix: options.root || '',
layout: options.layout,
$angular: options.$angular,
loader: that.loader,
showStart: function () {
that.loader.transition();
that.closeActiveDialogs();
},
after: function () {
that.loader.transitionDone();
},
viewShow: function (e) {
that.trigger(VIEW_SHOW, e);
},
loadStart: function () {
that.loader.show();
},
loadComplete: function () {
that.loader.hide();
},
sameViewRequested: function () {
that.trigger(SAME_VIEW_REQUESTED);
},
viewTypeDetermined: function (e) {
if (!e.remote || !that.options.serverNavigation) {
that.trigger(NAVIGATE, { url: e.url });
}
}
});
this._setPortraitWidth();
kendo.onResize(function () {
that._setPortraitWidth();
});
that._setupAppLinks();
},
closeActiveDialogs: function () {
var dialogs = this.element.find(roleSelector('actionsheet popover modalview')).filter(':visible');
dialogs.each(function () {
kendo.widgetInstance($(this), ui).close();
});
},
navigateToInitial: function () {
var initial = this.options.initial;
if (initial) {
this.navigate(initial);
}
return initial;
},
options: {
name: 'Pane',
portraitWidth: '',
transition: '',
layout: '',
collapsible: false,
initial: null,
modelScope: window,
loading: '
Loading...
'
},
events: [
NAVIGATE,
VIEW_SHOW,
SAME_VIEW_REQUESTED
],
append: function (html) {
return this.viewEngine.append(html);
},
destroy: function () {
Widget.fn.destroy.call(this);
this.viewEngine.destroy();
this.userEvents.destroy();
},
navigate: function (url, transition) {
if (url instanceof View) {
url = url.id;
}
this.transition = transition;
this._historyNavigate(url);
},
replace: function (url, transition) {
if (url instanceof View) {
url = url.id;
}
this.transition = transition;
this._historyReplace(url);
},
bindToRouter: function (router) {
var that = this, history = this.history, viewEngine = this.viewEngine;
router.bind('init', function (e) {
var url = e.url, attrUrl = router.pushState ? url : '/';
viewEngine.rootView.attr(kendo.attr('url'), attrUrl);
var length = history.length;
if (url === '/' && length) {
router.navigate(history[length - 1], true);
e.preventDefault();
}
});
router.bind('routeMissing', function (e) {
if (!that.historyCallback(e.url, e.params, e.backButtonPressed)) {
e.preventDefault();
}
});
router.bind('same', function () {
that.trigger(SAME_VIEW_REQUESTED);
});
that._historyNavigate = function (url) {
router.navigate(url);
};
that._historyReplace = function (url) {
router.replace(url);
};
},
hideLoading: function () {
this.loader.hide();
},
showLoading: function () {
this.loader.show();
},
changeLoadingMessage: function (message) {
this.loader.changeMessage(message);
},
view: function () {
return this.viewEngine.view();
},
_setPortraitWidth: function () {
var width, portraitWidth = this.options.portraitWidth;
if (portraitWidth) {
width = kendo.mobile.application.element.is('.km-vertical') ? portraitWidth : 'auto';
this.element.css('width', width);
}
},
_setupAppLinks: function () {
var that = this, linkRoles = 'tab', pressedButtonSelector = '[data-' + kendo.ns + 'navigate-on-press]', buttonSelectors = $.map([
'button',
'backbutton',
'detailbutton',
'listview-link'
], function (role) {
return roleSelector(role) + ':not(' + pressedButtonSelector + ')';
}).join(',');
this.element.handler(this).on('down', roleSelector(linkRoles) + ',' + pressedButtonSelector, '_mouseup').on('click', roleSelector(linkRoles) + ',' + buttonSelectors + ',' + pressedButtonSelector, '_appLinkClick');
this.userEvents = new kendo.UserEvents(this.element, {
fastTap: true,
filter: buttonSelectors,
tap: function (e) {
e.event.currentTarget = e.touch.currentTarget;
that._mouseup(e.event);
}
});
this.element.css('-ms-touch-action', '');
},
_appLinkClick: function (e) {
var href = $(e.currentTarget).attr('href');
var remote = href && href[0] !== '#' && this.options.serverNavigation;
if (!remote && attrValue($(e.currentTarget), 'rel') != EXTERNAL) {
e.preventDefault();
}
},
_mouseup: function (e) {
if (e.which > 1 || e.isDefaultPrevented()) {
return;
}
var pane = this, link = $(e.currentTarget), transition = attrValue(link, 'transition'), rel = attrValue(link, 'rel') || '', target = attrValue(link, 'target'), href = link.attr(HREF), delayedTouchEnd = SKIP_TRANSITION_ON_BACK_BUTTON && link[0].offsetHeight === 0, remote = href && href[0] !== '#' && this.options.serverNavigation;
if (delayedTouchEnd || remote || rel === EXTERNAL || typeof href === 'undefined' || href === DUMMY_HREF) {
return;
}
link.attr(HREF, DUMMY_HREF);
setTimeout(function () {
link.attr(HREF, href);
});
if (rel.match(WIDGET_RELS)) {
kendo.widgetInstance($(href), ui).openFor(link);
if (rel === 'actionsheet' || rel === 'drawer') {
e.stopPropagation();
}
} else {
if (target === '_top') {
pane = mobile.application.pane;
} else if (target) {
pane = $('#' + target).data('kendoMobilePane');
}
pane.navigate(href, transition);
}
e.preventDefault();
}
});
Pane.wrap = function (element) {
if (!element.is(roleSelector('view'))) {
element = element.wrap('
').parent();
}
var paneContainer = element.wrap('
').parent(), pane = new Pane(paneContainer);
pane.navigate('');
return pane;
};
ui.plugin(Pane);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.popover', [
'kendo.popup',
'kendo.mobile.pane'
], f);
}(function () {
var __meta__ = {
id: 'mobile.popover',
name: 'PopOver',
category: 'mobile',
description: 'The mobile PopOver widget represents a transient view which is displayed when the user taps on a navigational widget or area on the screen. ',
depends: [
'popup',
'mobile.pane'
]
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, HIDE = 'hide', OPEN = 'open', CLOSE = 'close', WRAPPER = '', ARROW = '', OVERLAY = '', DIRECTION_CLASSES = 'km-up km-down km-left km-right', Widget = ui.Widget, DIRECTIONS = {
'down': {
origin: 'bottom center',
position: 'top center'
},
'up': {
origin: 'top center',
position: 'bottom center'
},
'left': {
origin: 'center left',
position: 'center right',
collision: 'fit flip'
},
'right': {
origin: 'center right',
position: 'center left',
collision: 'fit flip'
}
}, ANIMATION = {
animation: {
open: {
effects: 'fade:in',
duration: 0
},
close: {
effects: 'fade:out',
duration: 400
}
}
}, DIMENSIONS = {
'horizontal': {
offset: 'top',
size: 'height'
},
'vertical': {
offset: 'left',
size: 'width'
}
}, REVERSE = {
'up': 'down',
'down': 'up',
'left': 'right',
'right': 'left'
};
var Popup = Widget.extend({
init: function (element, options) {
var that = this, containerPopup = element.closest('.km-modalview-wrapper'), viewport = element.closest('.km-root').children('.km-pane').first(), container = containerPopup[0] ? containerPopup : viewport, popupOptions, axis;
if (options.viewport) {
viewport = options.viewport;
} else if (!viewport[0]) {
viewport = window;
}
if (options.container) {
container = options.container;
} else if (!container[0]) {
container = document.body;
}
popupOptions = {
viewport: viewport,
copyAnchorStyles: false,
autosize: true,
open: function () {
that.overlay.show();
},
activate: $.proxy(that._activate, that),
deactivate: function () {
that.overlay.hide();
if (!that._apiCall) {
that.trigger(HIDE);
}
that._apiCall = false;
}
};
Widget.fn.init.call(that, element, options);
element = that.element;
options = that.options;
element.wrap(WRAPPER).addClass('km-popup').show();
axis = that.options.direction.match(/left|right/) ? 'horizontal' : 'vertical';
that.dimensions = DIMENSIONS[axis];
that.wrapper = element.parent().css({
width: options.width,
height: options.height
}).addClass('km-popup-wrapper km-' + options.direction).hide();
that.arrow = $(ARROW).prependTo(that.wrapper).hide();
that.overlay = $(OVERLAY).appendTo(container).hide();
popupOptions.appendTo = that.overlay;
if (options.className) {
that.overlay.addClass(options.className);
}
that.popup = new kendo.ui.Popup(that.wrapper, $.extend(true, popupOptions, ANIMATION, DIRECTIONS[options.direction]));
},
options: {
name: 'Popup',
width: 240,
height: '',
direction: 'down',
container: null,
viewport: null
},
events: [HIDE],
show: function (target) {
this.popup.options.anchor = $(target);
this.popup.open();
},
hide: function () {
this._apiCall = true;
this.popup.close();
},
destroy: function () {
Widget.fn.destroy.call(this);
this.popup.destroy();
this.overlay.remove();
},
target: function () {
return this.popup.options.anchor;
},
_activate: function () {
var that = this, direction = that.options.direction, dimensions = that.dimensions, offset = dimensions.offset, popup = that.popup, anchor = popup.options.anchor, anchorOffset = $(anchor).offset(), elementOffset = $(popup.element).offset(), cssClass = popup.flipped ? REVERSE[direction] : direction, min = that.arrow[dimensions.size]() * 2, max = that.element[dimensions.size]() - that.arrow[dimensions.size](), size = $(anchor)[dimensions.size](), offsetAmount = anchorOffset[offset] - elementOffset[offset] + size / 2;
if (offsetAmount < min) {
offsetAmount = min;
}
if (offsetAmount > max) {
offsetAmount = max;
}
that.wrapper.removeClass(DIRECTION_CLASSES).addClass('km-' + cssClass);
that.arrow.css(offset, offsetAmount).show();
}
});
var PopOver = Widget.extend({
init: function (element, options) {
var that = this, popupOptions;
that.initialOpen = false;
Widget.fn.init.call(that, element, options);
popupOptions = $.extend({
className: 'km-popover-root',
hide: function () {
that.trigger(CLOSE);
}
}, this.options.popup);
that.popup = new Popup(that.element, popupOptions);
that.popup.overlay.on('move', function (e) {
if (e.target == that.popup.overlay[0]) {
e.preventDefault();
}
});
that.pane = new ui.Pane(that.element, $.extend(this.options.pane, { $angular: this.options.$angular }));
kendo.notify(that, ui);
},
options: {
name: 'PopOver',
popup: {},
pane: {}
},
events: [
OPEN,
CLOSE
],
open: function (target) {
this.popup.show(target);
if (!this.initialOpen) {
if (!this.pane.navigateToInitial()) {
this.pane.navigate('');
}
this.popup.popup._position();
this.initialOpen = true;
} else {
this.pane.view()._invokeNgController();
}
},
openFor: function (target) {
this.open(target);
this.trigger(OPEN, { target: this.popup.target() });
},
close: function () {
this.popup.hide();
},
destroy: function () {
Widget.fn.destroy.call(this);
this.pane.destroy();
this.popup.destroy();
kendo.destroy(this.element);
}
});
ui.plugin(Popup);
ui.plugin(PopOver);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.shim', ['kendo.popup'], f);
}(function () {
var __meta__ = {
id: 'mobile.shim',
name: 'Shim',
category: 'mobile',
description: 'Mobile Shim',
depends: ['popup'],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Popup = kendo.ui.Popup, SHIM = '
', HIDE = 'hide', Widget = ui.Widget;
var Shim = Widget.extend({
init: function (element, options) {
var that = this, app = kendo.mobile.application, os = kendo.support.mobileOS, osname = app ? app.os.name : os ? os.name : 'ios', ioswp = osname === 'ios' || osname === 'wp' || (app ? app.os.skin : false), bb = osname === 'blackberry', align = options.align || (ioswp ? 'bottom center' : bb ? 'center right' : 'center center'), position = options.position || (ioswp ? 'bottom center' : bb ? 'center right' : 'center center'), effect = options.effect || (ioswp ? 'slideIn:up' : bb ? 'slideIn:left' : 'fade:in'), shim = $(SHIM).handler(that).hide();
Widget.fn.init.call(that, element, options);
that.shim = shim;
element = that.element;
options = that.options;
if (options.className) {
that.shim.addClass(options.className);
}
if (!options.modal) {
that.shim.on('down', '_hide');
}
(app ? app.element : $(document.body)).append(shim);
that.popup = new Popup(that.element, {
anchor: shim,
modal: true,
appendTo: shim,
origin: align,
position: position,
animation: {
open: {
effects: effect,
duration: options.duration
},
close: { duration: options.duration }
},
close: function (e) {
var prevented = false;
if (!that._apiCall) {
prevented = that.trigger(HIDE);
}
if (prevented) {
e.preventDefault();
}
that._apiCall = false;
},
deactivate: function () {
shim.hide();
},
open: function () {
shim.show();
}
});
kendo.notify(that);
},
events: [HIDE],
options: {
name: 'Shim',
modal: false,
align: undefined,
position: undefined,
effect: undefined,
duration: 200
},
show: function () {
this.popup.open();
},
hide: function () {
this._apiCall = true;
this.popup.close();
},
destroy: function () {
Widget.fn.destroy.call(this);
this.shim.kendoDestroy();
this.popup.destroy();
this.shim.remove();
},
_hide: function (e) {
if (!e || !$.contains(this.shim.children().children('.k-popup')[0], e.target)) {
this.popup.close();
}
}
});
ui.plugin(Shim);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.modalview', [
'kendo.mobile.shim',
'kendo.mobile.view'
], f);
}(function () {
var __meta__ = {
id: 'mobile.modalview',
name: 'ModalView',
category: 'mobile',
description: 'The Kendo ModalView is used to present self-contained functionality in the context of the current task.',
depends: [
'mobile.shim',
'mobile.view'
]
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Shim = ui.Shim, Widget = ui.Widget, BEFORE_OPEN = 'beforeOpen', OPEN = 'open', CLOSE = 'close', INIT = 'init', WRAP = '
';
var ModalView = ui.View.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
that._id();
that._wrap();
that._shim();
if (!this.options.$angular) {
that._layout();
that._scroller();
that._model();
}
that.element.css('display', '');
that.trigger(INIT);
},
events: [
INIT,
BEFORE_OPEN,
OPEN,
CLOSE
],
options: {
name: 'ModalView',
modal: true,
width: null,
height: null
},
destroy: function () {
Widget.fn.destroy.call(this);
this.shim.destroy();
},
open: function (target) {
var that = this;
that.target = $(target);
that.shim.show();
that._invokeNgController();
that.trigger('show', { view: that });
},
openFor: function (target) {
if (!this.trigger(BEFORE_OPEN, { target: target })) {
this.open(target);
this.trigger(OPEN, { target: target });
}
},
close: function () {
if (this.element.is(':visible') && !this.trigger(CLOSE)) {
this.shim.hide();
}
},
_wrap: function () {
var that = this, element = that.element, options = that.options, width, height;
width = element[0].style.width || 'auto';
height = element[0].style.height || 'auto';
element.addClass('km-modalview').wrap(WRAP);
that.wrapper = element.parent().css({
width: options.width || width || 300,
height: options.height || height || 300
}).addClass(height == 'auto' ? ' km-auto-height' : '');
element.css({
width: '',
height: ''
});
},
_shim: function () {
var that = this;
that.shim = new Shim(that.wrapper, {
modal: that.options.modal,
position: 'center center',
align: 'center center',
effect: 'fade:in',
className: 'km-modalview-root',
hide: function (e) {
if (that.trigger(CLOSE)) {
e.preventDefault();
}
}
});
}
});
ui.plugin(ModalView);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.drawer', [
'kendo.mobile.view',
'kendo.userevents'
], f);
}(function () {
var __meta__ = {
id: 'mobile.drawer',
name: 'Drawer',
category: 'mobile',
description: 'The Kendo Mobile Drawer widget provides slide to reveal global application toolbox',
depends: [
'mobile.view',
'userevents'
]
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, os = kendo.support.mobileOS, Transition = kendo.effects.Transition, roleSelector = kendo.roleSelector, AXIS = 'x', ui = mobile.ui, SWIPE_TO_OPEN = !(os.ios && os.majorVersion == 7 && !os.appMode), BEFORE_SHOW = 'beforeShow', INIT = 'init', SHOW = 'show', HIDE = 'hide', AFTER_HIDE = 'afterHide', NULL_VIEW = { enable: $.noop };
var Drawer = ui.View.extend({
init: function (element, options) {
$(element).parent().prepend(element);
mobile.ui.Widget.fn.init.call(this, element, options);
if (!this.options.$angular) {
this._layout();
this._scroller();
}
this._model();
var pane = this.element.closest(roleSelector('pane')).data('kendoMobilePane'), userEvents;
if (pane) {
this.pane = pane;
this.pane.bind('viewShow', function (e) {
drawer._viewShow(e);
});
this.pane.bind('sameViewRequested', function () {
drawer.hide();
});
userEvents = this.userEvents = new kendo.UserEvents(pane.element, {
fastTap: true,
filter: roleSelector('view splitview'),
allowSelection: true
});
} else {
this.currentView = NULL_VIEW;
var container = $(this.options.container);
if (!container) {
throw new Error('The drawer needs a container configuration option set.');
}
userEvents = this.userEvents = new kendo.UserEvents(container, {
fastTap: true,
allowSelection: true
});
this._attachTransition(container);
}
var drawer = this;
var hide = function (e) {
if (drawer.visible) {
drawer.hide();
e.preventDefault();
}
};
if (this.options.swipeToOpen && SWIPE_TO_OPEN) {
userEvents.bind('press', function () {
drawer.transition.cancel();
});
userEvents.bind('start', function (e) {
drawer._start(e);
});
userEvents.bind('move', function (e) {
drawer._update(e);
});
userEvents.bind('end', function (e) {
drawer._end(e);
});
userEvents.bind('tap', hide);
} else {
userEvents.bind('press', hide);
}
this.leftPositioned = this.options.position === 'left';
this.visible = false;
this.element.hide().addClass('km-drawer').addClass(this.leftPositioned ? 'km-left-drawer' : 'km-right-drawer');
this.trigger(INIT);
},
options: {
name: 'Drawer',
position: 'left',
views: [],
swipeToOpenViews: [],
swipeToOpen: true,
title: '',
container: null
},
events: [
BEFORE_SHOW,
HIDE,
AFTER_HIDE,
INIT,
SHOW
],
show: function () {
if (this._activate()) {
this._show();
}
},
hide: function () {
if (!this.currentView) {
return;
}
this.currentView.enable();
Drawer.current = null;
this._moveViewTo(0);
this.trigger(HIDE, { view: this });
},
openFor: function () {
if (this.visible) {
this.hide();
} else {
this.show();
}
},
destroy: function () {
ui.View.fn.destroy.call(this);
this.userEvents.destroy();
},
_activate: function () {
if (this.visible) {
return true;
}
var visibleOnCurrentView = this._currentViewIncludedIn(this.options.views);
if (!visibleOnCurrentView || this.trigger(BEFORE_SHOW, { view: this })) {
return false;
}
this._setAsCurrent();
this.element.show();
this.trigger(SHOW, { view: this });
this._invokeNgController();
return true;
},
_currentViewIncludedIn: function (views) {
if (!this.pane || !views.length) {
return true;
}
var view = this.pane.view();
return $.inArray(view.id.replace('#', ''), views) > -1 || $.inArray(view.element.attr('id'), views) > -1;
},
_show: function () {
this.currentView.enable(false);
this.visible = true;
var offset = this.element.width();
if (!this.leftPositioned) {
offset = -offset;
}
this._moveViewTo(offset);
},
_setAsCurrent: function () {
if (Drawer.last !== this) {
if (Drawer.last) {
Drawer.last.element.hide();
}
this.element.show();
}
Drawer.last = this;
Drawer.current = this;
},
_moveViewTo: function (offset) {
this.userEvents.cancel();
this.transition.moveTo({
location: offset,
duration: 400,
ease: Transition.easeOutExpo
});
},
_viewShow: function (e) {
if (this.currentView) {
this.currentView.enable();
}
if (this.currentView === e.view) {
this.hide();
return;
}
this.currentView = e.view;
this._attachTransition(e.view.element);
},
_attachTransition: function (element) {
var that = this, movable = this.movable, currentOffset = movable && movable.x;
if (this.transition) {
this.transition.cancel();
this.movable.moveAxis('x', 0);
}
movable = this.movable = new kendo.ui.Movable(element);
this.transition = new Transition({
axis: AXIS,
movable: this.movable,
onEnd: function () {
if (movable[AXIS] === 0) {
element[0].style.cssText = '';
that.element.hide();
that.trigger(AFTER_HIDE);
that.visible = false;
}
}
});
if (currentOffset) {
element.addClass('k-fx-hidden');
kendo.animationFrame(function () {
element.removeClass('k-fx-hidden');
that.movable.moveAxis(AXIS, currentOffset);
that.hide();
});
}
},
_start: function (e) {
var userEvents = e.sender;
if (Math.abs(e.x.velocity) < Math.abs(e.y.velocity) || kendo.triggeredByInput(e.event) || !this._currentViewIncludedIn(this.options.swipeToOpenViews)) {
userEvents.cancel();
return;
}
var leftPositioned = this.leftPositioned, visible = this.visible, canMoveLeft = leftPositioned && visible || !leftPositioned && !Drawer.current, canMoveRight = !leftPositioned && visible || leftPositioned && !Drawer.current, leftSwipe = e.x.velocity < 0;
if (canMoveLeft && leftSwipe || canMoveRight && !leftSwipe) {
if (this._activate()) {
userEvents.capture();
return;
}
}
userEvents.cancel();
},
_update: function (e) {
var movable = this.movable, newPosition = movable.x + e.x.delta, limitedPosition;
if (this.leftPositioned) {
limitedPosition = Math.min(Math.max(0, newPosition), this.element.width());
} else {
limitedPosition = Math.max(Math.min(0, newPosition), -this.element.width());
}
this.movable.moveAxis(AXIS, limitedPosition);
e.event.preventDefault();
e.event.stopPropagation();
},
_end: function (e) {
var velocity = e.x.velocity, pastHalf = Math.abs(this.movable.x) > this.element.width() / 2, velocityThreshold = 0.8, shouldShow;
if (this.leftPositioned) {
shouldShow = velocity > -velocityThreshold && (velocity > velocityThreshold || pastHalf);
} else {
shouldShow = velocity < velocityThreshold && (velocity < -velocityThreshold || pastHalf);
}
if (shouldShow) {
this._show();
} else {
this.hide();
}
}
});
ui.plugin(Drawer);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.splitview', ['kendo.mobile.pane'], f);
}(function () {
var __meta__ = {
id: 'mobile.splitview',
name: 'SplitView',
category: 'mobile',
description: 'The mobile SplitView is a tablet-specific view that consists of two or more mobile Pane widgets.',
depends: ['mobile.pane']
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, EXPANED_PANE_SHIM = '
', View = ui.View;
var SplitView = View.extend({
init: function (element, options) {
var that = this, pane, modalViews;
Widget.fn.init.call(that, element, options);
element = that.element;
$.extend(that, options);
that._id();
if (!that.options.$angular) {
that._layout();
that._overlay();
} else {
that._overlay();
}
that._style();
modalViews = element.children(that._locate('modalview'));
if (!that.options.$angular) {
kendo.mobile.init(modalViews);
} else {
modalViews.each(function (idx, element) {
kendo.compileMobileDirective($(element), options.$angular[0]);
});
}
that.panes = [];
that._paramsHistory = [];
if (!that.options.$angular) {
that.content.children(kendo.roleSelector('pane')).each(function () {
pane = kendo.initWidget(this, {}, ui.roles);
that.panes.push(pane);
});
} else {
that.element.children(kendo.directiveSelector('pane')).each(function () {
pane = kendo.compileMobileDirective($(this), options.$angular[0]);
that.panes.push(pane);
});
that.element.children(kendo.directiveSelector('header footer')).each(function () {
kendo.compileMobileDirective($(this), options.$angular[0]);
});
}
that.expandedPaneShim = $(EXPANED_PANE_SHIM).appendTo(that.element);
that._shimUserEvents = new kendo.UserEvents(that.expandedPaneShim, {
fastTap: true,
tap: function () {
that.collapsePanes();
}
});
},
_locate: function (selectors) {
return this.options.$angular ? kendo.directiveSelector(selectors) : kendo.roleSelector(selectors);
},
options: {
name: 'SplitView',
style: 'horizontal'
},
expandPanes: function () {
this.element.addClass('km-expanded-splitview');
},
collapsePanes: function () {
this.element.removeClass('km-expanded-splitview');
},
_layout: function () {
var that = this, element = that.element;
that.transition = kendo.attrValue(element, 'transition');
kendo.mobile.ui.View.prototype._layout.call(this);
kendo.mobile.init(this.header.add(this.footer));
that.element.addClass('km-splitview');
that.content.addClass('km-split-content');
},
_style: function () {
var style = this.options.style, element = this.element, styles;
if (style) {
styles = style.split(' ');
$.each(styles, function () {
element.addClass('km-split-' + this);
});
}
},
showStart: function () {
var that = this;
that.element.css('display', '');
if (!that.inited) {
that.inited = true;
$.each(that.panes, function () {
if (this.options.initial) {
this.navigateToInitial();
} else {
this.navigate('');
}
});
that.trigger('init', { view: that });
} else {
this._invokeNgController();
}
that.trigger('show', { view: that });
}
});
ui.plugin(SplitView);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.application', [
'kendo.mobile.pane',
'kendo.router'
], f);
}(function () {
var __meta__ = {
id: 'mobile.application',
name: 'Application',
category: 'mobile',
description: 'The Mobile application provides a framework to build native looking web applications on mobile devices.',
depends: [
'mobile.pane',
'router'
]
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, support = kendo.support, Widget = mobile.ui.Widget, Pane = mobile.ui.Pane, DEFAULT_OS = 'ios7', OS = support.mobileOS, BERRYPHONEGAP = OS.device == 'blackberry' && OS.flatVersion >= 600 && OS.flatVersion < 1000 && OS.appMode, FONT_SIZE_COEF = 0.93, VERTICAL = 'km-vertical', CHROME = OS.browser === 'chrome', BROKEN_WEBVIEW_RESIZE = OS.ios && OS.flatVersion >= 700 && OS.flatVersion < 800 && (OS.appMode || CHROME), INITIALLY_HORIZONTAL = Math.abs(window.orientation) / 90 == 1, HORIZONTAL = 'km-horizontal', MOBILE_PLATFORMS = {
ios7: {
ios: true,
browser: 'default',
device: 'iphone',
flatVersion: '700',
majorVersion: '7',
minorVersion: '0.0',
name: 'ios',
tablet: false
},
ios: {
ios: true,
browser: 'default',
device: 'iphone',
flatVersion: '612',
majorVersion: '6',
minorVersion: '1.2',
name: 'ios',
tablet: false
},
android: {
android: true,
browser: 'default',
device: 'android',
flatVersion: '442',
majorVersion: '4',
minorVersion: '4.2',
name: 'android',
tablet: false
},
blackberry: {
blackberry: true,
browser: 'default',
device: 'blackberry',
flatVersion: '710',
majorVersion: '7',
minorVersion: '1.0',
name: 'blackberry',
tablet: false
},
meego: {
meego: true,
browser: 'default',
device: 'meego',
flatVersion: '850',
majorVersion: '8',
minorVersion: '5.0',
name: 'meego',
tablet: false
},
wp: {
wp: true,
browser: 'default',
device: 'wp',
flatVersion: '800',
majorVersion: '8',
minorVersion: '0.0',
name: 'wp',
tablet: false
}
}, viewportTemplate = kendo.template('
', { usedWithBlock: false }), systemMeta = kendo.template('
' + '
' + '
', { usedWithBlock: false }), clipTemplate = kendo.template('', { usedWithBlock: false }), ENABLE_CLIP = OS.android && OS.browser != 'chrome' || OS.blackberry, iconMeta = kendo.template('
', { usedWithBlock: false }), HIDEBAR = (OS.device == 'iphone' || OS.device == 'ipod') && OS.majorVersion < 7, SUPPORT_SWIPE_TO_GO_BACK = (OS.device == 'iphone' || OS.device == 'ipod') && OS.majorVersion >= 7, HISTORY_TRANSITION = SUPPORT_SWIPE_TO_GO_BACK ? 'none' : null, BARCOMPENSATION = OS.browser == 'mobilesafari' ? 60 : 0, STATUS_BAR_HEIGHT = 20, WINDOW = $(window), SCREEN = window.screen, HEAD = $('head'), INIT = 'init', proxy = $.proxy;
function osCssClass(os, options) {
var classes = [];
if (OS) {
classes.push('km-on-' + OS.name);
}
if (os.skin) {
classes.push('km-' + os.skin);
} else {
if (os.name == 'ios' && os.majorVersion > 6) {
classes.push('km-ios7');
} else {
classes.push('km-' + os.name);
}
}
if (os.name == 'ios' && os.majorVersion < 7 || os.name != 'ios') {
classes.push('km-' + os.name + os.majorVersion);
}
classes.push('km-' + os.majorVersion);
classes.push('km-m' + (os.minorVersion ? os.minorVersion[0] : 0));
if (os.variant && (os.skin && os.skin === os.name || !os.skin || os.setDefaultPlatform === false)) {
classes.push('km-' + (os.skin ? os.skin : os.name) + '-' + os.variant);
}
if (os.cordova) {
classes.push('km-cordova');
}
if (os.appMode) {
classes.push('km-app');
} else {
classes.push('km-web');
}
if (options && options.statusBarStyle) {
classes.push('km-' + options.statusBarStyle + '-status-bar');
}
return classes.join(' ');
}
function wp8Background(os) {
return 'km-wp-' + (os.noVariantSet ? parseInt($('
').css('background-color').split(',')[1], 10) === 0 ? 'dark' : 'light' : os.variant + ' km-wp-' + os.variant + '-force');
}
function isOrientationHorizontal(element) {
return OS.wp ? element.css('animation-name') == '-kendo-landscape' : Math.abs(window.orientation) / 90 == 1;
}
function getOrientationClass(element) {
return isOrientationHorizontal(element) ? HORIZONTAL : VERTICAL;
}
function setMinimumHeight(pane) {
pane.parent().addBack().css('min-height', window.innerHeight);
}
function applyViewportHeight() {
$('meta[name=viewport]').remove();
HEAD.append(viewportTemplate({ height: ', width=device-width' + (isOrientationHorizontal() ? ', height=' + window.innerHeight + 'px' : support.mobileOS.flatVersion >= 600 && support.mobileOS.flatVersion < 700 ? ', height=' + window.innerWidth + 'px' : ', height=device-height') }));
}
var Application = Widget.extend({
init: function (element, options) {
mobile.application = this;
$($.proxy(this, 'bootstrap', element, options));
},
bootstrap: function (element, options) {
element = $(element);
if (!element[0]) {
element = $(document.body);
}
Widget.fn.init.call(this, element, options);
this.element.removeAttr('data-' + kendo.ns + 'role');
this._setupPlatform();
this._attachMeta();
this._setupElementClass();
this._attachHideBarHandlers();
var paneOptions = $.extend({}, this.options);
delete paneOptions.name;
var that = this, startHistory = function () {
that.pane = new Pane(that.element, paneOptions);
that.pane.navigateToInitial();
if (that.options.updateDocumentTitle) {
that._setupDocumentTitle();
}
that._startHistory();
that.trigger(INIT);
};
if (this.options.$angular) {
setTimeout(startHistory);
} else {
startHistory();
}
},
options: {
name: 'Application',
hideAddressBar: true,
browserHistory: true,
historyTransition: HISTORY_TRANSITION,
modelScope: window,
statusBarStyle: 'black',
transition: '',
retina: false,
platform: null,
skin: null,
updateDocumentTitle: true,
useNativeScrolling: false
},
events: [INIT],
navigate: function (url, transition) {
this.pane.navigate(url, transition);
},
replace: function (url, transition) {
this.pane.replace(url, transition);
},
scroller: function () {
return this.view().scroller;
},
hideLoading: function () {
if (this.pane) {
this.pane.hideLoading();
} else {
throw new Error('The mobile application instance is not fully instantiated. Please consider activating loading in the application init event handler.');
}
},
showLoading: function () {
if (this.pane) {
this.pane.showLoading();
} else {
throw new Error('The mobile application instance is not fully instantiated. Please consider activating loading in the application init event handler.');
}
},
changeLoadingMessage: function (message) {
if (this.pane) {
this.pane.changeLoadingMessage(message);
} else {
throw new Error('The mobile application instance is not fully instantiated. Please consider changing the message in the application init event handler.');
}
},
view: function () {
return this.pane.view();
},
skin: function (skin) {
var that = this;
if (!arguments.length) {
return that.options.skin;
}
that.options.skin = skin || '';
that.element[0].className = 'km-pane';
that._setupPlatform();
that._setupElementClass();
return that.options.skin;
},
destroy: function () {
Widget.fn.destroy.call(this);
this.pane.destroy();
this.router.destroy();
},
_setupPlatform: function () {
var that = this, platform = that.options.platform, skin = that.options.skin, split = [], os = OS || MOBILE_PLATFORMS[DEFAULT_OS];
if (platform) {
os.setDefaultPlatform = true;
if (typeof platform === 'string') {
split = platform.split('-');
os = $.extend({ variant: split[1] }, os, MOBILE_PLATFORMS[split[0]]);
} else {
os = platform;
}
}
if (skin) {
split = skin.split('-');
if (!OS) {
os.setDefaultPlatform = false;
}
os = $.extend({}, os, {
skin: split[0],
variant: split[1]
});
}
if (!os.variant) {
os.noVariantSet = true;
os.variant = 'dark';
}
that.os = os;
that.osCssClass = osCssClass(that.os, that.options);
if (os.name == 'wp') {
if (!that.refreshBackgroundColorProxy) {
that.refreshBackgroundColorProxy = $.proxy(function () {
if (that.os.variant && (that.os.skin && that.os.skin === that.os.name) || !that.os.skin) {
that.element.removeClass('km-wp-dark km-wp-light km-wp-dark-force km-wp-light-force').addClass(wp8Background(that.os));
}
}, that);
}
$(document).off('visibilitychange', that.refreshBackgroundColorProxy);
$(document).off('resume', that.refreshBackgroundColorProxy);
if (!os.skin) {
that.element.parent().css('overflow', 'hidden');
$(document).on('visibilitychange', that.refreshBackgroundColorProxy);
$(document).on('resume', that.refreshBackgroundColorProxy);
that.refreshBackgroundColorProxy();
}
}
},
_startHistory: function () {
if (this.options.browserHistory) {
this.router = new kendo.Router({
pushState: this.options.pushState,
root: this.options.root,
hashBang: this.options.hashBang
});
this.pane.bindToRouter(this.router);
this.router.start();
} else {
if (!this.options.initial) {
this.pane.navigate('');
}
}
},
_resizeToScreenHeight: function () {
var includeStatusBar = $('meta[name=apple-mobile-web-app-status-bar-style]').attr('content').match(/black-translucent|hidden/), element = this.element, height;
if (CHROME) {
height = window.innerHeight;
} else {
if (isOrientationHorizontal(element)) {
if (includeStatusBar) {
if (INITIALLY_HORIZONTAL) {
height = SCREEN.availWidth + STATUS_BAR_HEIGHT;
} else {
height = SCREEN.availWidth;
}
} else {
if (INITIALLY_HORIZONTAL) {
height = SCREEN.availWidth;
} else {
height = SCREEN.availWidth - STATUS_BAR_HEIGHT;
}
}
} else {
if (includeStatusBar) {
if (INITIALLY_HORIZONTAL) {
height = SCREEN.availHeight;
} else {
height = SCREEN.availHeight + STATUS_BAR_HEIGHT;
}
} else {
if (INITIALLY_HORIZONTAL) {
height = SCREEN.availHeight - STATUS_BAR_HEIGHT;
} else {
height = SCREEN.availHeight;
}
}
}
}
element.height(height);
},
_setupElementClass: function () {
var that = this, size, element = that.element;
element.parent().addClass('km-root km-' + (that.os.tablet ? 'tablet' : 'phone'));
element.addClass(that.osCssClass + ' ' + getOrientationClass(element));
if (this.options.useNativeScrolling) {
element.parent().addClass('km-native-scrolling');
}
if (CHROME) {
element.addClass('km-ios-chrome');
}
if (support.wpDevicePixelRatio) {
element.parent().css('font-size', support.wpDevicePixelRatio + 'em');
}
if (this.options.retina) {
element.parent().addClass('km-retina');
element.parent().css('font-size', support.devicePixelRatio * FONT_SIZE_COEF + 'em');
}
if (BERRYPHONEGAP) {
applyViewportHeight();
}
if (that.options.useNativeScrolling) {
element.parent().addClass('km-native-scrolling');
} else if (ENABLE_CLIP) {
size = (screen.availWidth > screen.availHeight ? screen.availWidth : screen.availHeight) + 200;
$(clipTemplate({
width: size,
height: size
})).appendTo(HEAD);
}
if (BROKEN_WEBVIEW_RESIZE) {
that._resizeToScreenHeight();
}
kendo.onResize(function () {
element.removeClass('km-horizontal km-vertical').addClass(getOrientationClass(element));
if (that.options.useNativeScrolling) {
setMinimumHeight(element);
}
if (BROKEN_WEBVIEW_RESIZE) {
that._resizeToScreenHeight();
}
if (BERRYPHONEGAP) {
applyViewportHeight();
}
kendo.resize(element);
});
},
_clearExistingMeta: function () {
HEAD.find('meta').filter('[name|=\'apple-mobile-web-app\'],[name|=\'msapplication-tap\'],[name=\'viewport\']').remove();
},
_attachMeta: function () {
var options = this.options, icon = options.icon, size;
this._clearExistingMeta();
if (!BERRYPHONEGAP) {
HEAD.prepend(viewportTemplate({
height: '',
scale: this.options.retina ? 1 / support.devicePixelRatio : '1.0'
}));
}
HEAD.prepend(systemMeta(options));
if (icon) {
if (typeof icon === 'string') {
icon = { '': icon };
}
for (size in icon) {
HEAD.prepend(iconMeta({
icon: icon[size],
size: size
}));
}
}
if (options.useNativeScrolling) {
setMinimumHeight(this.element);
}
},
_attachHideBarHandlers: function () {
var that = this, hideBar = proxy(that, '_hideBar');
if (support.mobileOS.appMode || !that.options.hideAddressBar || !HIDEBAR || that.options.useNativeScrolling) {
return;
}
that._initialHeight = {};
WINDOW.on('load', hideBar);
kendo.onResize(function () {
setTimeout(window.scrollTo, 0, 0, 1);
});
},
_setupDocumentTitle: function () {
var that = this, defaultTitle = document.title;
that.pane.bind('viewShow', function (e) {
var title = e.view.title;
document.title = title !== undefined ? title : defaultTitle;
});
},
_hideBar: function () {
var that = this, element = that.element;
element.height(kendo.support.transforms.css + 'calc(100% + ' + BARCOMPENSATION + 'px)');
$(window).trigger(kendo.support.resize);
}
});
kendo.mobile.Application = Application;
kendo.ui.plugin(Application, kendo.mobile, 'Mobile');
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.actionsheet', [
'kendo.mobile.popover',
'kendo.mobile.shim'
], f);
}(function () {
var __meta__ = {
id: 'mobile.actionsheet',
name: 'ActionSheet',
category: 'mobile',
description: 'The mobile ActionSheet widget displays a set of choices related to a task the user initiates.',
depends: [
'mobile.popover',
'mobile.shim'
]
};
(function ($, undefined) {
var kendo = window.kendo, support = kendo.support, ui = kendo.mobile.ui, Shim = ui.Shim, Popup = ui.Popup, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', COMMAND = 'command', BUTTONS = 'li>a', CONTEXT_DATA = 'actionsheetContext', WRAP = '
', cancelTemplate = kendo.template('
#:cancel#');
var ActionSheet = Widget.extend({
init: function (element, options) {
var that = this, ShimClass, tablet, type, os = support.mobileOS;
Widget.fn.init.call(that, element, options);
options = that.options;
type = options.type;
element = that.element;
if (type === 'auto') {
tablet = os && os.tablet;
} else {
tablet = type === 'tablet';
}
ShimClass = tablet ? Popup : Shim;
if (options.cancelTemplate) {
cancelTemplate = kendo.template(options.cancelTemplate);
}
element.addClass('km-actionsheet').append(cancelTemplate({ cancel: that.options.cancel })).wrap(WRAP).on('up', BUTTONS, '_click').on('click', BUTTONS, kendo.preventDefault);
that.view().bind('destroy', function () {
that.destroy();
});
that.wrapper = element.parent().addClass(type ? ' km-actionsheet-' + type : '');
that.shim = new ShimClass(that.wrapper, $.extend({
modal: os.ios && os.majorVersion < 7,
className: 'km-actionsheet-root'
}, that.options.popup));
that._closeProxy = $.proxy(that, '_close');
that._shimHideProxy = $.proxy(that, '_shimHide');
that.shim.bind('hide', that._shimHideProxy);
if (tablet) {
kendo.onResize(that._closeProxy);
}
kendo.notify(that, ui);
},
events: [
OPEN,
CLOSE,
COMMAND
],
options: {
name: 'ActionSheet',
cancel: 'Cancel',
type: 'auto',
popup: { height: 'auto' }
},
open: function (target, context) {
var that = this;
that.target = $(target);
that.context = context;
that.shim.show(target);
},
close: function () {
this.context = this.target = null;
this.shim.hide();
},
openFor: function (target) {
var that = this, context = target.data(CONTEXT_DATA);
that.open(target, context);
that.trigger(OPEN, {
target: target,
context: context
});
},
destroy: function () {
Widget.fn.destroy.call(this);
kendo.unbindResize(this._closeProxy);
this.shim.destroy();
},
_click: function (e) {
if (e.isDefaultPrevented()) {
return;
}
var currentTarget = $(e.currentTarget);
var action = currentTarget.data('action');
if (action) {
var actionData = {
target: this.target,
context: this.context
}, $angular = this.options.$angular;
if ($angular) {
this.element.injector().get('$parse')(action)($angular[0])(actionData);
} else {
kendo.getter(action)(window)(actionData);
}
}
this.trigger(COMMAND, {
target: this.target,
context: this.context,
currentTarget: currentTarget
});
e.preventDefault();
this._close();
},
_shimHide: function (e) {
if (!this.trigger(CLOSE)) {
this.context = this.target = null;
} else {
e.preventDefault();
}
},
_close: function (e) {
if (!this.trigger(CLOSE)) {
this.close();
} else {
e.preventDefault();
}
}
});
ui.plugin(ActionSheet);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.button', ['kendo.userevents'], f);
}(function () {
var __meta__ = {
id: 'mobile.button',
name: 'Button',
category: 'mobile',
description: 'The Button widget navigates between mobile Application views when pressed.',
depends: ['userevents']
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, Widget = ui.Widget, support = kendo.support, os = support.mobileOS, ANDROID3UP = os.android && os.flatVersion >= 300, CLICK = 'click', DISABLED = 'disabled', DISABLEDSTATE = 'km-state-disabled';
function highlightButton(widget, event, highlight) {
$(event.target).closest('.km-button,.km-detail').toggleClass('km-state-active', highlight);
if (ANDROID3UP && widget.deactivateTimeoutID) {
clearTimeout(widget.deactivateTimeoutID);
widget.deactivateTimeoutID = 0;
}
}
function createBadge(value) {
return $('
' + value + '');
}
var Button = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
var useTap = that.options.clickOn === 'up';
that._wrap();
that._style();
if (!useTap) {
that.element.attr('data-navigate-on-press', true);
}
that.options.enable = that.options.enable && !that.element.attr(DISABLED);
that.enable(that.options.enable);
that._userEvents = new kendo.UserEvents(that.element, {
allowSelection: !useTap,
fastTap: true,
press: function (e) {
that._activate(e);
},
release: function (e) {
highlightButton(that, e, false);
if (!useTap) {
e.event.stopPropagation();
}
}
});
that._userEvents.bind(useTap ? 'tap' : 'press', function (e) {
that._release(e);
});
if (ANDROID3UP) {
that.element.on('move', function (e) {
that._timeoutDeactivate(e);
});
}
},
destroy: function () {
Widget.fn.destroy.call(this);
this._userEvents.destroy();
},
events: [CLICK],
options: {
name: 'Button',
icon: '',
style: '',
badge: '',
clickOn: 'up',
enable: true
},
badge: function (value) {
var badge = this.badgeElement = this.badgeElement || createBadge(value).appendTo(this.element);
if (value || value === 0) {
badge.html(value);
return this;
}
if (value === false) {
badge.empty().remove();
this.badgeElement = false;
return this;
}
return badge.html();
},
enable: function (enable) {
var element = this.element;
if (typeof enable == 'undefined') {
enable = true;
}
this.options.enable = enable;
if (enable) {
element.removeAttr(DISABLED);
} else {
element.attr(DISABLED, DISABLED);
}
element.toggleClass(DISABLEDSTATE, !enable);
},
_timeoutDeactivate: function (e) {
if (!this.deactivateTimeoutID) {
this.deactivateTimeoutID = setTimeout(highlightButton, 500, this, e, false);
}
},
_activate: function (e) {
var activeElement = document.activeElement, nodeName = activeElement ? activeElement.nodeName : '';
if (this.options.enable) {
highlightButton(this, e, true);
if (nodeName == 'INPUT' || nodeName == 'TEXTAREA') {
activeElement.blur();
}
}
},
_release: function (e) {
var that = this;
if (e.which > 1) {
return;
}
if (!that.options.enable) {
e.preventDefault();
return;
}
if (that.trigger(CLICK, {
target: $(e.target),
button: that.element
})) {
e.preventDefault();
}
},
_style: function () {
var style = this.options.style, element = this.element, styles;
if (style) {
styles = style.split(' ');
$.each(styles, function () {
element.addClass('km-' + this);
});
}
},
_wrap: function () {
var that = this, icon = that.options.icon, badge = that.options.badge, iconSpan = '
').children('span.km-text');
}
if (!image[0] && icon) {
if (!span[0]) {
iconSpan += ' km-notext';
}
that.iconElement = element.prepend($(iconSpan + '" />'));
}
if (badge || badge === 0) {
that.badgeElement = createBadge(badge).appendTo(element);
}
}
});
var BackButton = Button.extend({
options: {
name: 'BackButton',
style: 'back'
},
init: function (element, options) {
var that = this;
Button.fn.init.call(that, element, options);
if (typeof that.element.attr('href') === 'undefined') {
that.element.attr('href', '#:back');
}
}
});
var DetailButton = Button.extend({
options: {
name: 'DetailButton',
style: ''
},
init: function (element, options) {
Button.fn.init.call(this, element, options);
},
_style: function () {
var style = this.options.style + ' detail', element = this.element;
if (style) {
var styles = style.split(' ');
$.each(styles, function () {
element.addClass('km-' + this);
});
}
},
_wrap: function () {
var that = this, icon = that.options.icon, iconSpan = '
'));
}
}
});
ui.plugin(Button);
ui.plugin(BackButton);
ui.plugin(DetailButton);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.buttongroup', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'mobile.buttongroup',
name: 'ButtonGroup',
category: 'mobile',
description: 'The Kendo mobile ButtonGroup widget is a linear set of grouped buttons.',
depends: ['core']
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, ACTIVE = 'km-state-active', DISABLE = 'km-state-disabled', SELECT = 'select', SELECTOR = 'li:not(.' + ACTIVE + ')';
function createBadge(value) {
return $('
' + value + '');
}
var ButtonGroup = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
that.element.addClass('km-buttongroup').find('li').each(that._button);
that.element.on(that.options.selectOn, SELECTOR, '_select');
that._enable = true;
that.select(that.options.index);
if (!that.options.enable) {
that._enable = false;
that.wrapper.addClass(DISABLE);
}
},
events: [SELECT],
options: {
name: 'ButtonGroup',
selectOn: 'down',
index: -1,
enable: true
},
current: function () {
return this.element.find('.' + ACTIVE);
},
select: function (li) {
var that = this, index = -1;
if (li === undefined || li === -1 || !that._enable || $(li).is('.' + DISABLE)) {
return;
}
that.current().removeClass(ACTIVE);
if (typeof li === 'number') {
index = li;
li = $(that.element[0].children[li]);
} else if (li.nodeType) {
li = $(li);
index = li.index();
}
li.addClass(ACTIVE);
that.selectedIndex = index;
},
badge: function (item, value) {
var buttongroup = this.element, badge;
if (!isNaN(item)) {
item = buttongroup.children().get(item);
}
item = buttongroup.find(item);
badge = $(item.children('.km-badge')[0] || createBadge(value).appendTo(item));
if (value || value === 0) {
badge.html(value);
return this;
}
if (value === false) {
badge.empty().remove();
return this;
}
return badge.html();
},
enable: function (enable) {
var wrapper = this.wrapper;
if (typeof enable == 'undefined') {
enable = true;
}
if (enable) {
wrapper.removeClass(DISABLE);
} else {
wrapper.addClass(DISABLE);
}
this._enable = this.options.enable = enable;
},
_button: function () {
var button = $(this).addClass('km-button'), icon = kendo.attrValue(button, 'icon'), badge = kendo.attrValue(button, 'badge'), span = button.children('span'), image = button.find('img').addClass('km-image');
if (!span[0]) {
span = button.wrapInner('
').children('span');
}
span.addClass('km-text');
if (!image[0] && icon) {
button.prepend($('
'));
}
if (badge || badge === 0) {
createBadge(badge).appendTo(button);
}
},
_select: function (e) {
if (e.which > 1 || e.isDefaultPrevented() || !this._enable) {
return;
}
this.select(e.currentTarget);
this.trigger(SELECT, { index: this.selectedIndex });
}
});
ui.plugin(ButtonGroup);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.collapsible', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'mobile.collapsible',
name: 'Collapsible',
category: 'mobile',
description: 'The Kendo mobile Collapsible widget provides ability for creating collapsible blocks of content.',
depends: [
'core',
'userevents'
]
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, COLLAPSIBLE = 'km-collapsible', HEADER = 'km-collapsible-header', CONTENT = 'km-collapsible-content', INSET = 'km-collapsibleinset', HEADER_WRAPPER = '
', CONTENT_WRAPPER = '
', COLLAPSED = 'km-collapsed', EXPANDED = 'km-expanded', ANIMATED = 'km-animated', LEFT = 'left', EXAPND = 'expand', COLLAPSE = 'collapse';
var Collapsible = Widget.extend({
init: function (element, options) {
var that = this, container = $(element);
Widget.fn.init.call(that, container, options);
container.addClass(COLLAPSIBLE);
that._buildHeader();
that.content = container.children().not(that.header).wrapAll(CONTENT_WRAPPER).parent();
that._userEvents = new kendo.UserEvents(that.header, {
fastTap: true,
tap: function () {
that.toggle();
}
});
container.addClass(that.options.collapsed ? COLLAPSED : EXPANDED);
if (that.options.inset) {
container.addClass(INSET);
}
if (that.options.animation) {
that.content.addClass(ANIMATED);
that.content.height(0);
if (that.options.collapsed) {
that.content.hide();
}
} else if (that.options.collapsed) {
that.content.hide();
}
},
events: [
EXAPND,
COLLAPSE
],
options: {
name: 'Collapsible',
collapsed: true,
collapseIcon: 'arrow-n',
expandIcon: 'arrow-s',
iconPosition: LEFT,
animation: true,
inset: false
},
destroy: function () {
Widget.fn.destroy.call(this);
this._userEvents.destroy();
},
expand: function (instant) {
var icon = this.options.collapseIcon, content = this.content, ios = kendo.support.mobileOS.ios;
if (!this.trigger(EXAPND)) {
if (icon) {
this.header.find('.km-icon').removeClass().addClass('km-icon km-' + icon);
}
this.element.removeClass(COLLAPSED).addClass(EXPANDED);
if (this.options.animation && !instant) {
content.off('transitionend');
content.show();
if (ios) {
content.removeClass(ANIMATED);
}
content.height(this._getContentHeight());
if (ios) {
content.addClass(ANIMATED);
}
kendo.resize(content);
} else {
content.show();
}
}
},
collapse: function (instant) {
var icon = this.options.expandIcon, content = this.content;
if (!this.trigger(COLLAPSE)) {
if (icon) {
this.header.find('.km-icon').removeClass().addClass('km-icon km-' + icon);
}
this.element.removeClass(EXPANDED).addClass(COLLAPSED);
if (this.options.animation && !instant) {
content.one('transitionend', function () {
content.hide();
});
content.height(0);
} else {
content.hide();
}
}
},
toggle: function (instant) {
if (this.isCollapsed()) {
this.expand(instant);
} else {
this.collapse(instant);
}
},
isCollapsed: function () {
return this.element.hasClass(COLLAPSED);
},
resize: function () {
if (!this.isCollapsed() && this.options.animation) {
this.content.height(this._getContentHeight());
}
},
_buildHeader: function () {
var header = this.element.children(':header').wrapAll(HEADER_WRAPPER), iconSpan = $('
'), icon = this.options.collapsed ? this.options.expandIcon : this.options.collapseIcon, iconPosition = this.options.iconPosition;
if (icon) {
header.prepend(iconSpan);
iconSpan.addClass('km-' + icon);
}
this.header = header.parent();
this.header.addClass('km-icon-' + iconPosition);
},
_getContentHeight: function () {
var style = this.content.attr('style'), height;
this.content.css({
position: 'absolute',
visibility: 'hidden',
height: 'auto'
});
height = this.content.height();
this.content.attr('style', style ? style : '');
return height;
}
});
ui.plugin(Collapsible);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.listview', [
'kendo.data',
'kendo.userevents',
'kendo.mobile.button'
], f);
}(function () {
var __meta__ = {
id: 'mobile.listview',
name: 'ListView',
category: 'mobile',
description: 'The Kendo Mobile ListView widget is used to display flat or grouped list of items.',
depends: [
'data',
'userevents',
'mobile.button'
]
};
(function ($, undefined) {
var kendo = window.kendo, Node = window.Node, mobile = kendo.mobile, ui = mobile.ui, DataSource = kendo.data.DataSource, Widget = ui.DataBoundWidget, ITEM_SELECTOR = '.km-list > li, > li:not(.km-group-container)', HIGHLIGHT_SELECTOR = '.km-listview-link, .km-listview-label', ICON_SELECTOR = '[' + kendo.attr('icon') + ']', proxy = $.proxy, attrValue = kendo.attrValue, GROUP_CLASS = 'km-group-title', ACTIVE_CLASS = 'km-state-active', GROUP_WRAPPER = '
', GROUP_TEMPLATE = kendo.template('
#= this.headerTemplate(data) #
#= kendo.render(this.template, data.items)#
'), WRAPPER = '
', SEARCH_TEMPLATE = kendo.template('
'), NS = '.kendoMobileListView', STYLED = 'styled', DATABOUND = 'dataBound', DATABINDING = 'dataBinding', ITEM_CHANGE = 'itemChange', CLICK = 'click', CHANGE = 'change', PROGRESS = 'progress', FUNCTION = 'function', whitespaceRegExp = /^\s+$/, buttonRegExp = /button/;
function whitespace() {
return this.nodeType === Node.TEXT_NODE && this.nodeValue.match(whitespaceRegExp);
}
function addIcon(item, icon) {
if (icon && !item[0].querySelector('.km-icon')) {
item.prepend('
');
}
}
function enhanceItem(item) {
addIcon(item, attrValue(item, 'icon'));
addIcon(item, attrValue(item.children(ICON_SELECTOR), 'icon'));
}
function enhanceLinkItem(item) {
var parent = item.parent(), itemAndDetailButtons = item.add(parent.children(kendo.roleSelector('detailbutton'))), otherNodes = parent.contents().not(itemAndDetailButtons).not(whitespace);
if (otherNodes.length) {
return;
}
item.addClass('km-listview-link').attr(kendo.attr('role'), 'listview-link');
addIcon(item, attrValue(parent, 'icon'));
addIcon(item, attrValue(item, 'icon'));
}
function enhanceCheckBoxItem(label) {
if (!label[0].querySelector('input[type=checkbox],input[type=radio]')) {
return;
}
var item = label.parent();
if (item.contents().not(label).not(function () {
return this.nodeType == 3;
})[0]) {
return;
}
label.addClass('km-listview-label');
label.children('[type=checkbox],[type=radio]').addClass('km-widget km-icon km-check');
}
function putAt(element, top) {
$(element).css('transform', 'translate3d(0px, ' + top + 'px, 0px)');
}
var HeaderFixer = kendo.Class.extend({
init: function (listView) {
var scroller = listView.scroller();
if (!scroller) {
return;
}
this.options = listView.options;
this.element = listView.element;
this.scroller = listView.scroller();
this._shouldFixHeaders();
var headerFixer = this;
var cacheHeaders = function () {
headerFixer._cacheHeaders();
};
listView.bind('resize', cacheHeaders);
listView.bind(STYLED, cacheHeaders);
listView.bind(DATABOUND, cacheHeaders);
scroller.bind('scroll', function (e) {
headerFixer._fixHeader(e);
});
},
_fixHeader: function (e) {
if (!this.fixedHeaders) {
return;
}
var i = 0, scroller = this.scroller, headers = this.headers, scrollTop = e.scrollTop, headerPair, offset, header;
do {
headerPair = headers[i++];
if (!headerPair) {
header = $('
');
break;
}
offset = headerPair.offset;
header = headerPair.header;
} while (offset + 1 > scrollTop);
if (this.currentHeader != i) {
scroller.fixedContainer.html(header.clone());
this.currentHeader = i;
}
},
_shouldFixHeaders: function () {
this.fixedHeaders = this.options.type === 'group' && this.options.fixedHeaders;
},
_cacheHeaders: function () {
this._shouldFixHeaders();
if (!this.fixedHeaders) {
return;
}
var headers = [], offset = this.scroller.scrollTop;
this.element.find('.' + GROUP_CLASS).each(function (_, header) {
header = $(header);
headers.unshift({
offset: header.position().top + offset,
header: header
});
});
this.headers = headers;
this._fixHeader({ scrollTop: offset });
}
});
var DEFAULT_PULL_PARAMETERS = function () {
return { page: 1 };
};
var RefreshHandler = kendo.Class.extend({
init: function (listView) {
var handler = this, options = listView.options, scroller = listView.scroller(), pullParameters = options.pullParameters || DEFAULT_PULL_PARAMETERS;
this.listView = listView;
this.scroller = scroller;
listView.bind('_dataSource', function (e) {
handler.setDataSource(e.dataSource);
});
scroller.setOptions({
pullToRefresh: true,
pull: function () {
if (!handler._pulled) {
handler._pulled = true;
handler.dataSource.read(pullParameters.call(listView, handler._first));
}
},
messages: {
pullTemplate: options.messages.pullTemplate,
releaseTemplate: options.messages.releaseTemplate,
refreshTemplate: options.messages.refreshTemplate
}
});
},
setDataSource: function (dataSource) {
var handler = this;
this._first = dataSource.view()[0];
this.dataSource = dataSource;
dataSource.bind('change', function () {
handler._change();
});
dataSource.bind('error', function () {
handler._change();
});
},
_change: function () {
var scroller = this.scroller, dataSource = this.dataSource;
if (this._pulled) {
scroller.pullHandled();
}
if (this._pulled || !this._first) {
var view = dataSource.view();
if (view[0]) {
this._first = view[0];
}
}
this._pulled = false;
}
});
var VirtualList = kendo.Observable.extend({
init: function (options) {
var list = this;
kendo.Observable.fn.init.call(list);
list.buffer = options.buffer;
list.height = options.height;
list.item = options.item;
list.items = [];
list.footer = options.footer;
list.buffer.bind('reset', function () {
list.refresh();
});
},
refresh: function () {
var buffer = this.buffer, items = this.items, endReached = false;
while (items.length) {
items.pop().destroy();
}
this.offset = buffer.offset;
var itemConstructor = this.item, prevItem, item;
for (var idx = 0; idx < buffer.viewSize; idx++) {
if (idx === buffer.total()) {
endReached = true;
break;
}
item = itemConstructor(this.content(this.offset + items.length));
item.below(prevItem);
prevItem = item;
items.push(item);
}
this.itemCount = items.length;
this.trigger('reset');
this._resize();
if (endReached) {
this.trigger('endReached');
}
},
totalHeight: function () {
if (!this.items[0]) {
return 0;
}
var list = this, items = list.items, top = items[0].top, bottom = items[items.length - 1].bottom, averageItemHeight = (bottom - top) / list.itemCount, remainingItemsCount = list.buffer.length - list.offset - list.itemCount;
return (this.footer ? this.footer.height : 0) + bottom + remainingItemsCount * averageItemHeight;
},
batchUpdate: function (top) {
var height = this.height(), items = this.items, item, initialOffset = this.offset;
if (!items[0]) {
return;
}
if (this.lastDirection) {
while (items[items.length - 1].bottom > top + height * 2) {
if (this.offset === 0) {
break;
}
this.offset--;
item = items.pop();
item.update(this.content(this.offset));
item.above(items[0]);
items.unshift(item);
}
} else {
while (items[0].top < top - height) {
var nextIndex = this.offset + this.itemCount;
if (nextIndex === this.buffer.total()) {
this.trigger('endReached');
break;
}
if (nextIndex === this.buffer.length) {
break;
}
item = items.shift();
item.update(this.content(this.offset + this.itemCount));
item.below(items[items.length - 1]);
items.push(item);
this.offset++;
}
}
if (initialOffset !== this.offset) {
this._resize();
}
},
update: function (top) {
var list = this, items = this.items, item, firstItem, lastItem, height = this.height(), itemCount = this.itemCount, padding = height / 2, up = (this.lastTop || 0) > top, topBorder = top - padding, bottomBorder = top + height + padding;
if (!items[0]) {
return;
}
this.lastTop = top;
this.lastDirection = up;
if (up) {
if (items[0].top > topBorder && items[items.length - 1].bottom > bottomBorder + padding && this.offset > 0) {
this.offset--;
item = items.pop();
firstItem = items[0];
item.update(this.content(this.offset));
items.unshift(item);
item.above(firstItem);
list._resize();
}
} else {
if (items[items.length - 1].bottom < bottomBorder && items[0].top < topBorder - padding) {
var nextIndex = this.offset + itemCount;
if (nextIndex === this.buffer.total()) {
this.trigger('endReached');
} else if (nextIndex !== this.buffer.length) {
item = items.shift();
lastItem = items[items.length - 1];
items.push(item);
item.update(this.content(this.offset + this.itemCount));
list.offset++;
item.below(lastItem);
list._resize();
}
}
}
},
content: function (index) {
return this.buffer.at(index);
},
destroy: function () {
this.unbind();
},
_resize: function () {
var items = this.items, top = 0, bottom = 0, firstItem = items[0], lastItem = items[items.length - 1];
if (firstItem) {
top = firstItem.top;
bottom = lastItem.bottom;
}
this.trigger('resize', {
top: top,
bottom: bottom
});
if (this.footer) {
this.footer.below(lastItem);
}
}
});
kendo.mobile.ui.VirtualList = VirtualList;
var VirtualListViewItem = kendo.Class.extend({
init: function (listView, dataItem) {
var element = listView.append([dataItem], true)[0], height = element.offsetHeight;
$.extend(this, {
top: 0,
element: element,
listView: listView,
height: height,
bottom: height
});
},
update: function (dataItem) {
this.element = this.listView.setDataItem(this.element, dataItem);
},
above: function (item) {
if (item) {
this.height = this.element.offsetHeight;
this.top = item.top - this.height;
this.bottom = item.top;
putAt(this.element, this.top);
}
},
below: function (item) {
if (item) {
this.height = this.element.offsetHeight;
this.top = item.bottom;
this.bottom = this.top + this.height;
putAt(this.element, this.top);
}
},
destroy: function () {
kendo.destroy(this.element);
$(this.element).remove();
}
});
var LOAD_ICON = '
';
var VirtualListViewLoadingIndicator = kendo.Class.extend({
init: function (listView) {
this.element = $('
').appendTo(listView.element);
this._loadIcon = $(LOAD_ICON).appendTo(this.element);
},
enable: function () {
this.element.show();
this.height = this.element.outerHeight(true);
},
disable: function () {
this.element.hide();
this.height = 0;
},
below: function (item) {
if (item) {
this.top = item.bottom;
this.bottom = this.height + this.top;
putAt(this.element, this.top);
}
}
});
var VirtualListViewPressToLoadMore = VirtualListViewLoadingIndicator.extend({
init: function (listView, buffer) {
this._loadIcon = $(LOAD_ICON).hide();
this._loadButton = $('
' + listView.options.messages.loadMoreText + '').hide();
this.element = $('
').append(this._loadIcon).append(this._loadButton).appendTo(listView.element);
var loadMore = this;
this._loadButton.kendoMobileButton().data('kendoMobileButton').bind('click', function () {
loadMore._hideShowButton();
buffer.next();
});
buffer.bind('resize', function () {
loadMore._showLoadButton();
});
this.height = this.element.outerHeight(true);
this.disable();
},
_hideShowButton: function () {
this._loadButton.hide();
this.element.addClass('km-scroller-refresh');
this._loadIcon.css('display', 'block');
},
_showLoadButton: function () {
this._loadButton.show();
this.element.removeClass('km-scroller-refresh');
this._loadIcon.hide();
}
});
var VirtualListViewItemBinder = kendo.Class.extend({
init: function (listView) {
var binder = this;
this.chromeHeight = listView.wrapper.children().not(listView.element).outerHeight() || 0;
this.listView = listView;
this.scroller = listView.scroller();
this.options = listView.options;
listView.bind('_dataSource', function (e) {
binder.setDataSource(e.dataSource, e.empty);
});
listView.bind('resize', function () {
if (!binder.list.items.length) {
return;
}
binder.scroller.reset();
binder.buffer.range(0);
binder.list.refresh();
});
this.scroller.makeVirtual();
this.scroller.bind('scroll', function (e) {
binder.list.update(e.scrollTop);
});
this.scroller.bind('scrollEnd', function (e) {
binder.list.batchUpdate(e.scrollTop);
});
},
destroy: function () {
this.list.unbind();
this.buffer.unbind();
},
setDataSource: function (dataSource, empty) {
var binder = this, options = this.options, listView = this.listView, scroller = listView.scroller(), pressToLoadMore = options.loadMore, pageSize, buffer, footer;
this.dataSource = dataSource;
pageSize = dataSource.pageSize() || options.virtualViewSize;
if (!pageSize && !empty) {
throw new Error('the DataSource does not have page size configured. Page Size setting is mandatory for the mobile listview virtual scrolling to work as expected.');
}
if (this.buffer) {
this.buffer.destroy();
}
buffer = new kendo.data.Buffer(dataSource, Math.floor(pageSize / 2), pressToLoadMore);
if (pressToLoadMore) {
footer = new VirtualListViewPressToLoadMore(listView, buffer);
} else {
footer = new VirtualListViewLoadingIndicator(listView);
}
if (this.list) {
this.list.destroy();
}
var list = new VirtualList({
buffer: buffer,
footer: footer,
item: function (dataItem) {
return new VirtualListViewItem(listView, dataItem);
},
height: function () {
return scroller.height();
}
});
list.bind('resize', function () {
binder.updateScrollerSize();
listView.updateSize();
});
list.bind('reset', function () {
binder.footer.enable();
});
list.bind('endReached', function () {
footer.disable();
binder.updateScrollerSize();
});
buffer.bind('expand', function () {
list.lastDirection = false;
list.batchUpdate(scroller.scrollTop);
});
$.extend(this, {
buffer: buffer,
scroller: scroller,
list: list,
footer: footer
});
},
updateScrollerSize: function () {
this.scroller.virtualSize(0, this.list.totalHeight() + this.chromeHeight);
},
refresh: function () {
this.list.refresh();
},
reset: function () {
this.buffer.range(0);
this.list.refresh();
}
});
var ListViewItemBinder = kendo.Class.extend({
init: function (listView) {
var binder = this;
this.listView = listView;
this.options = listView.options;
var itemBinder = this;
this._refreshHandler = function (e) {
itemBinder.refresh(e);
};
this._progressHandler = function () {
listView.showLoading();
};
listView.bind('_dataSource', function (e) {
binder.setDataSource(e.dataSource);
});
},
destroy: function () {
this._unbindDataSource();
},
reset: function () {
},
refresh: function (e) {
var action = e && e.action, dataItems = e && e.items, listView = this.listView, dataSource = this.dataSource, prependOnRefresh = this.options.appendOnRefresh, view = dataSource.view(), groups = dataSource.group(), groupedMode = groups && groups[0], item;
if (action === 'itemchange') {
if (!listView._hasBindingTarget()) {
item = listView.findByDataItem(dataItems)[0];
if (item) {
listView.setDataItem(item, dataItems[0]);
}
}
return;
}
var removedItems, addedItems, addedDataItems;
var adding = action === 'add' && !groupedMode || prependOnRefresh && !listView._filter;
var removing = action === 'remove' && !groupedMode;
if (adding) {
removedItems = [];
} else if (removing) {
removedItems = listView.findByDataItem(dataItems);
}
if (listView.trigger(DATABINDING, {
action: action || 'rebind',
items: dataItems,
removedItems: removedItems,
index: e && e.index
})) {
if (this._shouldShowLoading()) {
listView.hideLoading();
}
return;
}
if (action === 'add' && !groupedMode) {
var index = view.indexOf(dataItems[0]);
if (index > -1) {
addedItems = listView.insertAt(dataItems, index);
addedDataItems = dataItems;
}
} else if (action === 'remove' && !groupedMode) {
addedItems = [];
listView.remove(dataItems);
} else if (groupedMode) {
listView.replaceGrouped(view);
} else if (prependOnRefresh && !listView._filter) {
addedItems = listView.prepend(view);
addedDataItems = view;
} else {
listView.replace(view);
}
if (this._shouldShowLoading()) {
listView.hideLoading();
}
listView.trigger(DATABOUND, {
ns: ui,
addedItems: addedItems,
addedDataItems: addedDataItems
});
},
setDataSource: function (dataSource) {
if (this.dataSource) {
this._unbindDataSource();
}
this.dataSource = dataSource;
dataSource.bind(CHANGE, this._refreshHandler);
if (this._shouldShowLoading()) {
this.dataSource.bind(PROGRESS, this._progressHandler);
}
},
_unbindDataSource: function () {
this.dataSource.unbind(CHANGE, this._refreshHandler).unbind(PROGRESS, this._progressHandler);
},
_shouldShowLoading: function () {
var options = this.options;
return !options.pullToRefresh && !options.loadMore && !options.endlessScroll;
}
});
var ListViewFilter = kendo.Class.extend({
init: function (listView) {
var filter = this, filterable = listView.options.filterable, events = 'change paste', that = this;
this.listView = listView;
this.options = filterable;
listView.element.before(SEARCH_TEMPLATE({ placeholder: filterable.placeholder || 'Search...' }));
if (filterable.autoFilter !== false) {
events += ' keyup';
}
this.element = listView.wrapper.find('.km-search-form');
this.searchInput = listView.wrapper.find('input[type=search]').closest('form').on('submit' + NS, function (e) {
e.preventDefault();
}).end().on('focus' + NS, function () {
filter._oldFilter = filter.searchInput.val();
}).on(events.split(' ').join(NS + ' ') + NS, proxy(this._filterChange, this));
this.clearButton = listView.wrapper.find('.km-filter-reset').on(CLICK, proxy(this, '_clearFilter')).hide();
this._dataSourceChange = $.proxy(this._refreshInput, this);
listView.bind('_dataSource', function (e) {
e.dataSource.bind('change', that._dataSourceChange);
});
},
_refreshInput: function () {
var appliedFilters = this.listView.dataSource.filter();
var searchInput = this.listView._filter.searchInput;
if (!appliedFilters || appliedFilters.filters[0].field !== this.listView.options.filterable.field) {
searchInput.val('');
} else {
searchInput.val(appliedFilters.filters[0].value);
}
},
_search: function (expr) {
this._filter = true;
this.clearButton[expr ? 'show' : 'hide']();
this.listView.dataSource.filter(expr);
},
_filterChange: function (e) {
var filter = this;
if (e.type == 'paste' && this.options.autoFilter !== false) {
setTimeout(function () {
filter._applyFilter();
}, 1);
} else {
this._applyFilter();
}
},
_applyFilter: function () {
var options = this.options, value = this.searchInput.val(), expr = value.length ? {
field: options.field,
operator: options.operator || 'startswith',
ignoreCase: options.ignoreCase,
value: value
} : null;
if (value === this._oldFilter) {
return;
}
this._oldFilter = value;
this._search(expr);
},
_clearFilter: function (e) {
this.searchInput.val('');
this._search(null);
e.preventDefault();
}
});
var ListView = Widget.extend({
init: function (element, options) {
var listView = this;
Widget.fn.init.call(this, element, options);
element = this.element;
options = this.options;
if (options.scrollTreshold) {
options.scrollThreshold = options.scrollTreshold;
}
element.on('down', HIGHLIGHT_SELECTOR, '_highlight').on('move up cancel', HIGHLIGHT_SELECTOR, '_dim');
this._userEvents = new kendo.UserEvents(element, {
fastTap: true,
filter: ITEM_SELECTOR,
allowSelection: true,
tap: function (e) {
listView._click(e);
}
});
element.css('-ms-touch-action', 'auto');
element.wrap(WRAPPER);
this.wrapper = this.element.parent();
this._headerFixer = new HeaderFixer(this);
this._itemsCache = {};
this._templates();
this.virtual = options.endlessScroll || options.loadMore;
this._style();
if (this.options.$angular && (this.virtual || this.options.pullToRefresh)) {
setTimeout($.proxy(this, '_start'));
} else {
this._start();
}
},
_start: function () {
var options = this.options;
if (this.options.filterable) {
this._filter = new ListViewFilter(this);
}
if (this.virtual) {
this._itemBinder = new VirtualListViewItemBinder(this);
} else {
this._itemBinder = new ListViewItemBinder(this);
}
if (this.options.pullToRefresh) {
this._pullToRefreshHandler = new RefreshHandler(this);
}
this.setDataSource(options.dataSource);
this._enhanceItems(this.items());
kendo.notify(this, ui);
},
events: [
CLICK,
DATABINDING,
DATABOUND,
ITEM_CHANGE
],
options: {
name: 'ListView',
style: '',
type: 'flat',
autoBind: true,
fixedHeaders: false,
template: '#:data#',
headerTemplate: '
#:value#',
appendOnRefresh: false,
loadMore: false,
endlessScroll: false,
scrollThreshold: 30,
pullToRefresh: false,
messages: {
loadMoreText: 'Press to load more',
pullTemplate: 'Pull to refresh',
releaseTemplate: 'Release to refresh',
refreshTemplate: 'Refreshing'
},
pullOffset: 140,
filterable: false,
virtualViewSize: null
},
refresh: function () {
this._itemBinder.refresh();
},
reset: function () {
this._itemBinder.reset();
},
setDataSource: function (dataSource) {
var emptyDataSource = !dataSource;
this.dataSource = DataSource.create(dataSource);
this.trigger('_dataSource', {
dataSource: this.dataSource,
empty: emptyDataSource
});
if (this.options.autoBind && !emptyDataSource) {
this.items().remove();
this.dataSource.fetch();
}
},
destroy: function () {
Widget.fn.destroy.call(this);
kendo.destroy(this.element);
this._userEvents.destroy();
if (this._itemBinder) {
this._itemBinder.destroy();
}
this.element.unwrap();
delete this.element;
delete this.wrapper;
delete this._userEvents;
},
items: function () {
if (this.options.type === 'group') {
return this.element.find('.km-list').children();
} else {
return this.element.children().not('.km-load-more');
}
},
scroller: function () {
if (!this._scrollerInstance) {
this._scrollerInstance = this.element.closest('.km-scroll-wrapper').data('kendoMobileScroller');
}
return this._scrollerInstance;
},
showLoading: function () {
var view = this.view();
if (view && view.loader) {
view.loader.show();
}
},
hideLoading: function () {
var view = this.view();
if (view && view.loader) {
view.loader.hide();
}
},
insertAt: function (dataItems, index, triggerChange) {
var listView = this;
return listView._renderItems(dataItems, function (items) {
if (index === 0) {
listView.element.prepend(items);
} else if (index === -1) {
listView.element.append(items);
} else {
listView.items().eq(index - 1).after(items);
}
if (triggerChange) {
for (var i = 0; i < items.length; i++) {
listView.trigger(ITEM_CHANGE, {
item: items.eq(i),
data: dataItems[i],
ns: ui
});
}
}
});
},
append: function (dataItems, triggerChange) {
return this.insertAt(dataItems, -1, triggerChange);
},
prepend: function (dataItems, triggerChange) {
return this.insertAt(dataItems, 0, triggerChange);
},
replace: function (dataItems) {
this.options.type = 'flat';
this._angularItems('cleanup');
this.element.empty();
this._userEvents.cancel();
this._style();
return this.insertAt(dataItems, 0);
},
replaceGrouped: function (groups) {
this.options.type = 'group';
this._angularItems('cleanup');
this.element.empty();
var items = $(kendo.render(this.groupTemplate, groups));
this._enhanceItems(items.children('ul').children('li'));
this.element.append(items);
mobile.init(items);
this._style();
this._angularItems('compile');
},
remove: function (dataItems) {
var items = this.findByDataItem(dataItems);
this.angular('cleanup', function () {
return { elements: items };
});
kendo.destroy(items);
items.remove();
},
findByDataItem: function (dataItems) {
var selectors = [];
for (var idx = 0, length = dataItems.length; idx < length; idx++) {
selectors[idx] = '[data-' + kendo.ns + 'uid=' + dataItems[idx].uid + ']';
}
return this.element.find(selectors.join(','));
},
setDataItem: function (item, dataItem) {
var listView = this, replaceItem = function (items) {
var newItem = $(items[0]);
kendo.destroy(item);
listView.angular('cleanup', function () {
return { elements: [$(item)] };
});
$(item).replaceWith(newItem);
listView.trigger(ITEM_CHANGE, {
item: newItem,
data: dataItem,
ns: ui
});
};
return this._renderItems([dataItem], replaceItem)[0];
},
updateSize: function () {
this._size = this.getSize();
},
_renderItems: function (dataItems, callback) {
var items = $(kendo.render(this.template, dataItems));
callback(items);
this.angular('compile', function () {
return {
elements: items,
data: dataItems.map(function (data) {
return { dataItem: data };
})
};
});
mobile.init(items);
this._enhanceItems(items);
return items;
},
_dim: function (e) {
this._toggle(e, false);
},
_highlight: function (e) {
this._toggle(e, true);
},
_toggle: function (e, highlight) {
if (e.which > 1) {
return;
}
var clicked = $(e.currentTarget), item = clicked.parent(), role = attrValue(clicked, 'role') || '', plainItem = !role.match(buttonRegExp), prevented = e.isDefaultPrevented();
if (plainItem) {
item.toggleClass(ACTIVE_CLASS, highlight && !prevented);
}
},
_templates: function () {
var template = this.options.template, headerTemplate = this.options.headerTemplate, dataIDAttribute = ' data-uid="#=arguments[0].uid || ""#"', templateProxy = {}, groupTemplateProxy = {};
if (typeof template === FUNCTION) {
templateProxy.template = template;
template = '#=this.template(data)#';
}
this.template = proxy(kendo.template('
' + template + ''), templateProxy);
groupTemplateProxy.template = this.template;
if (typeof headerTemplate === FUNCTION) {
groupTemplateProxy._headerTemplate = headerTemplate;
headerTemplate = '#=this._headerTemplate(data)#';
}
groupTemplateProxy.headerTemplate = kendo.template(headerTemplate);
this.groupTemplate = proxy(GROUP_TEMPLATE, groupTemplateProxy);
},
_click: function (e) {
if (e.event.which > 1 || e.event.isDefaultPrevented()) {
return;
}
var dataItem, item = e.target, target = $(e.event.target), buttonElement = target.closest(kendo.roleSelector('button', 'detailbutton', 'backbutton')), button = kendo.widgetInstance(buttonElement, ui), id = item.attr(kendo.attr('uid'));
if (id) {
dataItem = this.dataSource.getByUid(id);
}
if (this.trigger(CLICK, {
target: target,
item: item,
dataItem: dataItem,
button: button
})) {
e.preventDefault();
}
},
_styleGroups: function () {
var rootItems = this.element.children();
rootItems.children('ul').addClass('km-list');
rootItems.each(function () {
var li = $(this), groupHeader = li.contents().first();
li.addClass('km-group-container');
if (!groupHeader.is('ul') && !groupHeader.is('div.' + GROUP_CLASS)) {
groupHeader.wrap(GROUP_WRAPPER);
}
});
},
_style: function () {
var options = this.options, grouped = options.type === 'group', element = this.element, inset = options.style === 'inset';
element.addClass('km-listview').toggleClass('km-list', !grouped).toggleClass('km-virtual-list', this.virtual).toggleClass('km-listinset', !grouped && inset).toggleClass('km-listgroup', grouped && !inset).toggleClass('km-listgroupinset', grouped && inset);
if (!element.parents('.km-listview')[0]) {
element.closest('.km-content').toggleClass('km-insetcontent', inset);
}
if (grouped) {
this._styleGroups();
}
this.trigger(STYLED);
},
_enhanceItems: function (items) {
items.each(function () {
var item = $(this), child, enhanced = false;
item.children().each(function () {
child = $(this);
if (child.is('a')) {
enhanceLinkItem(child);
enhanced = true;
} else if (child.is('label')) {
enhanceCheckBoxItem(child);
enhanced = true;
}
});
if (!enhanced) {
enhanceItem(item);
}
});
}
});
ui.plugin(ListView);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.navbar', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'mobile.navbar',
name: 'NavBar',
category: 'mobile',
description: 'The Kendo mobile NavBar widget is used inside a mobile View or Layout Header element to display an application navigation bar.',
depends: ['core']
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, Widget = ui.Widget;
function createContainer(align, element) {
var items = element.find('[' + kendo.attr('align') + '=' + align + ']');
if (items[0]) {
return $('
').append(items).prependTo(element);
}
}
function toggleTitle(centerElement) {
var siblings = centerElement.siblings(), noTitle = !!centerElement.children('ul')[0], showTitle = !!siblings[0] && $.trim(centerElement.text()) === '', android = !!(kendo.mobile.application && kendo.mobile.application.element.is('.km-android'));
centerElement.prevAll().toggleClass('km-absolute', noTitle);
centerElement.toggleClass('km-show-title', showTitle);
centerElement.toggleClass('km-fill-title', showTitle && !$.trim(centerElement.html()));
centerElement.toggleClass('km-no-title', noTitle);
centerElement.toggleClass('km-hide-title', android && !siblings.children().is(':visible'));
}
var NavBar = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
element = that.element;
that.container().bind('show', $.proxy(this, 'refresh'));
element.addClass('km-navbar').wrapInner($('
'));
that.leftElement = createContainer('left', element);
that.rightElement = createContainer('right', element);
that.centerElement = element.find('.km-view-title');
},
options: { name: 'NavBar' },
title: function (value) {
this.element.find(kendo.roleSelector('view-title')).text(value);
toggleTitle(this.centerElement);
},
refresh: function (e) {
var view = e.view;
this.title(view.options.title);
},
destroy: function () {
Widget.fn.destroy.call(this);
kendo.destroy(this.element);
}
});
ui.plugin(NavBar);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.scrollview', [
'kendo.fx',
'kendo.data',
'kendo.draganddrop'
], f);
}(function () {
var __meta__ = {
id: 'mobile.scrollview',
name: 'ScrollView',
category: 'mobile',
description: 'The Kendo Mobile ScrollView widget is used to scroll content wider than the device screen.',
depends: [
'fx',
'data',
'draganddrop'
]
};
(function ($, undefined) {
var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, proxy = $.proxy, Transition = kendo.effects.Transition, Pane = kendo.ui.Pane, PaneDimensions = kendo.ui.PaneDimensions, Widget = ui.DataBoundWidget, DataSource = kendo.data.DataSource, Buffer = kendo.data.Buffer, BatchBuffer = kendo.data.BatchBuffer, math = Math, abs = math.abs, ceil = math.ceil, round = math.round, max = math.max, min = math.min, floor = math.floor, CHANGE = 'change', CHANGING = 'changing', REFRESH = 'refresh', CURRENT_PAGE_CLASS = 'km-current-page', VIRTUAL_PAGE_CLASS = 'km-virtual-page', FUNCTION = 'function', ITEM_CHANGE = 'itemChange', CLEANUP = 'cleanup', VIRTUAL_PAGE_COUNT = 3, LEFT_PAGE = -1, CETER_PAGE = 0, RIGHT_PAGE = 1, LEFT_SWIPE = -1, NUDGE = 0, RIGHT_SWIPE = 1;
var Pager = kendo.Class.extend({
init: function (scrollView) {
var that = this, element = $('
');
scrollView.element.append(element);
this._changeProxy = proxy(that, '_change');
this._refreshProxy = proxy(that, '_refresh');
scrollView.bind(CHANGE, this._changeProxy);
scrollView.bind(REFRESH, this._refreshProxy);
$.extend(that, {
element: element,
scrollView: scrollView
});
},
items: function () {
return this.element.children();
},
_refresh: function (e) {
var pageHTML = '';
for (var idx = 0; idx < e.pageCount; idx++) {
pageHTML += '';
}
this.element.html(pageHTML);
this.items().eq(e.page).addClass(CURRENT_PAGE_CLASS);
},
_change: function (e) {
this.items().removeClass(CURRENT_PAGE_CLASS).eq(e.page).addClass(CURRENT_PAGE_CLASS);
},
destroy: function () {
this.scrollView.unbind(CHANGE, this._changeProxy);
this.scrollView.unbind(REFRESH, this._refreshProxy);
this.element.remove();
}
});
kendo.mobile.ui.ScrollViewPager = Pager;
var TRANSITION_END = 'transitionEnd', DRAG_START = 'dragStart', DRAG_END = 'dragEnd';
var ElasticPane = kendo.Observable.extend({
init: function (element, options) {
var that = this;
kendo.Observable.fn.init.call(this);
this.element = element;
this.container = element.parent();
var movable, transition, userEvents, dimensions, dimension, pane;
movable = new kendo.ui.Movable(that.element);
transition = new Transition({
axis: 'x',
movable: movable,
onEnd: function () {
that.trigger(TRANSITION_END);
}
});
userEvents = new kendo.UserEvents(element, {
fastTap: true,
start: function (e) {
if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
userEvents.capture();
} else {
userEvents.cancel();
}
that.trigger(DRAG_START, e);
transition.cancel();
},
allowSelection: true,
end: function (e) {
that.trigger(DRAG_END, e);
}
});
dimensions = new PaneDimensions({
element: that.element,
container: that.container
});
dimension = dimensions.x;
dimension.bind(CHANGE, function () {
that.trigger(CHANGE);
});
pane = new Pane({
dimensions: dimensions,
userEvents: userEvents,
movable: movable,
elastic: true
});
$.extend(that, {
duration: options && options.duration || 1,
movable: movable,
transition: transition,
userEvents: userEvents,
dimensions: dimensions,
dimension: dimension,
pane: pane
});
this.bind([
TRANSITION_END,
DRAG_START,
DRAG_END,
CHANGE
], options);
},
size: function () {
return {
width: this.dimensions.x.getSize(),
height: this.dimensions.y.getSize()
};
},
total: function () {
return this.dimension.getTotal();
},
offset: function () {
return -this.movable.x;
},
updateDimension: function () {
this.dimension.update(true);
},
refresh: function () {
this.dimensions.refresh();
},
moveTo: function (offset) {
this.movable.moveAxis('x', -offset);
},
transitionTo: function (offset, ease, instant) {
if (instant) {
this.moveTo(-offset);
} else {
this.transition.moveTo({
location: offset,
duration: this.duration,
ease: ease
});
}
}
});
kendo.mobile.ui.ScrollViewElasticPane = ElasticPane;
var ScrollViewContent = kendo.Observable.extend({
init: function (element, pane, options) {
var that = this;
kendo.Observable.fn.init.call(this);
that.element = element;
that.pane = pane;
that._getPages();
this.page = 0;
this.pageSize = options.pageSize || 1;
this.contentHeight = options.contentHeight;
this.enablePager = options.enablePager;
this.pagerOverlay = options.pagerOverlay;
},
scrollTo: function (page, instant) {
this.page = page;
this.pane.transitionTo(-page * this.pane.size().width, Transition.easeOutExpo, instant);
},
paneMoved: function (swipeType, bounce, callback, instant) {
var that = this, pane = that.pane, width = pane.size().width * that.pageSize, approx = round, ease = bounce ? Transition.easeOutBack : Transition.easeOutExpo, snap, nextPage;
if (swipeType === LEFT_SWIPE) {
approx = ceil;
} else if (swipeType === RIGHT_SWIPE) {
approx = floor;
}
nextPage = approx(pane.offset() / width);
snap = max(that.minSnap, min(-nextPage * width, that.maxSnap));
if (nextPage != that.page) {
if (callback && callback({
currentPage: that.page,
nextPage: nextPage
})) {
snap = -that.page * pane.size().width;
}
}
pane.transitionTo(snap, ease, instant);
},
updatePage: function () {
var pane = this.pane, page = round(pane.offset() / pane.size().width);
if (page != this.page) {
this.page = page;
return true;
}
return false;
},
forcePageUpdate: function () {
return this.updatePage();
},
resizeTo: function (size) {
var pane = this.pane, width = size.width;
this.pageElements.width(width);
if (this.contentHeight === '100%') {
var containerHeight = this.element.parent().height();
if (this.enablePager === true) {
var pager = this.element.parent().find('ol.km-pages');
if (!this.pagerOverlay && pager.length) {
containerHeight -= pager.outerHeight(true);
}
}
this.element.css('height', containerHeight);
this.pageElements.css('height', containerHeight);
}
pane.updateDimension();
if (!this._paged) {
this.page = floor(pane.offset() / width);
}
this.scrollTo(this.page, true);
this.pageCount = ceil(pane.total() / width);
this.minSnap = -(this.pageCount - 1) * width;
this.maxSnap = 0;
},
_getPages: function () {
this.pageElements = this.element.find(kendo.roleSelector('page'));
this._paged = this.pageElements.length > 0;
}
});
kendo.mobile.ui.ScrollViewContent = ScrollViewContent;
var VirtualScrollViewContent = kendo.Observable.extend({
init: function (element, pane, options) {
var that = this;
kendo.Observable.fn.init.call(this);
that.element = element;
that.pane = pane;
that.options = options;
that._templates();
that.page = options.page || 0;
that.pages = [];
that._initPages();
that.resizeTo(that.pane.size());
that.pane.dimension.forceEnabled();
},
setDataSource: function (dataSource) {
this.dataSource = DataSource.create(dataSource);
this._buffer();
this._pendingPageRefresh = false;
this._pendingWidgetRefresh = false;
},
_viewShow: function () {
var that = this;
if (that._pendingWidgetRefresh) {
setTimeout(function () {
that._resetPages();
}, 0);
that._pendingWidgetRefresh = false;
}
},
_buffer: function () {
var itemsPerPage = this.options.itemsPerPage;
if (this.buffer) {
this.buffer.destroy();
}
if (itemsPerPage > 1) {
this.buffer = new BatchBuffer(this.dataSource, itemsPerPage);
} else {
this.buffer = new Buffer(this.dataSource, itemsPerPage * 3);
}
this._resizeProxy = proxy(this, '_onResize');
this._resetProxy = proxy(this, '_onReset');
this._endReachedProxy = proxy(this, '_onEndReached');
this.buffer.bind({
'resize': this._resizeProxy,
'reset': this._resetProxy,
'endreached': this._endReachedProxy
});
},
_templates: function () {
var template = this.options.template, emptyTemplate = this.options.emptyTemplate, templateProxy = {}, emptyTemplateProxy = {};
if (typeof template === FUNCTION) {
templateProxy.template = template;
template = '#=this.template(data)#';
}
this.template = proxy(kendo.template(template), templateProxy);
if (typeof emptyTemplate === FUNCTION) {
emptyTemplateProxy.emptyTemplate = emptyTemplate;
emptyTemplate = '#=this.emptyTemplate(data)#';
}
this.emptyTemplate = proxy(kendo.template(emptyTemplate), emptyTemplateProxy);
},
_initPages: function () {
var pages = this.pages, element = this.element, page;
for (var i = 0; i < VIRTUAL_PAGE_COUNT; i++) {
page = new Page(element);
pages.push(page);
}
this.pane.updateDimension();
},
resizeTo: function (size) {
var pages = this.pages, pane = this.pane;
for (var i = 0; i < pages.length; i++) {
pages[i].setWidth(size.width);
}
if (this.options.contentHeight === 'auto') {
this.element.css('height', this.pages[1].element.height());
} else if (this.options.contentHeight === '100%') {
var containerHeight = this.element.parent().height();
if (this.options.enablePager === true) {
var pager = this.element.parent().find('ol.km-pages');
if (!this.options.pagerOverlay && pager.length) {
containerHeight -= pager.outerHeight(true);
}
}
this.element.css('height', containerHeight);
pages[0].element.css('height', containerHeight);
pages[1].element.css('height', containerHeight);
pages[2].element.css('height', containerHeight);
}
pane.updateDimension();
this._repositionPages();
this.width = size.width;
},
scrollTo: function (page) {
var buffer = this.buffer, dataItem;
buffer.syncDataSource();
dataItem = buffer.at(page);
if (!dataItem) {
return;
}
this._updatePagesContent(page);
this.page = page;
},
paneMoved: function (swipeType, bounce, callback, instant) {
var that = this, pane = that.pane, width = pane.size().width, offset = pane.offset(), thresholdPassed = Math.abs(offset) >= width / 3, ease = bounce ? kendo.effects.Transition.easeOutBack : kendo.effects.Transition.easeOutExpo, isEndReached = that.page + 2 > that.buffer.total(), nextPage, delta = 0;
if (swipeType === RIGHT_SWIPE) {
if (that.page !== 0) {
delta = -1;
}
} else if (swipeType === LEFT_SWIPE && !isEndReached) {
delta = 1;
} else if (offset > 0 && (thresholdPassed && !isEndReached)) {
delta = 1;
} else if (offset < 0 && thresholdPassed) {
if (that.page !== 0) {
delta = -1;
}
}
nextPage = that.page;
if (delta) {
nextPage = delta > 0 ? nextPage + 1 : nextPage - 1;
}
if (callback && callback({
currentPage: that.page,
nextPage: nextPage
})) {
delta = 0;
}
if (delta === 0) {
that._cancelMove(ease, instant);
} else if (delta === -1) {
that._moveBackward(instant);
} else if (delta === 1) {
that._moveForward(instant);
}
},
updatePage: function () {
var pages = this.pages;
if (this.pane.offset() === 0) {
return false;
}
if (this.pane.offset() > 0) {
pages.push(this.pages.shift());
this.page++;
this.setPageContent(pages[2], this.page + 1);
} else {
pages.unshift(this.pages.pop());
this.page--;
this.setPageContent(pages[0], this.page - 1);
}
this._repositionPages();
this._resetMovable();
return true;
},
forcePageUpdate: function () {
var offset = this.pane.offset(), threshold = this.pane.size().width * 3 / 4;
if (abs(offset) > threshold) {
return this.updatePage();
}
return false;
},
_resetMovable: function () {
this.pane.moveTo(0);
},
_moveForward: function (instant) {
this.pane.transitionTo(-this.width, kendo.effects.Transition.easeOutExpo, instant);
},
_moveBackward: function (instant) {
this.pane.transitionTo(this.width, kendo.effects.Transition.easeOutExpo, instant);
},
_cancelMove: function (ease, instant) {
this.pane.transitionTo(0, ease, instant);
},
_resetPages: function () {
this.page = this.options.page || 0;
this._updatePagesContent(this.page);
this._repositionPages();
this.trigger('reset');
},
_onResize: function () {
this.pageCount = ceil(this.dataSource.total() / this.options.itemsPerPage);
if (this._pendingPageRefresh) {
this._updatePagesContent(this.page);
this._pendingPageRefresh = false;
}
this.trigger('resize');
},
_onReset: function () {
this.pageCount = ceil(this.dataSource.total() / this.options.itemsPerPage);
this._resetPages();
},
_onEndReached: function () {
this._pendingPageRefresh = true;
},
_repositionPages: function () {
var pages = this.pages;
pages[0].position(LEFT_PAGE);
pages[1].position(CETER_PAGE);
pages[2].position(RIGHT_PAGE);
},
_updatePagesContent: function (offset) {
var pages = this.pages, currentPage = offset || 0;
this.setPageContent(pages[0], currentPage - 1);
this.setPageContent(pages[1], currentPage);
this.setPageContent(pages[2], currentPage + 1);
},
setPageContent: function (page, index) {
var buffer = this.buffer, template = this.template, emptyTemplate = this.emptyTemplate, view = null;
if (index >= 0) {
view = buffer.at(index);
if ($.isArray(view) && !view.length) {
view = null;
}
}
this.trigger(CLEANUP, { item: page.element });
if (view !== null) {
page.content(template(view));
} else {
page.content(emptyTemplate({}));
}
kendo.mobile.init(page.element);
this.trigger(ITEM_CHANGE, {
item: page.element,
data: view,
ns: kendo.mobile.ui
});
}
});
kendo.mobile.ui.VirtualScrollViewContent = VirtualScrollViewContent;
var Page = kendo.Class.extend({
init: function (container) {
this.element = $('');
this.width = container.width();
this.element.width(this.width);
container.append(this.element);
},
content: function (theContent) {
this.element.html(theContent);
},
position: function (position) {
this.element.css('transform', 'translate3d(' + this.width * position + 'px, 0, 0)');
},
setWidth: function (width) {
this.width = width;
this.element.width(width);
}
});
kendo.mobile.ui.VirtualPage = Page;
var ScrollView = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
options = that.options;
element = that.element;
kendo.stripWhitespace(element[0]);
element.wrapInner('').addClass('km-scrollview');
if (this.options.enablePager) {
this.pager = new Pager(this);
if (this.options.pagerOverlay) {
element.addClass('km-scrollview-overlay');
}
}
that.inner = element.children().first();
that.page = 0;
that.inner.css('height', options.contentHeight);
that.pane = new ElasticPane(that.inner, {
duration: this.options.duration,
transitionEnd: proxy(this, '_transitionEnd'),
dragStart: proxy(this, '_dragStart'),
dragEnd: proxy(this, '_dragEnd'),
change: proxy(this, REFRESH)
});
that.bind('resize', function () {
that.pane.refresh();
});
that.page = options.page;
var empty = this.inner.children().length === 0;
var content = empty ? new VirtualScrollViewContent(that.inner, that.pane, options) : new ScrollViewContent(that.inner, that.pane, options);
content.page = that.page;
content.bind('reset', function () {
this._pendingPageRefresh = false;
that._syncWithContent();
that.trigger(REFRESH, {
pageCount: content.pageCount,
page: content.page
});
});
content.bind('resize', function () {
that.trigger(REFRESH, {
pageCount: content.pageCount,
page: content.page
});
});
content.bind(ITEM_CHANGE, function (e) {
that.trigger(ITEM_CHANGE, e);
that.angular('compile', function () {
return {
elements: e.item,
data: [{ dataItem: e.data }]
};
});
});
content.bind(CLEANUP, function (e) {
that.angular('cleanup', function () {
return { elements: e.item };
});
});
that._content = content;
that.setDataSource(options.dataSource);
var mobileContainer = that.container();
if (mobileContainer.nullObject) {
that.viewInit();
that.viewShow();
} else {
mobileContainer.bind('show', proxy(this, 'viewShow')).bind('init', proxy(this, 'viewInit'));
}
},
options: {
name: 'ScrollView',
page: 0,
duration: 400,
velocityThreshold: 0.8,
contentHeight: 'auto',
pageSize: 1,
itemsPerPage: 1,
bounceVelocityThreshold: 1.6,
enablePager: true,
pagerOverlay: false,
autoBind: true,
template: '',
emptyTemplate: ''
},
events: [
CHANGING,
CHANGE,
REFRESH
],
destroy: function () {
Widget.fn.destroy.call(this);
kendo.destroy(this.element);
},
viewInit: function () {
if (this.options.autoBind) {
this._content.scrollTo(this._content.page, true);
}
},
viewShow: function () {
this.pane.refresh();
},
refresh: function () {
var content = this._content;
content.resizeTo(this.pane.size());
this.page = content.page;
this.trigger(REFRESH, {
pageCount: content.pageCount,
page: content.page
});
},
content: function (html) {
this.element.children().first().html(html);
this._content._getPages();
this.pane.refresh();
},
value: function (item) {
var dataSource = this.dataSource;
if (item) {
this.scrollTo(dataSource.indexOf(item), true);
} else {
return dataSource.at(this.page);
}
},
scrollTo: function (page, instant) {
this._content.scrollTo(page, instant);
this._syncWithContent();
},
prev: function () {
var that = this, prevPage = that.page - 1;
if (that._content instanceof VirtualScrollViewContent) {
that._content.paneMoved(RIGHT_SWIPE, undefined, function (eventData) {
return that.trigger(CHANGING, eventData);
});
} else if (prevPage > -1) {
that.scrollTo(prevPage);
}
},
next: function () {
var that = this, nextPage = that.page + 1;
if (that._content instanceof VirtualScrollViewContent) {
that._content.paneMoved(LEFT_SWIPE, undefined, function (eventData) {
return that.trigger(CHANGING, eventData);
});
} else if (nextPage < that._content.pageCount) {
that.scrollTo(nextPage);
}
},
setDataSource: function (dataSource) {
if (!(this._content instanceof VirtualScrollViewContent)) {
return;
}
var emptyDataSource = !dataSource;
this.dataSource = DataSource.create(dataSource);
this._content.setDataSource(this.dataSource);
if (this.options.autoBind && !emptyDataSource) {
this.dataSource.fetch();
}
},
items: function () {
return this.element.find('.' + VIRTUAL_PAGE_CLASS);
},
_syncWithContent: function () {
var pages = this._content.pages, buffer = this._content.buffer, data, element;
this.page = this._content.page;
data = buffer ? buffer.at(this.page) : undefined;
if (!(data instanceof Array)) {
data = [data];
}
element = pages ? pages[1].element : undefined;
this.trigger(CHANGE, {
page: this.page,
element: element,
data: data
});
},
_dragStart: function () {
if (this._content.forcePageUpdate()) {
this._syncWithContent();
}
},
_dragEnd: function (e) {
var that = this, velocity = e.x.velocity, velocityThreshold = this.options.velocityThreshold, swipeType = NUDGE, bounce = abs(velocity) > this.options.bounceVelocityThreshold;
if (velocity > velocityThreshold) {
swipeType = RIGHT_SWIPE;
} else if (velocity < -velocityThreshold) {
swipeType = LEFT_SWIPE;
}
this._content.paneMoved(swipeType, bounce, function (eventData) {
return that.trigger(CHANGING, eventData);
});
},
_transitionEnd: function () {
if (this._content.updatePage()) {
this._syncWithContent();
}
}
});
ui.plugin(ScrollView);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.switch', [
'kendo.fx',
'kendo.userevents'
], f);
}(function () {
var __meta__ = {
id: 'mobile.switch',
name: 'Switch',
category: 'mobile',
description: 'The mobile Switch widget is used to display two exclusive choices.',
depends: [
'fx',
'userevents'
]
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, support = kendo.support, CHANGE = 'change', SWITCHON = 'km-switch-on', SWITCHOFF = 'km-switch-off', MARGINLEFT = 'margin-left', ACTIVE_STATE = 'km-state-active', DISABLED_STATE = 'km-state-disabled', DISABLED = 'disabled', TRANSFORMSTYLE = support.transitions.css + 'transform', proxy = $.proxy;
function limitValue(value, minLimit, maxLimit) {
return Math.max(minLimit, Math.min(maxLimit, value));
}
var SWITCH_MARKUP = ' {0} {1} ';
var Switch = Widget.extend({
init: function (element, options) {
var that = this, checked;
Widget.fn.init.call(that, element, options);
options = that.options;
that.wrapper = $(kendo.format(SWITCH_MARKUP, options.onLabel, options.offLabel));
that.handle = that.wrapper.find('.km-switch-handle');
that.background = that.wrapper.find('.km-switch-background');
that.wrapper.insertBefore(that.element).prepend(that.element);
that._drag();
that.origin = parseInt(that.background.css(MARGINLEFT), 10);
that.constrain = 0;
that.snapPoint = 0;
element = that.element[0];
element.type = 'checkbox';
that._animateBackground = true;
checked = that.options.checked;
if (checked === null) {
checked = element.checked;
}
that.check(checked);
that.options.enable = that.options.enable && !that.element.attr(DISABLED);
that.enable(that.options.enable);
that.refresh();
kendo.notify(that, kendo.mobile.ui);
},
refresh: function () {
var that = this, handleWidth = that.handle.outerWidth(true);
that.width = that.wrapper.width();
that.constrain = that.width - handleWidth;
that.snapPoint = that.constrain / 2;
if (typeof that.origin != 'number') {
that.origin = parseInt(that.background.css(MARGINLEFT), 10);
}
that.background.data('origin', that.origin);
that.check(that.element[0].checked);
},
events: [CHANGE],
options: {
name: 'Switch',
onLabel: 'on',
offLabel: 'off',
checked: null,
enable: true
},
check: function (check) {
var that = this, element = that.element[0];
if (check === undefined) {
return element.checked;
}
that._position(check ? that.constrain : 0);
element.checked = check;
that.wrapper.toggleClass(SWITCHON, check).toggleClass(SWITCHOFF, !check);
},
value: function () {
return this.check.apply(this, arguments);
},
destroy: function () {
Widget.fn.destroy.call(this);
this.userEvents.destroy();
},
toggle: function () {
var that = this;
that.check(!that.element[0].checked);
},
enable: function (enable) {
var element = this.element, wrapper = this.wrapper;
if (typeof enable == 'undefined') {
enable = true;
}
this.options.enable = enable;
if (enable) {
element.removeAttr(DISABLED);
} else {
element.attr(DISABLED, DISABLED);
}
wrapper.toggleClass(DISABLED_STATE, !enable);
},
_resize: function () {
this.refresh();
},
_move: function (e) {
var that = this;
e.preventDefault();
that._position(limitValue(that.position + e.x.delta, 0, that.width - that.handle.outerWidth(true)));
},
_position: function (position) {
var that = this;
that.position = position;
that.handle.css(TRANSFORMSTYLE, 'translatex(' + position + 'px)');
if (that._animateBackground) {
that.background.css(MARGINLEFT, that.origin + position);
}
},
_start: function () {
if (!this.options.enable) {
this.userEvents.cancel();
} else {
this.userEvents.capture();
this.handle.addClass(ACTIVE_STATE);
}
},
_stop: function () {
var that = this;
that.handle.removeClass(ACTIVE_STATE);
that._toggle(that.position > that.snapPoint);
},
_toggle: function (checked) {
var that = this, handle = that.handle, element = that.element[0], value = element.checked, duration = kendo.mobile.application && kendo.mobile.application.os.wp ? 100 : 200, distance;
that.wrapper.toggleClass(SWITCHON, checked).toggleClass(SWITCHOFF, !checked);
that.position = distance = checked * that.constrain;
if (that._animateBackground) {
that.background.kendoStop(true, true).kendoAnimate({
effects: 'slideMargin',
offset: distance,
reset: true,
reverse: !checked,
axis: 'left',
duration: duration
});
}
handle.kendoStop(true, true).kendoAnimate({
effects: 'slideTo',
duration: duration,
offset: distance + 'px,0',
reset: true,
complete: function () {
if (value !== checked) {
element.checked = checked;
that.trigger(CHANGE, { checked: checked });
}
}
});
},
_drag: function () {
var that = this;
that.userEvents = new kendo.UserEvents(that.wrapper, {
fastTap: true,
tap: function () {
if (that.options.enable) {
that._toggle(!that.element[0].checked);
}
},
start: proxy(that._start, that),
move: proxy(that._move, that),
end: proxy(that._stop, that)
});
}
});
ui.plugin(Switch);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile.tabstrip', ['kendo.core'], f);
}(function () {
var __meta__ = {
id: 'mobile.tabstrip',
name: 'TabStrip',
category: 'mobile',
description: 'The mobile TabStrip widget is used inside a mobile view or layout footer element to display an application-wide group of navigation buttons.',
depends: ['core']
};
(function ($, undefined) {
var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, ACTIVE_STATE_CLASS = 'km-state-active', SELECT = 'select';
function createBadge(value) {
return $('' + value + '');
}
var TabStrip = Widget.extend({
init: function (element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
that.container().bind('show', $.proxy(this, 'refresh'));
that.element.addClass('km-tabstrip').find('a').each(that._buildButton).eq(that.options.selectedIndex).addClass(ACTIVE_STATE_CLASS);
that.element.on('down', 'a', '_release');
},
events: [SELECT],
switchTo: function (url) {
var tabs = this.element.find('a'), tab, path, idx = 0, length = tabs.length;
if (isNaN(url)) {
for (; idx < length; idx++) {
tab = tabs[idx];
path = tab.href.replace(/(\#.+)(\?.+)$/, '$1');
if (path.indexOf(url, path.length - url.length) !== -1) {
this._setActiveItem($(tab));
return true;
}
}
} else {
this._setActiveItem(tabs.eq(url));
return true;
}
return false;
},
switchByFullUrl: function (url) {
var tab;
tab = this.element.find('a[href$=\'' + url + '\']');
this._setActiveItem(tab);
},
clear: function () {
this.currentItem().removeClass(ACTIVE_STATE_CLASS);
},
currentItem: function () {
return this.element.children('.' + ACTIVE_STATE_CLASS);
},
badge: function (item, value) {
var tabstrip = this.element, badge;
if (!isNaN(item)) {
item = tabstrip.children().get(item);
}
item = tabstrip.find(item);
badge = $(item.find('.km-badge')[0] || createBadge(value).insertAfter(item.children('.km-icon')));
if (value || value === 0) {
badge.html(value);
return this;
}
if (value === false) {
badge.empty().remove();
return this;
}
return badge.html();
},
_release: function (e) {
if (e.which > 1) {
return;
}
var that = this, item = $(e.currentTarget);
if (item[0] === that.currentItem()[0]) {
return;
}
if (that.trigger(SELECT, { item: item })) {
e.preventDefault();
} else {
that._setActiveItem(item);
}
},
_setActiveItem: function (item) {
if (!item[0]) {
return;
}
this.clear();
item.addClass(ACTIVE_STATE_CLASS);
},
_buildButton: function () {
var button = $(this), icon = kendo.attrValue(button, 'icon'), badge = kendo.attrValue(button, 'badge'), image = button.find('img'), iconSpan = $('');
button.addClass('km-button').attr(kendo.attr('role'), 'tab').contents().not(image).wrapAll('');
if (image[0]) {
image.addClass('km-image').prependTo(button);
} else {
button.prepend(iconSpan);
if (icon) {
iconSpan.addClass('km-' + icon);
if (badge || badge === 0) {
createBadge(badge).insertAfter(iconSpan);
}
}
}
},
refresh: function (e) {
var url = e.view.id;
if (url && !this.switchTo(e.view.id)) {
this.switchTo(url);
}
},
options: {
name: 'TabStrip',
selectedIndex: 0,
enable: true
}
});
ui.plugin(TabStrip);
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.mobile', [
'kendo.core',
'kendo.fx',
'kendo.data.odata',
'kendo.data.xml',
'kendo.data',
'kendo.data.signalr',
'kendo.binder',
'kendo.validator',
'kendo.router',
'kendo.view',
'kendo.userevents',
'kendo.draganddrop',
'kendo.popup',
'kendo.touch',
'kendo.mobile.popover',
'kendo.mobile.loader',
'kendo.mobile.scroller',
'kendo.mobile.shim',
'kendo.mobile.view',
'kendo.mobile.modalview',
'kendo.mobile.drawer',
'kendo.mobile.splitview',
'kendo.mobile.pane',
'kendo.mobile.application',
'kendo.mobile.actionsheet',
'kendo.mobile.button',
'kendo.mobile.buttongroup',
'kendo.mobile.collapsible',
'kendo.mobile.listview',
'kendo.mobile.navbar',
'kendo.mobile.scrollview',
'kendo.mobile.switch',
'kendo.mobile.tabstrip',
'kendo.angular',
'kendo.webcomponents',
'kendo.angular2'
], f);
}(function () {
'bundle all';
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dataviz.mobile', [
'kendo.dataviz',
'kendo.mobile'
], f);
}(function () {
'bundle all';
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));