Dynamic bootstrap nav wrapping menu items - javascript

I have a Bootstrap 3.3.7 page with a navbar component along the top of the page. It all works perfectly when populated with static data, but when I'm trying to populate the menu with new drop down lists based on some ajax loads from the server the menu line wraps even though there is loads of horizontal space.
I assume it is setting some fixed width based on the initial menu, and then failing to cope with the dynamic widening. If I manually narrow the page the point the nav collapses, and then widen it again then the reflow catches up and it all ends up back on one line.
Is there any way to force the Bootstrap nav to reflow programatically?
The specific element I need to make wider is ".navbar-right", and if I hand code CSS to make it wider after the dynamic addition then this works, but I'd rather not hard-code arbitrary constants into the code given that the menus are not constant and the font may change.

Answering my own question (although would appreciate any better alternatives if anyone knows any) - this seems to work OK.
// Perform the dynamic update
var htmlOutput = $.render.mytemplate(params);
$("#mynavtemplate").replaceWith(htmlOutput);
// Measure the total width of the children of .navbar-right
var newWidth = 0;
$(".navbar-right").children().each(function(){ newWidth += $(this).width(); });
// Force .navbar-right to be at least as wide as the sum of children
$(".navbar-right").css("min-width", newWidth);

Related

Vertical Chat scrolling is not working in VueJs

I am using chat scrolling in VUE JS. I want to have message scroll at the bottom of the page at every time when new message come or page load. I am trying to have a page scroll code in a function which works little bit surprisingly.
var container = this.$el.querySelector(".messages");
container.scrollTop = container.scrollHeight;
It is working but it cannot fully scroll down to the full bottom. With this, scroll remains at some position between top and bottom. When i trigger this one more time then it takes scroll to the full bottom. I want to have scroll on the bottom on first click not on two clicks. Please help me.
Are you sure your 'container' is full-filled on body or root element?
your code looks just fine...
You may better check:
1) URL bar height issue (on mobile)
2) HTML hierarchy and its css
3) CSS box model and default css values of html.
But still probs are following, If I were you,
I'll add a MAGIC PIXEL NUMBER (which bigger than the margin) like a boss!
Bigger (than its document height) value of scrollTop isn't throw any error. (but watch its cumulation..)

Display dynamic html content like an epub/ebook, without converting html to epub format?

I want to create a responsive, mobile optimized reading experience similar to an epub/ebook reader, like the Kindle app, or iBooks, using dynamic html as the source.
Imagine a long article or blog post that requires a lot of vertical scrolling to read, especially on a small mobile device. What I would like to do is break the long page into multiple full-screen sections, allowing the user to use left/right navigation arrows and/or the swipe gesture to "page" through the article.
There are many JS libraries available that can create a "slide show" or "carrousel" of pre-defined slides (using divs or other container elements). But I want the text and html content to dynamically re-flow to fit any device viewport and still be readable... just like an epub/ebook user interface, like the Kindle app or iBooks. So, for the same article, there would be many more "pages" on a phone than there would be on a tablet or desktop viewport, and those "pages" would need to be dynamically created/adjusted if/when the viewport size changes (like switching from portrait to landscape on a mobile device).
Here is an example of a javascript .epub reader: epub.js
... notice the responsive behavior. When you resize your viewport, all the text re-flows to fit the available space, increasing or decreasing the total number of "pages". The problem is that epub.js requires an .epub file as its source.
What I want is the same user interface and functionality for an html page.
I have searched and searched for some kind of library that can do this out of the box, but haven't been able to find anything.
I realize that I could use a conversion script to convert my html page into an .epub file, and then use epub.js to render that file within the browser, but that seems very round-about and clunky. It would be so much better to mimic or simulate the .epub reader user experience with html as the direct source, rendering/mimicking a client side responsive ebook user experience.
Does anyone know if something like this already exists, or how I could go about building it myself?
The crucial functionality is the dynamic/responsive text-reflow. When the viewport dimensions are reduced, the text/content needs to reflow to the next "page" to avoid any need for vertical scrolling. I don't know how to do this efficiently. If I were to code it myself, I might use something like the jQuery Columnize plugin, setting all columns to width: 100vw; height: 100vh, so that each column is like a "page", and then figuring out how to create a swipe UI between those "pages".
Any help is much appreciated!
This becomes very difficult if the html page is complex, eg with precisely positioned elements or images. However if (as in the epub.js example) the content consists only of headings and paragraphs, it is achievable.
The basic idea is to progressively add content until just before the page overflows. By keeping track of where we start and stop adding content, clicking to the next page is a case of changing the page start to the previous page end (or vice versa if you're going back).
Process for reshaping content into pages
Let's assume you have all your content in one long string. Begin by splitting all the content into an array of words and tags. It's not as easy as splitting by whitespace as whitespace between < and > should be ignored (you want to keep classnames etc within each tag). Also tags should be separated as well, even if there is no whitespace between the tag and a word.
Next you need a function that checks if an element's contents overflow the element. This question has a copy-paste solution.
You need two variables, pageStart and pageEnd, to keep track of what indexes in the array are the beginning and end of the current page.
Beginning at the index in pageStart you add elements from the array as content to the page, checking after each add whether or not the contents overflow. When they do overflow you take the index you're up to, minus 1, as the index for pageEnd.
Keeping tags across page breaks
Now if all's ticketyboo then this should fill the page pretty well. When you want to go to the next page set your new pageStart as pageEnd + 1 and repeat the process. However there are some issues that you may want to fix.
Firstly, what happens if the page overflows in the middle of a paragraph? Strictly speaking the closing tag, </p>, is not required in HTML, so we don't need to worry about it. But what about the start of the next page? It will be missing an opening tag and that is a major problem. So we have make sure we check if the page's content begins with a tag, and if it doesn't then we get the closest opening tag prior to the current pageStart (just step back along the array from pageStart) and add it in before the rest of the content.
Secondly, as shown in the example, if a paragraph continues onto the next page, the last line of the current page is still justified. You need to check if pageEnd is in the middle of a paragraph and if so add syle="text-align-last:justify;" to the opening tag of that paragraph.
Example implementation
A pen showing all this in action is at https://codepen.io/anon/pen/ZMJMZZ
The HTML page contains all content in one long element. The content is taken directly from the container #page and reformed into pages, depending on the size of #page. I have't implemented justifying the last line if a page break occurs within a paragraph. Resize the #page element in the css and see how the content resizes itself - note that since the page size is fixed you'll have to use click forward and back to trigger a recalculation. Once you bind the page size to the window size, recalculating pages on the fly simply involves adding a resize event listener to the window that calls fillPage.
No doubt there are numerous bugs, indeed it will sometimes display things incorrectly (eg skipping or repeating words at the beginning or end of a page), but this should give you an idea of where to start.
Take a look at this repository on GitHub. Otherwise, you can create a one-page website with many sections, each one as high as the viewport, by using only CSS (demo):
.section { height: 100vh; }
or by using JavaScript, adding an anchor to each section to navigate between them, and applying a responsive unit (my demo) for the text of each section, to adapt it on resize... Something like this:
var curr_el_index = 0;
var els_length = $(".container").length;
$(".next_section").on("click", function(e) {
curr_el_index++;
if (curr_el_index >= els_length) {
curr_el_index = 0;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
$(".previous_section").on("click", function(e) {
curr_el_index--;
if (curr_el_index < 0) {
curr_el_index = els_length - 1;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
* {
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body {
background-color: #1a1a1a;
}
section {
height: 100vh;
background-color: #eee;
border: 2px solid red;
font-size: 6vw;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">Section 1 Previous Next</section>
<section class="container">Section 2 Previous Next</section>
<section class="container">Section 3 Previous Next</section>
<section class="container">Section 4 Previous Next</section>
<section class="container">Section 5 Previous Next</section>
EDIT #1
An idea of algorithm, that come from a my codepen, that uses the same jQuery plugin:
Create your reader layout, copying the whole text in it
Use this jQuery plugin to check the text inside the viewport (demo)
Count the number of characters/WORDS with "Onscreen" label in the
viewport (a references)
Split the whole text in a list containing as many characters/WORDS as
there are in the "Onscreen" label
Create a section for each element of the obtained list, filling each
section with the relative text; the number of elements of the list
gives you the number of pages (sections) of the whole text. You may
navigate between sections like above
On resize event, redo [2-5] algorithm steps
Cheers
The idea is to have a div that will contain the whole text (let's call this div #epub_container). Then, you will have a div with the same size of the page viewport (let's call it #displayer) and it will contain #epub_container.
#displayer will have css overflow:hidden. So when the site loads, it will only show the first page, because the rest of the #epub_container will be hidden.
Then you need a page navigator to increment/decrement the page number. When the page number changes, we will move the top offset of the #epub_container based on that.
This is the jQuery function:
function move_to_page() {
var height = window.innerHeight;
var width = window.innerWidth;
var $displayer = $('#displayer');
var offset = $displayer.offset();
$displayer.height(height - offset.top - 5);
var $epub = $('#epub_container');
var offset_top = offset.top - $displayer.height() * m_page;
$epub.offset({top: offset_top, left: offset.left});
}
JSFiddle
EDIT: call move_to_page() after the text reflow in order to recompute the pages.
I created a plugin that handles this perfectly. It has features like dark mode, font changing, line height adjustment, select chapter in a side nav menu, save and restore scrolling/reading position. You can find it for free on git hub at https://github.com/E-TechDev/Html-Book-Reader
Screenshots
Light Mode Dark Mode Side Nav Menu Change Font Adjust Paragraph
You can try CSS scroll snap points on text with columns
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points
Somehow make the columns as wide as the viewport, and allow horizontal snapped scrolling.
Update
I mean to try to do the text flowing entirely using css. Pen:
https://codepen.io/ericc3141/pen/RYZEpr
body {
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
}
#columns-test {
height: 80vh;
columns: 90vw auto;
}
All you need is to insert a page break at the right places when you load the page. You can take the cue from here:
Dynamic Page-Break - Jquery
Here you can set the page height to your viewport height. You can handle the rest with javascript and css.

Document height determined incorrectly - can't see all the content

I am building a wordpress template, and I use a little Javascript to make the 'content' element fill the page from top to bottom. The goal is to cover the background image, so the 'content' doesn't look cut above the edge on larger screens. The code is:
$(document).ready(function() {
var h = Math.max($(window).height()+50, $("#content").height());
$("#content").height(h);
});
$(window).resize(function() {
var h = Math.max($(window).height()+50, $("#content").height());
$("#content").height(h);
});
My layout is: fixed sidebar on the left, then content with auto-width and two floated columns inside. It generally works, however on pages where I have a nivo-slider in one of the columns, the document height is determined incorrectly. When the screen size is small, the other column lands underneath (#media statement) and I can't scroll the screen to see that column.
See example page here: http://figtreephotodesign.com/kidsandfamilies/about/ - and set your browser window below 860px-wide to see the problem.
On another page: http://figtreephotodesign.com/kidsandfamilies/contact/ - it works (there is no nivo-slider).
Is it the nivo-slider's css messing up?

Position an element at the bottom of a floating div with unknown height

I am currently trying to position an element in a way that it always is at the bottom of it's parent. What's special here is that none of the heights or widths are known. I'd like to do this without tables, if at all possible (my superior is against using those. In a very religious way).
I tried the approach of using position:relative on the parent and position:absolute; bottom:0; on the box I want to have at the bottom. This, however, causes the box to overlap with the other content of the parent div since absolute positioning causes the parent to ignore the height of the positioned element. Some JavaScript is used to align the heights of the floating divs to each other. But disabled JavaScript should not completely break the layout (as in: cause content to overlap or break the "flow" of the page).
Here's the fiddle with the exact structure of my markup: http://jsfiddle.net/vbeC2/27/
I did read the "float: bottom" question on SO, but none of the answers really adressed my problem, hence the new question.
It's not the cleanest solution, but since you were already using the maxHeight bit to calculate the sizes, I just added a second each loop to check the max-height of the bottom section, and added it, so that the relative, absolute positioning would work.
http://jsfiddle.net/robsterlini/svcGB/ or http://codepen.io/robsterlini/pen/BcDyt
EDIT When you resize your browser it won't work, but you could just add a resize event that recalculated it, and you'd need to think about creating some javascript-less fallbacks, either using modernizr, or just some simple
Please find the working demo here: JS Enabled
Modified the jquery logic to calculate the height of the maximum height of the container as shown below:
$(document).ready(function(){
//Set the height of the columns to the highest value of all columns
var maxHeight = 0;
$(".same-height").each(function(){
var k = $(this).children('.headline').innerHeight() + $(this).children('.description').innerHeight()+$(this).children('.bottom').innerHeight();
maxHeight = Math.max(maxHeight,k);
});
$(".same-height").css({"height" : maxHeight});
});
If JavaScript is disabled then you should apply different styles as shown in demo here:
JS Disabled
Here is something similar to what you want to atchive but the demo is centering the
http://css-tricks.com/centering-in-the-unknown/
You should use the same trick : using css ::after/::before pseudo classes to set your footer content in your parent div

jQuery offset, position element under another, where the right borders touch of the aligned elements

Ok, the subject is not super specific to the overall need I am looking to address. So I have this function that is called on a given element, which is a hidden submenu next to a triggering element. The way the page renders, and to keep the styling optimized I can't just style the position in via css. So I need javascript/jquerys help.
With that I have come up with a function that I can reuse as needed, and works fine all around. However my key problem is, that I have a couple cases where the submenu will overlap the edge of the <section> element it resides in. Which that elements overflow is set to hidden, that and its also about 30 pixels from the bottom of the page anyway. All in all the submenu element gets hidden a bit by either falling completely out of the pages view half way through the element, or it gets hidden by the section tags overflow state.
With that. In a case where this happens I am wanting to instead of have the element align to the bottom of the trigger element, have it align to the top instead so that way the menu in that case is above the trigger element and not below.
Problem is Im not sure how to compensate for that.
Here is the function I came up with to do what I need, now I just need some help in a sense catching when the menu element falls off the page so to speak, so I can adjust for it when it does.
function openSubOrgMenu(triggerID, elem)
{
orgSubOpenID = triggerID;
orgSubShowing = true;
elemOffset = elem.offset(); //trigger element
elemWidth = elem.width();
elemHeight = elem.height();
elemWrap = elem.siblings('.org_group_wrapper');//menu element
elemWrapWidth = elemWrap.width();
elemWrapHeight = elemWrap.height();
moveTop = elemHeight + elemOffset.top + 4;
moveLeft = elemOffset.left - (elemWrapWidth-elemWidth-15);
elemWrap.show().offset({top:moveTop, left:moveLeft});
}
Well here is a JS Fiddle, not necessarily showing a working logic of what I want, but demonstrating the desired effect when its an element that at the bottom of the page/section:
http://jsfiddle.net/4zwEr/

Categories

Resources