Skip to content

Instantly share code, notes, and snippets.

@caramelopardalis
Last active December 21, 2018 14:46
Show Gist options
  • Select an option

  • Save caramelopardalis/4991df1f29761668a357dbc2d466dea5 to your computer and use it in GitHub Desktop.

Select an option

Save caramelopardalis/4991df1f29761668a357dbc2d466dea5 to your computer and use it in GitHub Desktop.
Browser Report Memo
ページの高さを超えている間 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