Last active
December 21, 2018 14:46
-
-
Save caramelopardalis/4991df1f29761668a357dbc2d466dea5 to your computer and use it in GitHub Desktop.
Browser Report Memo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ページの高さを超えている間 while して | |
| 分割したオリジナル要素にはマーキング | |
| 最外のグループをコピー | |
| その中の祖先以外のグループは削除 | |
| 分割されたやつも削除 | |
| walker は、コンテンツの高さがページの高さを超えたとき、 | |
| 現在の要素をシャロ―コピーして split に渡す | |
| また、split の返り値を新しいページに追加する | |
| -> つまり、split の中で改ページしちゃいけないじゃん | |
| これは設計としてはよくなさそうに思える。 | |
| split の役割は超えた分をうまいことやってくれるやつ。 | |
| ということは、元通りに次のコンテンツを現在のページに | |
| 収められるように調整してくれないといけない。 | |
| というか、walker がページの高さを超えたかどうかを | |
| 気にする時点でよくないのでは | |
| split が改ページにかかわることを修復してくれて、 | |
| walker はただ単に次々と要素を追加していくだけで | |
| いいようでないといけない。 | |
| 名前がよくないな。split ではなくて、なんだろう? | |
| pageBreakIfOverflowed() とか? | |
| pageBreakIfOverflowed() の役割でかすぎない問題もある | |
| 分割は直近のグループ内すべての .br-grid-data? | |
| trimedCount と original は、 | |
| data-* に持たせないとダメでは? | |
| height が高い順に削っていかないといけない | |
| 超えてたら、まず直近のグループをオリジナルから取得し、 | |
| その中の要素すべてに data-br-id を追加 | |
| そのあとそれらをマルっとディープコピーする | |
| さらに、その中から .br-grid-data をすべて取得し、 | |
| 元々のテキストをそれぞれの data-br-original-text に設定 | |
| height が高いやつから textContent を削っていく。 | |
| このとき、削った要素には .br-splited を設定する | |
| もし、すべての textContent.length が 0 になったら | |
| その直近のグループは次のページへ移す。 | |
| ただし、次のページでも収まらない可能性があるので、 | |
| ここではループを抜けない | |
| 次のページへ移すときは、最外のグループごとコピーする必要がある | |
| 現在のページに収まるようになったら、 | |
| オリジナル要素の最外グループをコピーし、 | |
| その中の祖先以外のグループを削除 | |
| 直近のグループと同じ id を持つやつは、 | |
| ((global) => { | |
| const main = () => { | |
| pagerize() | |
| complete() | |
| } | |
| const pagerize = () => { | |
| const contentContainer = document.getElementsByClassName('br-content')[0] | |
| const pagesContainer = document.createElement('div') | |
| pagesContainer.classList.add('br-pages-container') | |
| document.body.appendChild(pagesContainer) | |
| let page = new Page() | |
| pagesContainer.appendChild(page.container) | |
| const pageBreakIfOverflowed = (clonedCurrentElement, currentElement) => { | |
| if (page.getContentHeight() <= page.getHeight()) { | |
| return | |
| } | |
| if (!clonedCurrentElement.classList.contains('br-grid-data')) { | |
| clonedCurrentElement.parentElement.removeChild(clonedCurrentElement) | |
| page = new Page() | |
| pagesContainer.appendChild(page.container) | |
| page.appendChild(clonedCurrentElement) | |
| return | |
| } | |
| while (page.getHeight() < page.getContentHeight()) { | |
| const nearestGroup = currentElement.closest('.br-group') | |
| const allElementInNearestGroup = nearestGroup.querySelectorAll('*') | |
| Array.prototype.slice.call(allElementInNearestGroup).push(nearestGroup) | |
| for (const elementInNearestGroup of allElementInNearestGroup) { | |
| if (!elementInNearestGroup.hasAttribute('data-br-id')) { | |
| elementInNearestGroup.setAttribute('data-br-id', uuid()) | |
| } | |
| } | |
| const clonedNearestGroup = nearestGroup.cloneNode(true) | |
| const clonedDataInNearestGroup = clonedNearestGroup.querySelectorAll('.br-grid-data') | |
| for (const clonedDatumInNearestGroup of clonedDataInNearestGroup) { | |
| if (!clonedDatumInNearestGroup.hasAttribute('data-br-original-text')) { | |
| clonedDatumInNearestGroup.setAttribute('data-br-original-text', clonedDatumInNearestGroup.textContent) | |
| } | |
| } | |
| const insertedNearestGroup = page.querySelector('[data-br-id="' + clonedNearestGroup.getAttribute('data-br-id') + '"]') | |
| insertedNearestGroup.insertBefore(clonedNearestGroup) | |
| insertedNearestGroup.parentElement.removeChild(insertedNearestGroup) | |
| while (page.getHeight() < page.getContentHeight()) { | |
| let hasText = false | |
| let mostHighHeight = 0 | |
| let mostHighElement | |
| for (const clonedDatumInNearestGroup of clonedDataInNearestGroup) { | |
| if (0 < clonedDatumInNearestGroup.textContent.length) { | |
| hasText = true | |
| } | |
| const height = getLayout(clonedDatumInNearestGroup).height | |
| if (mostHighHeight < height) { | |
| mostHighHeight = height | |
| mostHighElement = clonedDatumInNearestGroup | |
| } | |
| } | |
| if (mostHighElement) { | |
| if (!mostHighElement.hasAttribute('br-removed-count')) { | |
| mostHighElement.setAttribute('br-removed-count', 0) | |
| } | |
| mostHighElement.setAttribute('br-removed-text-count', parseInt(mostHighElement.getAttribute('br-removed-count')) + 1) | |
| mostHighElement.textContent = mostHighElement.textContent.substring(0, mostHighElement.textContent.length - 1) | |
| } | |
| if (!hasText) { | |
| clonedNearestGroup.parentElement.removeChild(clonedNearestGroup) | |
| page = new Page() | |
| pagesContainer.appendChild(page.container) | |
| const ancestorGroups = [] | |
| const ancestorGroupsIds = [] | |
| let ancestorGroup = currentElement.closest('.br-group') | |
| while (ancestorGroup) { | |
| ancestorGroups.push(ancestorGroup) | |
| ancestorGroupsIds.push(ancestorGroup.getAttribute('data-br-id')) | |
| ancestorGroup = ancestorGroup.parentElement.closest('.br-group') | |
| } | |
| const clonedFarthestGroup = ancestorGroups[ancestorGroups.length - 1].cloneNode(true) | |
| const groupedGroups = clonedFarthestGroup.querySelectorAll(':scope .br-group') | |
| for (const groupedGroup of groupedGroups) { | |
| if (!ancestorGroupsIds.includes(groupedGroup.getAttribute('data-br-id'))) { | |
| groupedGroup.parentElement.removeChild(groupedGroup) | |
| } | |
| } | |
| page.container.appendChild(clonedFarthestGroup) | |
| } | |
| } | |
| } | |
| } | |
| walkDescendant(contentContainer, (currentElement) => { | |
| if (!currentElement.hasAttribute('data-br-id')) { | |
| currentElement.setAttribute('data-br-id', uuid()) | |
| } | |
| const parent = page.container.querySelector('[data-br-id="' + currentElement.parentElement.getAttribute('data-br-id') + '"]') | |
| const clonedCurrentElement = currentElement.cloneNode(false) | |
| for (let i = 0; i < currentElement.childNodes.length; i++) { | |
| if (currentElement.childNodes[i].nodeType === Node.TEXT_NODE) { | |
| clonedCurrentElement.appendChild(currentElement.childNodes[i]) | |
| } | |
| } | |
| if (!parent) { | |
| if (!page.container.querySelector('[data-br-id="' + clonedCurrentElement.getAttribute('data-br-id') + '"]')) { | |
| page.appendChild(clonedCurrentElement) | |
| } | |
| } else { | |
| if (!parent.querySelector('[data-br-id="' + clonedCurrentElement.getAttribute('data-br-id') + '"]')) { | |
| parent.appendChild(clonedCurrentElement) | |
| } | |
| } | |
| pageBreakIfOverflowed(clonedCurrentElement, currentElement) | |
| }) | |
| } | |
| const complete = () => { | |
| const content = document.getElementsByClassName('br-content')[0] | |
| content.parentElement.removeChild(content) | |
| } | |
| const walkDescendant = (root, elementHandler) => { | |
| let currentElement = root | |
| let processCount = 0 | |
| const walk = () => { | |
| if (currentElement !== root) { | |
| processCurrentElement() | |
| } | |
| if (0 < currentElement.children.length) { | |
| currentElement = currentElement.children[0] | |
| } else if (currentElement.nextElementSibling) { | |
| currentElement = currentElement.nextElementSibling | |
| } else { | |
| let element = currentElement | |
| while (element.parentElement) { | |
| if (element.parentElement === root) { | |
| return; | |
| } | |
| if (element.parentElement.nextElementSibling) { | |
| break | |
| } | |
| element = element.parentElement | |
| } | |
| currentElement = element.parentElement.nextElementSibling | |
| } | |
| if (1 === processCount) { | |
| processCount = 0 | |
| setTimeout(walk, 0) | |
| } else { | |
| walk() | |
| } | |
| } | |
| const processCurrentElement = () => { | |
| ++processCount | |
| elementHandler(currentElement) | |
| } | |
| walk() | |
| } | |
| const getLayout = (element) => { | |
| return element.getBoundingClientRect() | |
| } | |
| const uuid = () => { | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | |
| var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8) | |
| return v.toString(16) | |
| }) | |
| } | |
| const loadScripts = (urls, callback) => { | |
| if (urls.length) { | |
| loadScript(urls[0], () => { | |
| urls = urls.slice(1) | |
| loadScripts(urls, callback) | |
| }) | |
| } else { | |
| callback() | |
| } | |
| } | |
| const loadScript = (url, callback) => { | |
| const script = document.createElement('script') | |
| script.type = 'text/javascript' | |
| script.async = false | |
| script.src = url | |
| if (script.readyState) { | |
| script.onreadystatechange = () => { | |
| if (script.readyState === 'loaded' || script.readyState === 'complete') { | |
| script.onreadystatechange = null | |
| callback() | |
| } | |
| } | |
| } else { | |
| script.onload = () => { | |
| callback() | |
| } | |
| } | |
| document.getElementsByTagName('body')[0].appendChild(script) | |
| } | |
| class Waiter { | |
| constructor(callback) { | |
| this.callback = callback | |
| this.counter = 0 | |
| } | |
| wait(func) { | |
| --this.counter | |
| func() | |
| } | |
| ok() { | |
| setTimeout(() => { | |
| this.counter++ | |
| if (this.counter === 0) { | |
| this.callback() | |
| } | |
| }, 0) | |
| } | |
| } | |
| class Page { | |
| constructor() { | |
| this.container = this.createContainer() | |
| this.containerInner = this.createContainerInner() | |
| this.container.appendChild(this.containerInner) | |
| this.contentOutline = this.createContentOutline() | |
| this.containerInner.appendChild(this.contentOutline) | |
| this.contentOutlineInner = this.createContentOutlineInner() | |
| this.contentOutline.appendChild(this.contentOutlineInner) | |
| } | |
| appendChild(element) { | |
| this.contentOutlineInner.appendChild(element) | |
| } | |
| createContainer() { | |
| const element = document.createElement('div') | |
| element.className = 'br-page' | |
| return element | |
| } | |
| createContainerInner() { | |
| const element = document.createElement('div') | |
| element.className = 'br-page-inner' | |
| return element | |
| } | |
| createContentOutline() { | |
| const element = document.createElement('div') | |
| element.className = 'br-content-outline' | |
| return element | |
| } | |
| createContentOutlineInner() { | |
| const element = document.createElement('div') | |
| element.className = 'br-content-outline-inner' | |
| return element | |
| } | |
| getHeight() { | |
| return getLayout(this.containerInner).height | |
| } | |
| getContentHeight() { | |
| return getLayout(this.contentOutlineInner).height | |
| } | |
| } | |
| const waiter = new Waiter(main) | |
| waiter.wait(() => { | |
| loadScripts([ | |
| 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js' | |
| ], () => { | |
| WebFont.load({ | |
| google: { | |
| families: [ | |
| 'Noto Sans JP' | |
| ] | |
| }, | |
| active() { | |
| waiter.ok() | |
| } | |
| }) | |
| }) | |
| }) | |
| waiter.wait(() => { | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', () => { | |
| waiter.ok() | |
| }) | |
| } else { | |
| setTimeout(() => { | |
| waiter.ok() | |
| }, 0) | |
| } | |
| }) | |
| })(this) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment