diff --git a/app/src/main/assets/dist/scroll-jqlite.js b/app/src/main/assets/dist/scroll-jqlite.js new file mode 100644 index 0000000..8a340ae --- /dev/null +++ b/app/src/main/assets/dist/scroll-jqlite.js @@ -0,0 +1,229 @@ +'use strict'; +angular.module('ui.scroll.jqlite', ['ui.scroll']).service('jqLiteExtras', [ + '$log', '$window', function(console, window) { + return { + registerFor: function(element) { + var convertToPx, css, getMeasurements, getStyle, getWidthHeight, isWindow, scrollTo; + css = angular.element.prototype.css; + element.prototype.css = function(name, value) { + var elem, self; + self = this; + elem = self[0]; + if (!(!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style)) { + return css.call(self, name, value); + } + }; + isWindow = function(obj) { + return obj && obj.document && obj.location && obj.alert && obj.setInterval; + }; + scrollTo = function(self, direction, value) { + var elem, method, preserve, prop, _ref; + elem = self[0]; + _ref = { + top: ['scrollTop', 'pageYOffset', 'scrollLeft'], + left: ['scrollLeft', 'pageXOffset', 'scrollTop'] + }[direction], method = _ref[0], prop = _ref[1], preserve = _ref[2]; + if (isWindow(elem)) { + if (angular.isDefined(value)) { + return elem.scrollTo(self[preserve].call(self), value); + } else { + if (prop in elem) { + return elem[prop]; + } else { + return elem.document.documentElement[method]; + } + } + } else { + if (angular.isDefined(value)) { + return elem[method] = value; + } else { + return elem[method]; + } + } + }; + if (window.getComputedStyle) { + getStyle = function(elem) { + return window.getComputedStyle(elem, null); + }; + convertToPx = function(elem, value) { + return parseFloat(value); + }; + } else { + getStyle = function(elem) { + return elem.currentStyle; + }; + convertToPx = function(elem, value) { + var core_pnum, left, result, rnumnonpx, rs, rsLeft, style; + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source; + rnumnonpx = new RegExp('^(' + core_pnum + ')(?!px)[a-z%]+$', 'i'); + if (!rnumnonpx.test(value)) { + return parseFloat(value); + } else { + style = elem.style; + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + if (rs) { + rs.left = style.left; + } + style.left = value; + result = style.pixelLeft; + style.left = left; + if (rsLeft) { + rs.left = rsLeft; + } + return result; + } + }; + } + getMeasurements = function(elem, measure) { + var base, borderA, borderB, computedMarginA, computedMarginB, computedStyle, dirA, dirB, marginA, marginB, paddingA, paddingB, _ref; + if (isWindow(elem)) { + base = document.documentElement[{ + height: 'clientHeight', + width: 'clientWidth' + }[measure]]; + return { + base: base, + padding: 0, + border: 0, + margin: 0 + }; + } + _ref = { + width: [elem.offsetWidth, 'Left', 'Right'], + height: [elem.offsetHeight, 'Top', 'Bottom'] + }[measure], base = _ref[0], dirA = _ref[1], dirB = _ref[2]; + computedStyle = getStyle(elem); + paddingA = convertToPx(elem, computedStyle['padding' + dirA]) || 0; + paddingB = convertToPx(elem, computedStyle['padding' + dirB]) || 0; + borderA = convertToPx(elem, computedStyle['border' + dirA + 'Width']) || 0; + borderB = convertToPx(elem, computedStyle['border' + dirB + 'Width']) || 0; + computedMarginA = computedStyle['margin' + dirA]; + computedMarginB = computedStyle['margin' + dirB]; + marginA = convertToPx(elem, computedMarginA) || 0; + marginB = convertToPx(elem, computedMarginB) || 0; + return { + base: base, + padding: paddingA + paddingB, + border: borderA + borderB, + margin: marginA + marginB + }; + }; + getWidthHeight = function(elem, direction, measure) { + var computedStyle, measurements, result; + measurements = getMeasurements(elem, direction); + if (measurements.base > 0) { + return { + base: measurements.base - measurements.padding - measurements.border, + outer: measurements.base, + outerfull: measurements.base + measurements.margin + }[measure]; + } else { + computedStyle = getStyle(elem); + result = computedStyle[direction]; + if (result < 0 || result === null) { + result = elem.style[direction] || 0; + } + result = parseFloat(result) || 0; + return { + base: result - measurements.padding - measurements.border, + outer: result, + outerfull: result + measurements.padding + measurements.border + measurements.margin + }[measure]; + } + }; + return angular.forEach({ + before: function(newElem) { + var children, elem, i, parent, self, _i, _ref; + self = this; + elem = self[0]; + parent = self.parent(); + children = parent.contents(); + if (children[0] === elem) { + return parent.prepend(newElem); + } else { + for (i = _i = 1, _ref = children.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) { + if (children[i] === elem) { + angular.element(children[i - 1]).after(newElem); + return; + } + } + throw new Error('invalid DOM structure ' + elem.outerHTML); + } + }, + height: function(value) { + var self; + self = this; + if (angular.isDefined(value)) { + if (angular.isNumber(value)) { + value = value + 'px'; + } + return css.call(self, 'height', value); + } else { + return getWidthHeight(this[0], 'height', 'base'); + } + }, + outerHeight: function(option) { + return getWidthHeight(this[0], 'height', option ? 'outerfull' : 'outer'); + }, + /* + UIScroller no longer relies on jQuery method offset. The jQLite implementation of the method + is kept here just for the reference. Also the offset setter method was never implemented + */ + + offset: function(value) { + var box, doc, docElem, elem, self, win; + self = this; + if (arguments.length) { + if (value === void 0) { + return self; + } else { + throw new Error('offset setter method is not implemented'); + } + } + box = { + top: 0, + left: 0 + }; + elem = self[0]; + doc = elem && elem.ownerDocument; + if (!doc) { + return; + } + docElem = doc.documentElement; + if (elem.getBoundingClientRect != null) { + box = elem.getBoundingClientRect(); + } + win = doc.defaultView || doc.parentWindow; + return { + top: box.top + (win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0), + left: box.left + (win.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0) + }; + }, + scrollTop: function(value) { + return scrollTo(this, 'top', value); + }, + scrollLeft: function(value) { + return scrollTo(this, 'left', value); + } + }, function(value, key) { + if (!element.prototype[key]) { + return element.prototype[key] = value; + } + }); + } + }; + } +]).run([ + '$log', '$window', 'jqLiteExtras', function(console, window, jqLiteExtras) { + if (!window.jQuery) { + return jqLiteExtras.registerFor(angular.element); + } + } +]); + +/* +//# sourceURL=src/scripts/ui-scroll-jqlite.js +*/ + diff --git a/app/src/main/assets/dist/scroll.js b/app/src/main/assets/dist/scroll.js new file mode 100644 index 0000000..27966ea --- /dev/null +++ b/app/src/main/assets/dist/scroll.js @@ -0,0 +1,576 @@ +'use strict'; +/* +globals: angular, window + + List of used element methods available in JQuery but not in JQuery Lite + + element.before(elem) + element.height() + element.outerHeight(true) + element.height(value) = only for Top/Bottom padding elements + element.scrollTop() + element.scrollTop(value) +*/ + +angular.module('ui.scroll', []).directive('uiScrollViewport', [ + '$log', function() { + return { + controller: [ + '$scope', '$element', function(scope, element) { + return element; + } + ] + }; + } +]).directive('uiScroll', [ + '$log', '$injector', '$rootScope', '$timeout', function(console, $injector, $rootScope, $timeout) { + return { + require: ['?^uiScrollViewport'], + transclude: 'element', + priority: 1000, + terminal: true, + compile: function(elementTemplate, attr, linker) { + return function($scope, element, $attr, controllers) { + var adapter, adjustBuffer, adjustRowHeight, bof, bottomVisiblePos, buffer, bufferPadding, bufferSize, clipBottom, clipTop, datasource, datasourceName, doAdjustment, enqueueFetch, eof, eventListener, fetch, finalize, first, hideElementBeforeAppend, insert, isDatasource, isLoading, itemName, loading, log, match, next, pending, reload, removeFromBuffer, resizeHandler, ridActual, scrollHandler, scrollHeight, shouldLoadBottom, shouldLoadTop, showElementAfterRender, tempScope, topVisible, topVisibleElement, topVisibleItem, topVisiblePos, topVisibleScope, viewport, viewportScope, wheelHandler; + log = console.debug || console.log; + match = $attr.uiScroll.match(/^\s*(\w+)\s+in\s+(\w+)\s*$/); + if (!match) { + throw new Error('Expected uiScroll in form of \'_item_ in _datasource_\' but got \'' + $attr.uiScroll + '\''); + } + itemName = match[1]; + datasourceName = match[2]; + isDatasource = function(datasource) { + return angular.isObject(datasource) && datasource.get && angular.isFunction(datasource.get); + }; + datasource = $scope[datasourceName]; + if (!isDatasource(datasource)) { + datasource = $injector.get(datasourceName); + if (!isDatasource(datasource)) { + throw new Error('' + datasourceName + ' is not a valid datasource'); + } + } + bufferSize = Math.max(3, +$attr.bufferSize || 10); + bufferPadding = function() { + return viewport.outerHeight() * Math.max(0.1, +$attr.padding || 0.1); + }; + scrollHeight = function(elem) { + var _ref; + return (_ref = elem[0].scrollHeight) != null ? _ref : elem[0].document.documentElement.scrollHeight; + }; + adapter = null; + linker(tempScope = $scope.$new(), function(template) { + var bottomPadding, createPadding, padding, repeaterType, topPadding, viewport; + repeaterType = template[0].localName; + if (repeaterType === 'dl') { + throw new Error('ui-scroll directive does not support <' + template[0].localName + '> as a repeating tag: ' + template[0].outerHTML); + } + if (repeaterType !== 'li' && repeaterType !== 'tr') { + repeaterType = 'div'; + } + viewport = controllers[0] || angular.element(window); + viewport.css({ + 'overflow-y': 'auto', + 'display': 'block' + }); + padding = function(repeaterType) { + var div, result, table; + switch (repeaterType) { + case 'tr': + table = angular.element('
'); + div = table.find('div'); + result = table.find('tr'); + result.paddingHeight = function() { + return div.height.apply(div, arguments); + }; + return result; + default: + result = angular.element('<' + repeaterType + '>'); + result.paddingHeight = result.height; + return result; + } + }; + createPadding = function(padding, element, direction) { + element[{ + top: 'before', + bottom: 'after' + }[direction]](padding); + return { + paddingHeight: function() { + return padding.paddingHeight.apply(padding, arguments); + }, + insert: function(element) { + return padding[{ + top: 'after', + bottom: 'before' + }[direction]](element); + } + }; + }; + topPadding = createPadding(padding(repeaterType), element, 'top'); + bottomPadding = createPadding(padding(repeaterType), element, 'bottom'); + tempScope.$destroy(); + return adapter = { + viewport: viewport, + topPadding: topPadding.paddingHeight, + bottomPadding: bottomPadding.paddingHeight, + append: bottomPadding.insert, + prepend: topPadding.insert, + bottomDataPos: function() { + return scrollHeight(viewport) - bottomPadding.paddingHeight(); + }, + topDataPos: function() { + return topPadding.paddingHeight(); + } + }; + }); + viewport = adapter.viewport; + viewportScope = viewport.scope() || $rootScope; + if (angular.isDefined($attr.topVisible)) { + topVisibleItem = function(item) { + return viewportScope[$attr.topVisible] = item; + }; + } + if (angular.isDefined($attr.topVisibleElement)) { + topVisibleElement = function(element) { + return viewportScope[$attr.topVisibleElement] = element; + }; + } + if (angular.isDefined($attr.topVisibleScope)) { + topVisibleScope = function(scope) { + return viewportScope[$attr.topVisibleScope] = scope; + }; + } + topVisible = function(item) { + if (topVisibleItem) { + topVisibleItem(item.scope[itemName]); + } + if (topVisibleElement) { + topVisibleElement(item.element); + } + if (topVisibleScope) { + topVisibleScope(item.scope); + } + if (datasource.topVisible) { + return datasource.topVisible(item); + } + }; + if (angular.isDefined($attr.isLoading)) { + loading = function(value) { + viewportScope[$attr.isLoading] = value; + if (datasource.loading) { + return datasource.loading(value); + } + }; + } else { + loading = function(value) { + if (datasource.loading) { + return datasource.loading(value); + } + }; + } + ridActual = 0; + first = 1; + next = 1; + buffer = []; + pending = []; + eof = false; + bof = false; + isLoading = false; + removeFromBuffer = function(start, stop) { + var i, _i; + for (i = _i = start; start <= stop ? _i < stop : _i > stop; i = start <= stop ? ++_i : --_i) { + buffer[i].scope.$destroy(); + buffer[i].element.remove(); + } + return buffer.splice(start, stop - start); + }; + reload = function() { + ridActual++; + first = 1; + next = 1; + removeFromBuffer(0, buffer.length); + adapter.topPadding(0); + adapter.bottomPadding(0); + pending = []; + eof = false; + bof = false; + return adjustBuffer(ridActual, false); + }; + bottomVisiblePos = function() { + return viewport.scrollTop() + viewport.outerHeight(); + }; + topVisiblePos = function() { + return viewport.scrollTop(); + }; + shouldLoadBottom = function() { + return !eof && adapter.bottomDataPos() < bottomVisiblePos() + bufferPadding(); + }; + clipBottom = function() { + var bottomHeight, i, item, itemHeight, itemTop, newRow, overage, rowTop, _i, _ref; + bottomHeight = 0; + overage = 0; + for (i = _i = _ref = buffer.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) { + item = buffer[i]; + itemTop = item.element.offset().top; + newRow = rowTop !== itemTop; + rowTop = itemTop; + if (newRow) { + itemHeight = item.element.outerHeight(true); + } + if (adapter.bottomDataPos() - bottomHeight - itemHeight > bottomVisiblePos() + bufferPadding()) { + if (newRow) { + bottomHeight += itemHeight; + } + overage++; + eof = false; + } else { + if (newRow) { + break; + } + overage++; + } + } + if (overage > 0) { + adapter.bottomPadding(adapter.bottomPadding() + bottomHeight); + removeFromBuffer(buffer.length - overage, buffer.length); + next -= overage; + return log('clipped off bottom ' + overage + ' bottom padding ' + (adapter.bottomPadding())); + } + }; + shouldLoadTop = function() { + return !bof && (adapter.topDataPos() > topVisiblePos() - bufferPadding()); + }; + clipTop = function() { + var item, itemHeight, itemTop, newRow, overage, rowTop, topHeight, _i, _len; + topHeight = 0; + overage = 0; + for (_i = 0, _len = buffer.length; _i < _len; _i++) { + item = buffer[_i]; + itemTop = item.element.offset().top; + newRow = rowTop !== itemTop; + rowTop = itemTop; + if (newRow) { + itemHeight = item.element.outerHeight(true); + } + if (adapter.topDataPos() + topHeight + itemHeight < topVisiblePos() - bufferPadding()) { + if (newRow) { + topHeight += itemHeight; + } + overage++; + bof = false; + } else { + if (newRow) { + break; + } + overage++; + } + } + if (overage > 0) { + adapter.topPadding(adapter.topPadding() + topHeight); + removeFromBuffer(0, overage); + first += overage; + return log('clipped off top ' + overage + ' top padding ' + (adapter.topPadding())); + } + }; + enqueueFetch = function(rid, direction, scrolling) { + if (!isLoading) { + isLoading = true; + loading(true); + } + if (pending.push(direction) === 1) { + return fetch(rid, scrolling); + } + }; + hideElementBeforeAppend = function(element) { + element.displayTemp = element.css('display'); + return element.css('display', 'none'); + }; + showElementAfterRender = function(element) { + if (element.hasOwnProperty('displayTemp')) { + return element.css('display', element.displayTemp); + } + }; + insert = function(index, item) { + var itemScope, toBeAppended, wrapper; + itemScope = $scope.$new(); + itemScope[itemName] = item; + toBeAppended = index > first; + itemScope.$index = index; + if (toBeAppended) { + itemScope.$index--; + } + wrapper = { + scope: itemScope + }; + linker(itemScope, function(clone) { + wrapper.element = clone; + if (toBeAppended) { + if (index === next) { + hideElementBeforeAppend(clone); + adapter.append(clone); + return buffer.push(wrapper); + } else { + buffer[index - first].element.after(clone); + return buffer.splice(index - first + 1, 0, wrapper); + } + } else { + hideElementBeforeAppend(clone); + adapter.prepend(clone); + return buffer.unshift(wrapper); + } + }); + return { + appended: toBeAppended, + wrapper: wrapper + }; + }; + adjustRowHeight = function(appended, wrapper) { + var newHeight; + if (appended) { + return adapter.bottomPadding(Math.max(0, adapter.bottomPadding() - wrapper.element.outerHeight(true))); + } else { + newHeight = adapter.topPadding() - wrapper.element.outerHeight(true); + if (newHeight >= 0) { + return adapter.topPadding(newHeight); + } else { + return viewport.scrollTop(viewport.scrollTop() + wrapper.element.outerHeight(true)); + } + } + }; + doAdjustment = function(rid, scrolling, finalize) { + var item, itemHeight, itemTop, newRow, rowTop, topHeight, _i, _len, _results; + log('top {actual=' + (adapter.topDataPos()) + ' visible from=' + (topVisiblePos()) + ' bottom {visible through=' + (bottomVisiblePos()) + ' actual=' + (adapter.bottomDataPos()) + '}'); + if (shouldLoadBottom()) { + enqueueFetch(rid, true, scrolling); + } else { + if (shouldLoadTop()) { + enqueueFetch(rid, false, scrolling); + } + } + if (finalize) { + finalize(rid); + } + if (pending.length === 0) { + topHeight = 0; + _results = []; + for (_i = 0, _len = buffer.length; _i < _len; _i++) { + item = buffer[_i]; + itemTop = item.element.offset().top; + newRow = rowTop !== itemTop; + rowTop = itemTop; + if (newRow) { + itemHeight = item.element.outerHeight(true); + } + if (newRow && (adapter.topDataPos() + topHeight + itemHeight < topVisiblePos())) { + _results.push(topHeight += itemHeight); + } else { + if (newRow) { + topVisible(item); + } + break; + } + } + return _results; + } + }; + adjustBuffer = function(rid, scrolling, newItems, finalize) { + if (newItems && newItems.length) { + return $timeout(function() { + var itemTop, row, rowTop, rows, _i, _j, _len, _len1; + rows = []; + for (_i = 0, _len = newItems.length; _i < _len; _i++) { + row = newItems[_i]; + element = row.wrapper.element; + showElementAfterRender(element); + itemTop = element.offset().top; + if (rowTop !== itemTop) { + rows.push(row); + rowTop = itemTop; + } + } + for (_j = 0, _len1 = rows.length; _j < _len1; _j++) { + row = rows[_j]; + adjustRowHeight(row.appended, row.wrapper); + } + return doAdjustment(rid, scrolling, finalize); + }); + } else { + return doAdjustment(rid, scrolling, finalize); + } + }; + finalize = function(rid, scrolling, newItems) { + return adjustBuffer(rid, scrolling, newItems, function() { + pending.shift(); + if (pending.length === 0) { + isLoading = false; + return loading(false); + } else { + return fetch(rid, scrolling); + } + }); + }; + fetch = function(rid, scrolling) { + var direction; + direction = pending[0]; + if (direction) { + if (buffer.length && !shouldLoadBottom()) { + return finalize(rid, scrolling); + } else { + return datasource.get(next, bufferSize, function(result) { + var item, newItems, _i, _len; + if (rid && rid !== ridActual) { + return; + } + newItems = []; + if (result.length < bufferSize) { + eof = true; + adapter.bottomPadding(0); + } + if (result.length > 0) { + clipTop(); + for (_i = 0, _len = result.length; _i < _len; _i++) { + item = result[_i]; + newItems.push(insert(++next, item)); + } + } + return finalize(rid, scrolling, newItems); + }); + } + } else { + if (buffer.length && !shouldLoadTop()) { + return finalize(rid, scrolling); + } else { + return datasource.get(first - bufferSize, bufferSize, function(result) { + var i, newItems, _i, _ref; + if (rid && rid !== ridActual) { + return; + } + newItems = []; + if (result.length < bufferSize) { + bof = true; + adapter.topPadding(0); + } + if (result.length > 0) { + if (buffer.length) { + clipBottom(); + } + for (i = _i = _ref = result.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) { + newItems.unshift(insert(--first, result[i])); + } + } + return finalize(rid, scrolling, newItems); + }); + } + } + }; + resizeHandler = function() { + if (!$rootScope.$$phase && !isLoading) { + adjustBuffer(null, false); + return $scope.$apply(); + } + }; + viewport.bind('resize', resizeHandler); + scrollHandler = function() { + if (!$rootScope.$$phase && !isLoading) { + adjustBuffer(null, true); + return $scope.$apply(); + } + }; + viewport.bind('scroll', scrollHandler); + wheelHandler = function(event) { + var scrollTop, yMax; + scrollTop = viewport[0].scrollTop; + yMax = viewport[0].scrollHeight - viewport[0].clientHeight; + if ((scrollTop === 0 && !bof) || (scrollTop === yMax && !eof)) { + return event.preventDefault(); + } + }; + viewport.bind('mousewheel', wheelHandler); + $scope.$watch(datasource.revision, function() { + return reload(); + }); + if (datasource.scope) { + eventListener = datasource.scope.$new(); + } else { + eventListener = $scope.$new(); + } + $scope.$on('$destroy', function() { + eventListener.$destroy(); + viewport.unbind('resize', resizeHandler); + viewport.unbind('scroll', scrollHandler); + return viewport.unbind('mousewheel', wheelHandler); + }); + eventListener.$on('update.items', function(event, locator, newItem) { + var wrapper, _fn, _i, _len, _ref; + if (angular.isFunction(locator)) { + _fn = function(wrapper) { + return locator(wrapper.scope); + }; + for (_i = 0, _len = buffer.length; _i < _len; _i++) { + wrapper = buffer[_i]; + _fn(wrapper); + } + } else { + if ((0 <= (_ref = locator - first - 1) && _ref < buffer.length)) { + buffer[locator - first - 1].scope[itemName] = newItem; + } + } + return null; + }); + eventListener.$on('delete.items', function(event, locator) { + var i, item, temp, wrapper, _fn, _i, _j, _k, _len, _len1, _len2, _ref; + if (angular.isFunction(locator)) { + temp = []; + for (_i = 0, _len = buffer.length; _i < _len; _i++) { + item = buffer[_i]; + temp.unshift(item); + } + _fn = function(wrapper) { + if (locator(wrapper.scope)) { + removeFromBuffer(temp.length - 1 - i, temp.length - i); + return next--; + } + }; + for (i = _j = 0, _len1 = temp.length; _j < _len1; i = ++_j) { + wrapper = temp[i]; + _fn(wrapper); + } + } else { + if ((0 <= (_ref = locator - first - 1) && _ref < buffer.length)) { + removeFromBuffer(locator - first - 1, locator - first); + next--; + } + } + for (i = _k = 0, _len2 = buffer.length; _k < _len2; i = ++_k) { + item = buffer[i]; + item.scope.$index = first + i; + } + return adjustBuffer(null, false); + }); + return eventListener.$on('insert.item', function(event, locator, item) { + var i, inserted, _i, _len, _ref; + inserted = []; + if (angular.isFunction(locator)) { + throw new Error('not implemented - Insert with locator function'); + } else { + if ((0 <= (_ref = locator - first - 1) && _ref < buffer.length)) { + inserted.push(insert(locator, item)); + next++; + } + } + for (i = _i = 0, _len = buffer.length; _i < _len; i = ++_i) { + item = buffer[i]; + item.scope.$index = first + i; + } + return adjustBuffer(null, false, inserted); + }); + }; + } + }; + } +]); + +/* +//# sourceURL=src/scripts/ui-scroll.js +*/ +