From 4fd9b8f2b5a98bfcde57970b48fed2488a80f356 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 17 Sep 2021 21:53:37 +0300 Subject: add in master snapshot of epubjs --- lib/epub.js/src/managers/default/index.js | 1073 +++++++++++++++++++++++++++++ 1 file changed, 1073 insertions(+) create mode 100644 lib/epub.js/src/managers/default/index.js (limited to 'lib/epub.js/src/managers/default/index.js') diff --git a/lib/epub.js/src/managers/default/index.js b/lib/epub.js/src/managers/default/index.js new file mode 100644 index 0000000..b24a4f6 --- /dev/null +++ b/lib/epub.js/src/managers/default/index.js @@ -0,0 +1,1073 @@ +import EventEmitter from "event-emitter"; +import {extend, defer, windowBounds, isNumber} from "../../utils/core"; +import scrollType from "../../utils/scrolltype"; +import Mapping from "../../mapping"; +import Queue from "../../utils/queue"; +import Stage from "../helpers/stage"; +import Views from "../helpers/views"; +import { EVENTS } from "../../utils/constants"; + +class DefaultViewManager { + constructor(options) { + + this.name = "default"; + this.optsSettings = options.settings; + this.View = options.view; + this.request = options.request; + this.renditionQueue = options.queue; + this.q = new Queue(this); + + this.settings = extend(this.settings || {}, { + infinite: true, + hidden: false, + width: undefined, + height: undefined, + axis: undefined, + writingMode: undefined, + flow: "scrolled", + ignoreClass: "", + fullsize: undefined + }); + + extend(this.settings, options.settings || {}); + + this.viewSettings = { + ignoreClass: this.settings.ignoreClass, + axis: this.settings.axis, + flow: this.settings.flow, + layout: this.layout, + method: this.settings.method, // srcdoc, blobUrl, write + width: 0, + height: 0, + forceEvenPages: true + }; + + this.rendered = false; + + } + + render(element, size){ + let tag = element.tagName; + + if (typeof this.settings.fullsize === "undefined" && + tag && (tag.toLowerCase() == "body" || + tag.toLowerCase() == "html")) { + this.settings.fullsize = true; + } + + if (this.settings.fullsize) { + this.settings.overflow = "visible"; + this.overflow = this.settings.overflow; + } + + this.settings.size = size; + + this.settings.rtlScrollType = scrollType(); + + // Save the stage + this.stage = new Stage({ + width: size.width, + height: size.height, + overflow: this.overflow, + hidden: this.settings.hidden, + axis: this.settings.axis, + fullsize: this.settings.fullsize, + direction: this.settings.direction + }); + + this.stage.attachTo(element); + + // Get this stage container div + this.container = this.stage.getContainer(); + + // Views array methods + this.views = new Views(this.container); + + // Calculate Stage Size + this._bounds = this.bounds(); + this._stageSize = this.stage.size(); + + // Set the dimensions for views + this.viewSettings.width = this._stageSize.width; + this.viewSettings.height = this._stageSize.height; + + // Function to handle a resize event. + // Will only attach if width and height are both fixed. + this.stage.onResize(this.onResized.bind(this)); + + this.stage.onOrientationChange(this.onOrientationChange.bind(this)); + + // Add Event Listeners + this.addEventListeners(); + + // Add Layout method + // this.applyLayoutMethod(); + if (this.layout) { + this.updateLayout(); + } + + this.rendered = true; + + } + + addEventListeners(){ + var scroller; + + window.addEventListener("unload", function(e){ + this.destroy(); + }.bind(this)); + + if(!this.settings.fullsize) { + scroller = this.container; + } else { + scroller = window; + } + + this._onScroll = this.onScroll.bind(this); + scroller.addEventListener("scroll", this._onScroll); + } + + removeEventListeners(){ + var scroller; + + if(!this.settings.fullsize) { + scroller = this.container; + } else { + scroller = window; + } + + scroller.removeEventListener("scroll", this._onScroll); + this._onScroll = undefined; + } + + destroy(){ + clearTimeout(this.orientationTimeout); + clearTimeout(this.resizeTimeout); + clearTimeout(this.afterScrolled); + + this.clear(); + + this.removeEventListeners(); + + this.stage.destroy(); + + this.rendered = false; + + /* + + clearTimeout(this.trimTimeout); + if(this.settings.hidden) { + this.element.removeChild(this.wrapper); + } else { + this.element.removeChild(this.container); + } + */ + } + + onOrientationChange(e) { + let {orientation} = window; + + if(this.optsSettings.resizeOnOrientationChange) { + this.resize(); + } + + // Per ampproject: + // In IOS 10.3, the measured size of an element is incorrect if the + // element size depends on window size directly and the measurement + // happens in window.resize event. Adding a timeout for correct + // measurement. See https://github.com/ampproject/amphtml/issues/8479 + clearTimeout(this.orientationTimeout); + this.orientationTimeout = setTimeout(function(){ + this.orientationTimeout = undefined; + + if(this.optsSettings.resizeOnOrientationChange) { + this.resize(); + } + + this.emit(EVENTS.MANAGERS.ORIENTATION_CHANGE, orientation); + }.bind(this), 500); + + } + + onResized(e) { + this.resize(); + } + + resize(width, height, epubcfi){ + let stageSize = this.stage.size(width, height); + + // For Safari, wait for orientation to catch up + // if the window is a square + this.winBounds = windowBounds(); + if (this.orientationTimeout && + this.winBounds.width === this.winBounds.height) { + // reset the stage size for next resize + this._stageSize = undefined; + return; + } + + if (this._stageSize && + this._stageSize.width === stageSize.width && + this._stageSize.height === stageSize.height ) { + // Size is the same, no need to resize + return; + } + + this._stageSize = stageSize; + + this._bounds = this.bounds(); + + // Clear current views + this.clear(); + + // Update for new views + this.viewSettings.width = this._stageSize.width; + this.viewSettings.height = this._stageSize.height; + + this.updateLayout(); + + this.emit(EVENTS.MANAGERS.RESIZED, { + width: this._stageSize.width, + height: this._stageSize.height + }, epubcfi); + } + + createView(section, forceRight) { + return new this.View(section, extend(this.viewSettings, { forceRight }) ); + } + + handleNextPrePaginated(forceRight, section, action) { + let next; + + if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) { + if (forceRight || section.index === 0) { + // First page (cover) should stand alone for pre-paginated books + return; + } + next = section.next(); + if (next && !next.properties.includes("page-spread-left")) { + return action.call(this, next); + } + } + } + + display(section, target){ + + var displaying = new defer(); + var displayed = displaying.promise; + + // Check if moving to target is needed + if (target === section.href || isNumber(target)) { + target = undefined; + } + + // Check to make sure the section we want isn't already shown + var visible = this.views.find(section); + + // View is already shown, just move to correct location in view + if(visible && section && this.layout.name !== "pre-paginated") { + let offset = visible.offset(); + + if (this.settings.direction === "ltr") { + this.scrollTo(offset.left, offset.top, true); + } else { + let width = visible.width(); + this.scrollTo(offset.left + width, offset.top, true); + } + + if(target) { + let offset = visible.locationOf(target); + let width = visible.width(); + this.moveTo(offset, width); + } + + displaying.resolve(); + return displayed; + } + + // Hide all current views + this.clear(); + + let forceRight = false; + if (this.layout.name === "pre-paginated" && this.layout.divisor === 2 && section.properties.includes("page-spread-right")) { + forceRight = true; + } + + this.add(section, forceRight) + .then(function(view){ + + // Move to correct place within the section, if needed + if(target) { + let offset = view.locationOf(target); + let width = view.width(); + this.moveTo(offset, width); + } + + }.bind(this), (err) => { + displaying.reject(err); + }) + .then(function(){ + return this.handleNextPrePaginated(forceRight, section, this.add); + }.bind(this)) + .then(function(){ + + this.views.show(); + + displaying.resolve(); + + }.bind(this)); + // .then(function(){ + // return this.hooks.display.trigger(view); + // }.bind(this)) + // .then(function(){ + // this.views.show(); + // }.bind(this)); + return displayed; + } + + afterDisplayed(view){ + this.emit(EVENTS.MANAGERS.ADDED, view); + } + + afterResized(view){ + this.emit(EVENTS.MANAGERS.RESIZE, view.section); + } + + moveTo(offset, width){ + var distX = 0, + distY = 0; + + if(!this.isPaginated) { + distY = offset.top; + } else { + distX = Math.floor(offset.left / this.layout.delta) * this.layout.delta; + + if (distX + this.layout.delta > this.container.scrollWidth) { + distX = this.container.scrollWidth - this.layout.delta; + } + + distY = Math.floor(offset.top / this.layout.delta) * this.layout.delta; + + if (distY + this.layout.delta > this.container.scrollHeight) { + distY = this.container.scrollHeight - this.layout.delta; + } + } + if(this.settings.direction === 'rtl'){ + /*** + the `floor` function above (L343) is on positive values, so we should add one `layout.delta` + to distX or use `Math.ceil` function, or multiply offset.left by -1 + before `Math.floor` + */ + distX = distX + this.layout.delta + distX = distX - width + } + this.scrollTo(distX, distY, true); + } + + add(section, forceRight){ + var view = this.createView(section, forceRight); + + this.views.append(view); + + // view.on(EVENTS.VIEWS.SHOWN, this.afterDisplayed.bind(this)); + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(EVENTS.VIEWS.AXIS, (axis) => { + this.updateAxis(axis); + }); + + view.on(EVENTS.VIEWS.WRITING_MODE, (mode) => { + this.updateWritingMode(mode); + }); + + return view.display(this.request); + } + + append(section, forceRight){ + var view = this.createView(section, forceRight); + this.views.append(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(EVENTS.VIEWS.AXIS, (axis) => { + this.updateAxis(axis); + }); + + view.on(EVENTS.VIEWS.WRITING_MODE, (mode) => { + this.updateWritingMode(mode); + }); + + return view.display(this.request); + } + + prepend(section, forceRight){ + var view = this.createView(section, forceRight); + + view.on(EVENTS.VIEWS.RESIZED, (bounds) => { + this.counter(bounds); + }); + + this.views.prepend(view); + + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + view.on(EVENTS.VIEWS.AXIS, (axis) => { + this.updateAxis(axis); + }); + + view.on(EVENTS.VIEWS.WRITING_MODE, (mode) => { + this.updateWritingMode(mode); + }); + + return view.display(this.request); + } + + counter(bounds){ + if(this.settings.axis === "vertical") { + this.scrollBy(0, bounds.heightDelta, true); + } else { + this.scrollBy(bounds.widthDelta, 0, true); + } + + } + + // resizeView(view) { + // + // if(this.settings.globalLayoutProperties.layout === "pre-paginated") { + // view.lock("both", this.bounds.width, this.bounds.height); + // } else { + // view.lock("width", this.bounds.width, this.bounds.height); + // } + // + // }; + + next(){ + var next; + var left; + + let dir = this.settings.direction; + + if(!this.views.length) return; + + if(this.isPaginated && this.settings.axis === "horizontal" && (!dir || dir === "ltr")) { + + this.scrollLeft = this.container.scrollLeft; + + left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta; + + if(left <= this.container.scrollWidth) { + this.scrollBy(this.layout.delta, 0, true); + } else { + next = this.views.last().section.next(); + } + } else if (this.isPaginated && this.settings.axis === "horizontal" && dir === "rtl") { + + this.scrollLeft = this.container.scrollLeft; + + if (this.settings.rtlScrollType === "default"){ + left = this.container.scrollLeft; + + if (left > 0) { + this.scrollBy(this.layout.delta, 0, true); + } else { + next = this.views.last().section.next(); + } + } else { + left = this.container.scrollLeft + ( this.layout.delta * -1 ); + + if (left > this.container.scrollWidth * -1){ + this.scrollBy(this.layout.delta, 0, true); + } else { + next = this.views.last().section.next(); + } + } + + } else if (this.isPaginated && this.settings.axis === "vertical") { + + this.scrollTop = this.container.scrollTop; + + let top = this.container.scrollTop + this.container.offsetHeight; + + if(top < this.container.scrollHeight) { + this.scrollBy(0, this.layout.height, true); + } else { + next = this.views.last().section.next(); + } + + } else { + next = this.views.last().section.next(); + } + + if(next) { + this.clear(); + // The new section may have a different writing-mode from the old section. Thus, we need to update layout. + this.updateLayout(); + + let forceRight = false; + if (this.layout.name === "pre-paginated" && this.layout.divisor === 2 && next.properties.includes("page-spread-right")) { + forceRight = true; + } + + return this.append(next, forceRight) + .then(function(){ + return this.handleNextPrePaginated(forceRight, next, this.append); + }.bind(this), (err) => { + return err; + }) + .then(function(){ + + // Reset position to start for scrolled-doc vertical-rl in default mode + if (!this.isPaginated && + this.settings.axis === "horizontal" && + this.settings.direction === "rtl" && + this.settings.rtlScrollType === "default") { + + this.scrollTo(this.container.scrollWidth, 0, true); + } + this.views.show(); + }.bind(this)); + } + + + } + + prev(){ + var prev; + var left; + let dir = this.settings.direction; + + if(!this.views.length) return; + + if(this.isPaginated && this.settings.axis === "horizontal" && (!dir || dir === "ltr")) { + + this.scrollLeft = this.container.scrollLeft; + + left = this.container.scrollLeft; + + if(left > 0) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + + } else if (this.isPaginated && this.settings.axis === "horizontal" && dir === "rtl") { + + this.scrollLeft = this.container.scrollLeft; + + if (this.settings.rtlScrollType === "default"){ + left = this.container.scrollLeft + this.container.offsetWidth; + + if (left < this.container.scrollWidth) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + } + else{ + left = this.container.scrollLeft; + + if (left < 0) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + } + + } else if (this.isPaginated && this.settings.axis === "vertical") { + + this.scrollTop = this.container.scrollTop; + + let top = this.container.scrollTop; + + if(top > 0) { + this.scrollBy(0, -(this.layout.height), true); + } else { + prev = this.views.first().section.prev(); + } + + } else { + + prev = this.views.first().section.prev(); + + } + + if(prev) { + this.clear(); + // The new section may have a different writing-mode from the old section. Thus, we need to update layout. + this.updateLayout(); + + let forceRight = false; + if (this.layout.name === "pre-paginated" && this.layout.divisor === 2 && typeof prev.prev() !== "object") { + forceRight = true; + } + + return this.prepend(prev, forceRight) + .then(function(){ + var left; + if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) { + left = prev.prev(); + if (left) { + return this.prepend(left); + } + } + }.bind(this), (err) => { + return err; + }) + .then(function(){ + if(this.isPaginated && this.settings.axis === "horizontal") { + if (this.settings.direction === "rtl") { + if (this.settings.rtlScrollType === "default"){ + this.scrollTo(0, 0, true); + } + else{ + this.scrollTo((this.container.scrollWidth * -1) + this.layout.delta, 0, true); + } + } else { + this.scrollTo(this.container.scrollWidth - this.layout.delta, 0, true); + } + } + this.views.show(); + }.bind(this)); + } + } + + current(){ + var visible = this.visible(); + if(visible.length){ + // Current is the last visible view + return visible[visible.length-1]; + } + return null; + } + + clear () { + + // this.q.clear(); + + if (this.views) { + this.views.hide(); + this.scrollTo(0,0, true); + this.views.clear(); + } + } + + currentLocation(){ + this.updateLayout(); + if (this.isPaginated && this.settings.axis === "horizontal") { + this.location = this.paginatedLocation(); + } else { + this.location = this.scrolledLocation(); + } + return this.location; + } + + scrolledLocation() { + let visible = this.visible(); + let container = this.container.getBoundingClientRect(); + let pageHeight = (container.height < window.innerHeight) ? container.height : window.innerHeight; + let pageWidth = (container.width < window.innerWidth) ? container.width : window.innerWidth; + let vertical = (this.settings.axis === "vertical"); + let rtl = (this.settings.direction === "rtl"); + + let offset = 0; + let used = 0; + + if(this.settings.fullsize) { + offset = vertical ? window.scrollY : window.scrollX; + } + + let sections = visible.map((view) => { + let {index, href} = view.section; + let position = view.position(); + let width = view.width(); + let height = view.height(); + + let startPos; + let endPos; + let stopPos; + let totalPages; + + if (vertical) { + startPos = offset + container.top - position.top + used; + endPos = startPos + pageHeight - used; + totalPages = this.layout.count(height, pageHeight).pages; + stopPos = pageHeight; + } else { + startPos = offset + container.left - position.left + used; + endPos = startPos + pageWidth - used; + totalPages = this.layout.count(width, pageWidth).pages; + stopPos = pageWidth; + } + + let currPage = Math.ceil(startPos / stopPos); + let pages = []; + let endPage = Math.ceil(endPos / stopPos); + + // Reverse page counts for horizontal rtl + if (this.settings.direction === "rtl" && !vertical) { + let tempStartPage = currPage; + currPage = totalPages - endPage; + endPage = totalPages - tempStartPage; + } + + pages = []; + for (var i = currPage; i <= endPage; i++) { + let pg = i + 1; + pages.push(pg); + } + + let mapping = this.mapping.page(view.contents, view.section.cfiBase, startPos, endPos); + + return { + index, + href, + pages, + totalPages, + mapping + }; + }); + + return sections; + } + + paginatedLocation(){ + let visible = this.visible(); + let container = this.container.getBoundingClientRect(); + + let left = 0; + let used = 0; + + if(this.settings.fullsize) { + left = window.scrollX; + } + + let sections = visible.map((view) => { + let {index, href} = view.section; + let offset; + let position = view.position(); + let width = view.width(); + + // Find mapping + let start; + let end; + let pageWidth; + + if (this.settings.direction === "rtl") { + offset = container.right - left; + pageWidth = Math.min(Math.abs(offset - position.left), this.layout.width) - used; + end = position.width - (position.right - offset) - used; + start = end - pageWidth; + } else { + offset = container.left + left; + pageWidth = Math.min(position.right - offset, this.layout.width) - used; + start = offset - position.left + used; + end = start + pageWidth; + } + + used += pageWidth; + + let mapping = this.mapping.page(view.contents, view.section.cfiBase, start, end); + + let totalPages = this.layout.count(width).pages; + let startPage = Math.floor(start / this.layout.pageWidth); + let pages = []; + let endPage = Math.floor(end / this.layout.pageWidth); + + // start page should not be negative + if (startPage < 0) { + startPage = 0; + endPage = endPage + 1; + } + + // Reverse page counts for rtl + if (this.settings.direction === "rtl") { + let tempStartPage = startPage; + startPage = totalPages - endPage; + endPage = totalPages - tempStartPage; + } + + + for (var i = startPage + 1; i <= endPage; i++) { + let pg = i; + pages.push(pg); + } + + return { + index, + href, + pages, + totalPages, + mapping + }; + }); + + return sections; + } + + isVisible(view, offsetPrev, offsetNext, _container){ + var position = view.position(); + var container = _container || this.bounds(); + + if(this.settings.axis === "horizontal" && + position.right > container.left - offsetPrev && + position.left < container.right + offsetNext) { + + return true; + + } else if(this.settings.axis === "vertical" && + position.bottom > container.top - offsetPrev && + position.top < container.bottom + offsetNext) { + + return true; + } + + return false; + + } + + visible(){ + var container = this.bounds(); + var views = this.views.displayed(); + var viewsLength = views.length; + var visible = []; + var isVisible; + var view; + + for (var i = 0; i < viewsLength; i++) { + view = views[i]; + isVisible = this.isVisible(view, 0, 0, container); + + if(isVisible === true) { + visible.push(view); + } + + } + return visible; + } + + scrollBy(x, y, silent){ + let dir = this.settings.direction === "rtl" ? -1 : 1; + + if(silent) { + this.ignore = true; + } + + if(!this.settings.fullsize) { + if(x) this.container.scrollLeft += x * dir; + if(y) this.container.scrollTop += y; + } else { + window.scrollBy(x * dir, y * dir); + } + this.scrolled = true; + } + + scrollTo(x, y, silent){ + if(silent) { + this.ignore = true; + } + + if(!this.settings.fullsize) { + this.container.scrollLeft = x; + this.container.scrollTop = y; + } else { + window.scrollTo(x,y); + } + this.scrolled = true; + } + + onScroll(){ + let scrollTop; + let scrollLeft; + + if(!this.settings.fullsize) { + scrollTop = this.container.scrollTop; + scrollLeft = this.container.scrollLeft; + } else { + scrollTop = window.scrollY; + scrollLeft = window.scrollX; + } + + this.scrollTop = scrollTop; + this.scrollLeft = scrollLeft; + + if(!this.ignore) { + this.emit(EVENTS.MANAGERS.SCROLL, { + top: scrollTop, + left: scrollLeft + }); + + clearTimeout(this.afterScrolled); + this.afterScrolled = setTimeout(function () { + this.emit(EVENTS.MANAGERS.SCROLLED, { + top: this.scrollTop, + left: this.scrollLeft + }); + }.bind(this), 20); + + + + } else { + this.ignore = false; + } + + } + + bounds() { + var bounds; + + bounds = this.stage.bounds(); + + return bounds; + } + + applyLayout(layout) { + + this.layout = layout; + this.updateLayout(); + if (this.views && this.views.length > 0 && this.layout.name === "pre-paginated") { + this.display(this.views.first().section); + } + // this.manager.layout(this.layout.format); + } + + updateLayout() { + + if (!this.stage) { + return; + } + + this._stageSize = this.stage.size(); + + if(!this.isPaginated) { + this.layout.calculate(this._stageSize.width, this._stageSize.height); + } else { + this.layout.calculate( + this._stageSize.width, + this._stageSize.height, + this.settings.gap + ); + + // Set the look ahead offset for what is visible + this.settings.offset = this.layout.delta / this.layout.divisor; + + // this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]); + + } + + // Set the dimensions for views + this.viewSettings.width = this.layout.width; + this.viewSettings.height = this.layout.height; + + this.setLayout(this.layout); + } + + setLayout(layout){ + + this.viewSettings.layout = layout; + + this.mapping = new Mapping(layout.props, this.settings.direction, this.settings.axis); + + if(this.views) { + + this.views.forEach(function(view){ + if (view) { + view.setLayout(layout); + } + }); + + } + + } + + updateWritingMode(mode) { + this.writingMode = mode; + } + + updateAxis(axis, forceUpdate){ + + if (!forceUpdate && axis === this.settings.axis) { + return; + } + + this.settings.axis = axis; + + this.stage && this.stage.axis(axis); + + this.viewSettings.axis = axis; + + if (this.mapping) { + this.mapping = new Mapping(this.layout.props, this.settings.direction, this.settings.axis); + } + + if (this.layout) { + if (axis === "vertical") { + this.layout.spread("none"); + } else { + this.layout.spread(this.layout.settings.spread); + } + } + } + + updateFlow(flow, defaultScrolledOverflow="auto"){ + let isPaginated = (flow === "paginated" || flow === "auto"); + + this.isPaginated = isPaginated; + + if (flow === "scrolled-doc" || + flow === "scrolled-continuous" || + flow === "scrolled") { + this.updateAxis("vertical"); + } else { + this.updateAxis("horizontal"); + } + + this.viewSettings.flow = flow; + + if (!this.settings.overflow) { + this.overflow = isPaginated ? "hidden" : defaultScrolledOverflow; + } else { + this.overflow = this.settings.overflow; + } + + this.stage && this.stage.overflow(this.overflow); + + this.updateLayout(); + + } + + getContents(){ + var contents = []; + if (!this.views) { + return contents; + } + this.views.forEach(function(view){ + const viewContents = view && view.contents; + if (viewContents) { + contents.push(viewContents); + } + }); + return contents; + } + + direction(dir="ltr") { + this.settings.direction = dir; + + this.stage && this.stage.direction(dir); + + this.viewSettings.direction = dir; + + this.updateLayout(); + } + + isRendered() { + return this.rendered; + } +} + +//-- Enable binding events to Manager +EventEmitter(DefaultViewManager.prototype); + +export default DefaultViewManager; -- cgit v1.2.3