refactor: rename RDReaderView -> RDEpubReaderView, update pod config and docs
- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: {{BACKGROUND}}; }
|
||||
body { position: relative; }
|
||||
#ss-fixed-root {
|
||||
position: absolute;
|
||||
top: {{INSET_TOP}}px;
|
||||
right: {{INSET_RIGHT}}px;
|
||||
bottom: {{INSET_BOTTOM}}px;
|
||||
left: {{INSET_LEFT}}px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ss-fixed-viewport {
|
||||
position: relative;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ss-fixed-page {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
transform-origin: top left;
|
||||
}
|
||||
.ss-fixed-page[data-page-type="single"],
|
||||
.ss-fixed-page[data-page-type="center"] {
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.ss-fixed-page[data-page-type="left"] {
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
transform-origin: top right;
|
||||
}
|
||||
.ss-fixed-page[data-page-type="right"] {
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
transform-origin: top left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="ss-fixed-root">{{PANES}}</div>
|
||||
<script>
|
||||
(function() {
|
||||
var Fit = { AUTO: 'auto', PAGE: 'page', WIDTH: 'width' };
|
||||
var safeAreaInsets = { top: {{INSET_TOP}}, right: {{INSET_RIGHT}}, bottom: {{INSET_BOTTOM}}, left: {{INSET_LEFT}} };
|
||||
var viewportSize = { width: {{VIEWPORT_WIDTH}}, height: {{VIEWPORT_HEIGHT}} };
|
||||
var fit = '{{FIT_MODE}}';
|
||||
var pendingFrames = 0;
|
||||
var readySent = false;
|
||||
|
||||
function notifyReady() {
|
||||
if (readySent) { return; }
|
||||
readySent = true;
|
||||
try {
|
||||
window.webkit.messageHandlers.{{FIXED_LAYOUT_READY_MESSAGE}}.postMessage({ loaded: true });
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
function parsePageSizeFromViewportMetaTag(iframe) {
|
||||
try {
|
||||
var viewport = iframe.contentWindow.document.querySelector('meta[name="viewport"]');
|
||||
if (!viewport) { return null; }
|
||||
var regex = /(\w+) *= *([^\s,]+)/g;
|
||||
var properties = {};
|
||||
var match;
|
||||
while ((match = regex.exec(viewport.content))) {
|
||||
properties[match[1]] = match[2];
|
||||
}
|
||||
var width = Number.parseFloat(properties.width);
|
||||
var height = Number.parseFloat(properties.height);
|
||||
if (!width || !height) { return null; }
|
||||
return { width: width, height: height };
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parseCssPixelValue(value) {
|
||||
if (!value) { return 0; }
|
||||
var match = String(value).match(/([0-9]+(?:\.[0-9]+)?)px?/);
|
||||
return match ? Number.parseFloat(match[1]) : 0;
|
||||
}
|
||||
|
||||
function sizeFromElement(element) {
|
||||
if (!element) { return null; }
|
||||
var width = parseCssPixelValue(element.style && element.style.width);
|
||||
var height = parseCssPixelValue(element.style && element.style.height);
|
||||
if (!width || !height) {
|
||||
width = parseCssPixelValue(element.getAttribute && element.getAttribute('width'));
|
||||
height = parseCssPixelValue(element.getAttribute && element.getAttribute('height'));
|
||||
}
|
||||
if (!width || !height) {
|
||||
var rect = element.getBoundingClientRect ? element.getBoundingClientRect() : null;
|
||||
if (rect) {
|
||||
width = width || rect.width;
|
||||
height = height || rect.height;
|
||||
}
|
||||
}
|
||||
if (width > 1 && height > 1) {
|
||||
return { width: width, height: height };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parsePageSizeFromDocumentBox(iframe) {
|
||||
try {
|
||||
var doc = iframe.contentWindow.document;
|
||||
return sizeFromElement(doc.body) ||
|
||||
sizeFromElement(doc.documentElement) ||
|
||||
sizeFromElement(doc.querySelector('[id$="_hype_container"]')) ||
|
||||
sizeFromElement(doc.querySelector('iframe')) ||
|
||||
null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parsePageSizeFromNestedFrame(iframe) {
|
||||
try {
|
||||
var nestedFrame = iframe.contentWindow.document.querySelector('iframe');
|
||||
if (!nestedFrame || !nestedFrame.contentWindow || !nestedFrame.contentWindow.document) {
|
||||
return null;
|
||||
}
|
||||
return parsePageSizeFromViewportMetaTag(nestedFrame) ||
|
||||
parsePageSizeFromDocumentBox(nestedFrame) ||
|
||||
parsePageSizeFromEmbeddedImage(nestedFrame);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function parsePageSizeFromEmbeddedImage(iframe) {
|
||||
try {
|
||||
var img = iframe.contentWindow.document.querySelector('img');
|
||||
if (!img || !img.naturalWidth || !img.naturalHeight) { return null; }
|
||||
return { width: img.naturalWidth, height: img.naturalHeight };
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function pageViewportSize(iframe) {
|
||||
var viewport = iframe.closest('.ss-fixed-viewport');
|
||||
if (!viewport) { return viewportSize; }
|
||||
var width = Math.max(1, viewport.clientWidth);
|
||||
var height = Math.max(1, viewport.clientHeight);
|
||||
if (width <= 1 || height <= 1) {
|
||||
return viewportSize;
|
||||
}
|
||||
return {
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
}
|
||||
|
||||
function usesWidthFit(pageSize, localViewport) {
|
||||
if (fit === Fit.WIDTH) {
|
||||
return true;
|
||||
}
|
||||
if (fit !== Fit.AUTO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var widthRatio = localViewport.width / pageSize.width;
|
||||
var heightRatio = localViewport.height / pageSize.height;
|
||||
return widthRatio <= heightRatio;
|
||||
}
|
||||
|
||||
function layoutPage(iframe) {
|
||||
var pageSize = iframe.__ssPageSize;
|
||||
if (!pageSize) { return; }
|
||||
|
||||
var pageType = iframe.dataset.pageType || 'single';
|
||||
var localViewport = pageViewportSize(iframe);
|
||||
iframe.style.width = pageSize.width + 'px';
|
||||
iframe.style.height = pageSize.height + 'px';
|
||||
|
||||
var widthRatio = localViewport.width / pageSize.width;
|
||||
var heightRatio = localViewport.height / pageSize.height;
|
||||
var widthFit = usesWidthFit(pageSize, localViewport);
|
||||
var scale = widthFit ? widthRatio : Math.min(widthRatio, heightRatio);
|
||||
var scaledWidth = pageSize.width * scale;
|
||||
var scaledHeight = pageSize.height * scale;
|
||||
|
||||
var offsetX, offsetY;
|
||||
if (pageType === 'left') {
|
||||
offsetX = localViewport.width - scaledWidth;
|
||||
} else if (pageType === 'right') {
|
||||
offsetX = 0;
|
||||
} else {
|
||||
offsetX = (localViewport.width - scaledWidth) / 2;
|
||||
}
|
||||
|
||||
if (widthFit && scaledHeight > localViewport.height) {
|
||||
offsetY = safeAreaInsets.top;
|
||||
} else {
|
||||
offsetY = (localViewport.height - scaledHeight) / 2;
|
||||
offsetY += (safeAreaInsets.top - safeAreaInsets.bottom) / 2;
|
||||
}
|
||||
|
||||
iframe.style.left = offsetX + 'px';
|
||||
iframe.style.top = offsetY + 'px';
|
||||
iframe.style.transform = 'scale(' + scale + ')';
|
||||
}
|
||||
|
||||
function preparePage(iframe) {
|
||||
pendingFrames += 1;
|
||||
|
||||
function finalizeLoad() {
|
||||
pendingFrames = Math.max(0, pendingFrames - 1);
|
||||
if (pendingFrames === 0) {
|
||||
notifyReady();
|
||||
}
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
iframe.__ssPageSize =
|
||||
parsePageSizeFromViewportMetaTag(iframe) ||
|
||||
parsePageSizeFromDocumentBox(iframe) ||
|
||||
parsePageSizeFromNestedFrame(iframe) ||
|
||||
parsePageSizeFromEmbeddedImage(iframe) ||
|
||||
pageViewportSize(iframe);
|
||||
layoutPage(iframe);
|
||||
window.setTimeout(function() {
|
||||
layoutPage(iframe);
|
||||
}, 250);
|
||||
finalizeLoad();
|
||||
}
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
window.setTimeout(onLoad, 100);
|
||||
});
|
||||
|
||||
iframe.addEventListener('error', function() {
|
||||
iframe.__ssPageSize = pageViewportSize(iframe);
|
||||
layoutPage(iframe);
|
||||
finalizeLoad();
|
||||
});
|
||||
}
|
||||
|
||||
var pages = document.querySelectorAll('.ss-fixed-page');
|
||||
Array.prototype.forEach.call(pages, preparePage);
|
||||
if (pages.length === 0) {
|
||||
notifyReady();
|
||||
}
|
||||
window.addEventListener('resize', function() {
|
||||
Array.prototype.forEach.call(document.querySelectorAll('.ss-fixed-page'), layoutPage);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user