Skip to content

issue #47 resolved #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 61 additions & 40 deletions src/DocumentEditor/imports/page-transition-mgmt.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function find_sub_child_sibling_node (container, s_tag){
* @param {function(HTMLElement):boolean?} do_not_break Optional function that receives the current child element and should return true if the child should not be split over two pages but rather be moved directly to the next page
* @param {boolean?} not_first_child Should be unset. Used internally to let at least one child in the page
*/
function move_children_forward_recursively (child, child_sibling, stop_condition, do_not_break, not_first_child) {
function move_children_forward_recursively(child, child_sibling, stop_condition, do_not_break, not_first_child) {

// if the child still has nodes and the current page still overflows
while(child.childNodes.length && !stop_condition()){
Expand All @@ -38,26 +38,44 @@ function move_children_forward_recursively (child, child_sibling, stop_condition

// if it is a text node, move its content to next page word(/space) by word
if(sub_child.nodeType == Node.TEXT_NODE){
const sub_child_hashes = sub_child.textContent.match(/(\s|\S+)/g);
const sub_child_continuation = document.createTextNode('');
child_sibling.prepend(sub_child_continuation);
const l = sub_child_hashes ? sub_child_hashes.length : 0;
for(let i = 0; i < l; i++) {
if(i == l - 1 && !not_first_child) return; // never remove the first word of the page
sub_child.textContent = sub_child_hashes.slice(0, l - i - 1).join('');
sub_child_continuation.textContent = sub_child_hashes.slice(l - i - 1, l).join('');
if(stop_condition()) return;
const sub_child_text = sub_child.textContent;

if (sub_child_text.length > 0) {
let sub_child_hashes = sub_child_text.match(/(\s|\S+)/g);

// Handle long continuous words
if (!sub_child_hashes || sub_child_hashes.length === 1) {
console.log('Handling long continuous word');
const long_word = sub_child_text;

// Insert space before the last character so it's treated as normal text
const long_word_modified = long_word.slice(0, -1) + ' ' + long_word.slice(-1);

// Move the modified word to the next page in chunks
sub_child.textContent = long_word_modified;
sub_child_hashes = long_word_modified.match(/(\s|\S+)/g);
}

// Proceed with normal text handling
const sub_child_continuation = document.createTextNode('');
child_sibling.prepend(sub_child_continuation);
const l = sub_child_hashes ? sub_child_hashes.length : 0;

for (let i = 0; i < l; i++) {
if (i == l - 1 && !not_first_child) return;

// Move content from current page to the next
sub_child.textContent = sub_child_hashes.slice(0, l - i - 1).join('');
sub_child_continuation.textContent = sub_child_hashes.slice(l - i - 1).join('');

// Check stop condition and return if met
if (stop_condition()) return;
}
}
}

// we simply move it to the next page if it is either:
// - a node with no content (e.g. <img>)
// - a header title (e.g. <h1>)
// - a table row (e.g. <tr>)
// - any element on whose user-custom `do_not_break` function returns true
else if(!sub_child.childNodes.length || sub_child.tagName.match(/h\d/i) || sub_child.tagName.match(/tr/i) || (typeof do_not_break === "function" && do_not_break(sub_child))) {
// just prevent moving the last child of the page
if(!not_first_child){
// Handle elements that can be moved without breaking
else if (!sub_child.childNodes.length || sub_child.tagName.match(/h\d|tr/i) || (typeof do_not_break === "function" && do_not_break(sub_child))) {
if (!not_first_child) {
console.log("Move-forward: first child reached with no stop condition. Aborting");
return;
}
Expand Down Expand Up @@ -85,12 +103,13 @@ function move_children_forward_recursively (child, child_sibling, stop_condition
sub_child_sibling.normalize(); // merge consecutive text nodes
}

// if sub_child was a container that was cloned and is now empty, we clean it
if(child.contains(sub_child)){
if(sub_child.childNodes.length == 0 || sub_child.innerHTML == "") child.removeChild(sub_child);
else if(!stop_condition()) {
// the only case when it can be non empty should be when stop_condition is now true
console.log("sub_child:", sub_child, "that is in child:", child);
// Clean up child if it's emptied during the process
if (child.contains(sub_child)) {
if(sub_child.childNodes.length == 0 || sub_child.innerHTML == "") {
child.removeChild(sub_child);
} else if (!stop_condition()) {
console.error("Document editor is trying to remove a non-empty sub-child:", sub_child, "in parent:", child);

throw Error("Document editor is trying to remove a non-empty sub-child. This "
+ "is a bug and should not happen. Please report a repeatable set of actions that "
+ "leaded to this error to https://github.com/motla/vue-document-editor/issues/new");
Expand All @@ -108,28 +127,30 @@ function move_children_forward_recursively (child, child_sibling, stop_condition
* @param {HTMLElement} next_page_html_div Next page element
* @param {function} stop_condition Check function that returns a boolean if content overflows
*/
function move_children_backwards_with_merging (page_html_div, next_page_html_div, stop_condition) {

function move_children_backwards_with_merging(page_html_div, next_page_html_div, stop_condition) {
// loop until content is overflowing
while(!stop_condition()){

while (!stop_condition()) {
// find first child of next page
const first_child = next_page_html_div.firstChild;

// Exit loop if there are no more children to process
if (!first_child) break;

// merge it at the end of the current page
var merge_recursively = (container, elt) => {
// check if child had been splitted (= has a sibling on previous page)
const elt_sibling = find_sub_child_sibling_node(container, elt.s_tag);
if(elt_sibling && elt.childNodes.length) {
// then dig for deeper children, in case of
merge_recursively(elt_sibling, elt.firstChild);
}
// else move the child inside the right container at current page
else {
container.append(elt);
container.normalize();
if (elt) {
// check if child had been split (= has a sibling on previous page)
const elt_sibling = find_sub_child_sibling_node(container, elt.s_tag);
if (elt_sibling && elt.childNodes.length) {
// then dig for deeper children, in case of
merge_recursively(elt_sibling, elt.firstChild);
} else {
// else move the child inside the right container at current page
container.append(elt);
container.normalize();
}
}
}
};
merge_recursively(page_html_div, first_child);
}
}
Expand Down