Programmatically scroll ng-repeat with overflow:hidden - css

I'm using the following markup (JADE) to build a pagination with AngularJS and Foundation.
ul.pagination
li.arrow: a «
li(ng-repeat="month in months | orderBy:'_id'" ng-class="month._id === shownMonth ? 'current' : ''")
a(ng-href="#/months/{{month._id}}") {{ month._id | monthid:'short' }}
li.arrow#right-arrow: a »
In the CSS, I've set overflow: hidden. This gets me this:
Perfect so far, but obviously this could get long.
How can I make this scroll when the user clicks on the little arrow symbols at the end?
I've tried doing stuff like $(...).animate({left: '-=20'}) but it simply gets ignored (I'm guessing because of the Foundation css). Any ideas?
UPDATE
I've got a semi-working solution, but it's ugly.
I have attached an ng-show condition to the repeated list items as such:
li(ng-repeat="month in months | orderBy:'_id'" ng-class="month._id === shownMonth ? 'current' : ''" ng-show="month._id >= min && month._id <= max")
and after loading my data I do
$timeout(function() {
var availableWidth = $('ul.pagination').width() - 2 * $('ul li.arrow').width();
var itemWidth = $('li:not(.arrow)').width();
var total = Math.floor(availableWidth / itemWidth);
$scope.min = $scope.shownMonth - Math.floor(total / 2);
$scope.max = $scope.shownMonth + Math.floor(total / 2);
});
Then I basically just need to adjust min and max in an ng-click handler for the arrow buttons. This works, more or less, but for some reason, availableWidth gets calculated to much, much smaller than the space that's actually available for it - it's off by about 600px! Why?

Animating the left position makes no sense. What you want to animate is the horizontal scroll position (element.scrollLeft).
Also, consider removing your arrows out of the list of months. They don't make sense semantically in that list, and they'll end up constraining you when you want to scroll just the months but leave the arrows in place.
Edited to add fiddle: http://jsfiddle.net/R9QcB/5/ I did this with jQuery for quickness, but scrollLeft is a native javascript property.
It's the CSS that's actually important here moreso than the javascript:
#pagination {
text-align: center;
}
.nav {
display: inline-block;
vertical-align: middle;
}
ul {
display: inline-block;
vertical-align: middle;
max-width: 75%;
overflow: hidden;
white-space: nowrap;
}
li {
display: inline-block;
list-style: none;
color: #fff;
background: #aaa;
padding: 0.25em 0.5em;
margin: 0 0.5em;
}
Basically, you need a containing element that you can update the scrollLeft position of. That containing element has an overflow: hidden on it so that its child elements sit in a series inside the container (which is a result of white-space: nowrap).

Related

Why Codemirror editor does NOT scroll horizontally with long line?

I've a code mirror version: 5.65.3 with Blazor. When I've a long line in the editor the horizontal scroll doesn't work, it rather uses the scroll of the page which mess out the whole page.
Like this:
I don't think that I changed any CSS in Codemirror.
Here is some related CSS lines:
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 750px;
color: black;
direction: ltr;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 50px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -50px; margin-right: -50px;
padding-bottom: 50px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
z-index: 0;
}
I'm calling the codemirror through this code: (the onchange is because I'm using Blazor for binding purposes )
window.editor= function (dontNetObjRef) {
editor = CodeMirror.fromTextArea(document.getElementById('myTextArea'), {
lineNumbers: true,
indentUnit: 4,
lineWrapping: true,
tabMode: "shift",
gutters: ["CodeMirror-lint-markers"]
});
//JavaScript function use the onchange event of CodeMirror to invoke the C# method and pass the value of the myTextArea .
editor.on("change", editor => {
dontNetObjRef.invokeMethodAsync("UpdateField", editor.getValue());
// console.log(editor.getValue());
});
Note: even if I used lineWrapping: true it moved to the second line and does the same issue with scroll.
Also, it works well when I set a fixed width like 1000px but I'd like to make it auto in case the screen size of the user changes.
Thanks to Jax-p for giving me some hints to fix the issue.
I've add width:70vw in .CodeMirror class and max-width:70vm in .CodeMirror-scroll
Another thing that was affecting the changes is that I was putting the textarea in inside a <div class=col-11> which was affecting the width in the CSS so I just removed that and everything is working.
While working on a project I've encountered the same issue - that is a problem with CSS.
I fixed it with that pretty simple flexbox solution:
<div class="root-wrapper"> <!-- Editor parent container -->
<div class="cm-editor ͼ1 ͼ2 ͼ4"> <!-- CodeMirror stuff (v6 in my case) -->
...
</div>
</div>
The corresponding styling:
.root-wrapper {
display: flex;
flex-direction: row;
.cm-editor {
width: 0;
flex-grow: 1;
}
}

Responsive CSS Type scaling based on longest word in a list

I'm getting familiar with vmin vh etc
but I need a mroe elegant solution to display a list of words say:
apple
banana
lemon
pineapple
so the list takes always the maximum width of thew viewport...based on the longest word in this case 'pineapple'
using just CSS is it possible?
If you want a list element to always take x width of a page while keeping the elements boundaries fluid as to expand around its content ( instead of a fixed width ) you could use a solution that combines an inline-block display with a vw unit on the font-size of the html element. This, however scales everything in the entire page accordingly.
( make full-screen and resize the page to see the list adapt )
// All javascript is necessary only for the button to demo list growth.
function addCnt(){
var pinapl = document.getElementById( 'pinapl' );
pinapl.innerHTML += 'e';
}
var cnt = document.getElementById( 'cnt' );
cnt.addEventListener( 'click', addCnt );
html,
body {
margin: 0;
height: 100%;
}
html {
font-family: sans-serif;
font-size: 6vw; /* setting vw value on HTML makes elements resize to viewport width */
}
body {
display: flex;
}
ol {
display: inline-block; /* making list element inline-block forces content to determine its width */
margin: auto;
background-color: #eee;
list-style-position: inside;
}
.cnt {
cursor: pointer;
padding: 10px;
background-color: #000;
color: #eee;
font-size: 16px;
position: absolute;
}
<ol>
<li>apple</li>
<li>banana</li>
<li>lemon</li>
<li id="pinapl">pineapple</li>
</ol>
<div id="cnt" class="cnt">
click to add content
</div>
No, in pure CSS you cannot tell "set the font-size so the longest word fits in viewport automatically". You'll need JavaScript, presumably FitText:
http://fittextjs.com/ / https://github.com/adactio/FitText.js

CSS calc() behaviour in CSS variables

I'm curious to the behaviour of using calc() in setting a CSS variable.
Example:
#test {
--halfWidth: calc(100% / 2);
}
Now, if the #test element, say a div, was 500px wide, I would like the --halfWidth variable to be set to 250px.
But, as far as I can tell the var(--halfWidth) code used elsewhere simply drops in the calc(100% / 2) string instead of 250px. Which means that I can't use the calculation of say element A and use it in element B later on, since it would simply set for example width: var(--halfWidth); as half the width of element B instead of half the width of element A, where the variable was defined.
I've scoured the web trying to find any documentation on the behaviour of this, but I have so far drawn a blank.
Ideally, setting a CSS variable using calc should be available in two variants:
One variant working just like this example, simply dropping in the string as-is, bar any in-string variable replacements.
A second variant where calc() would yield the result of the calculation instead of simply replacing the string.
How to achieve this? I'd rather leave the actual implementation to people suited to it, but one possibility would be an eval() kind of thing; like eval(calc(100% / 2)) would give the result 250px.
Anyway, if anyone have any real documentation on this behaviour or a solution to how to get the example above to yield the result instead, I'm all ears!
Edit: Just FYI, I have read the specs at https://drafts.csswg.org/css-variables/
This is kind of a tough question to answer cause the answer will not be:
Do it like this...then it will work
The problem you are facing is the normal behavior of CSS. It cascades the styles. If what you are trying to achieve would work it would get real messy after a short amount of time.
I mean how cool is it that you can define a variable like this
#test {
--halfWidth: calc(100% / 2);
}
where var(--halfWidth) should always be calc(100% / 2). Did you note that it will always be half the width of the parent element?
Imagine how strange it would be if a programmer in a few months reads your code and has box with a width of 1000px set with --halfWidth and now it is 250px wide ... I would think the internet is broken :) It should just be 500px wide.
To achieve what you want, you could/should define different vars defining the widths of the parent elements. And split it down to the children.
One approach to this is to dynamically add a line to the CSS Object Model (CSSOM) which explicitly declares the width of the .halfwidth class.
This width will then apply to all divs with the .halfwidth class.
In the example below, I have, additionally, made .element-a horizontally resizable, so that you can see more clearly that as you change the width of .element-a, the width of both .halfwidth divs changes proportionately, including the .halfwidth div which is a child of .element-b.
Working Example:
let myStylesheet = document.styleSheets[0];
const elementA = document.getElementsByClassName('element-a')[0];
let elementAWidth = window.getComputedStyle(elementA).getPropertyValue('width');
const calculateHalfWidth = (elementAWidth) => {
myStylesheet.insertRule('.halfWidth { width: ' + (parseInt(elementAWidth) / 2) + 'px; }', myStylesheet.cssRules.length);
}
calculateHalfWidth(elementAWidth);
// ================================================================================
// THE SCRIPT BELOW USES A ResizeObserver TO WATCH THE RESIZABLE .element-a DIV
// ================================================================================
const elementAObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.contentRect.width !== elementAWidth) {
calculateHalfWidth(entry.contentRect.width);
}
}
});
elementAObserver.observe(elementA);
body {
font-family: sans-serif;
}
div.element {
float: left;
width: 200px;
height: 100px;
margin: 12px 3px;
text-align: center;
border: 1px solid rgb(0, 0, 0);
}
div.element h2 {
font-size: 18px;
}
div.element-a {
resize: horizontal;
overflow: auto;
}
div.element-b {
width: 300px;
}
div.halfWidth {
height: 40px;
margin: 0 auto;
border: 1px dashed rgb(255, 0, 0);
}
div.halfWidth h2 {
font-size: 14px;
}
<div class="element element-a">
<h2>Element A</h2>
<div class="halfWidth">
<h2>halfWidth</h2>
</div>
</div>
<div class="element element-b">
<h2>Element B</h2>
<div class="halfWidth">
<h2>halfWidth</h2>
</div>
</div>

SASS: Can I get element count in one class?

I want to position divs next to each other spaced equally and reposition them if the window size is changed. For that I think I need SASS. One time there may be 14 divs, other 10 divs in one class and I want them to be spaced equally depending on the count and the screen size. Can I get element count in SASS for one class?
Or you can do that with pure css and flex property
.equalSpaces {
overflow: hidden;
display: flex;
}
.equalSpaces p {
padding: 5px;
margin: 0;
background-color: #000;
border: 1px solid #999;
}
.equalSpaces div {
display: inline-block;
flex: 1; /* to make all blocks equal */
}
An example: http://jsfiddle.net/LbxyLmpg/
edit: #cimmannon suggestion display: inline-block;
You just need to use jQuery for this. Not AJAX or SASS. The reason is, AJAX is server side and SASS is just precompiled CSS, nothing more. So, you need to make it this way:
$(document).ready(function(){
$(".equalSpaces").each(function(){
totalDivs = $(this).find("div").length;
$(this).find("div").width(100/totalDivs + "%");
});
});
Fiddle: http://jsfiddle.net/praveenscience/h72horvz/

Align a button to top

I am building a webapp in .net using some of the AJAX features; in this case it is TabContainer.
Below is a screenshot of the area I want to play with.
The menu on the left is the tabs of TabContainer. The right side is tab's content. I would like to have the "Update PCR" button to be right underneath "Disciplines Affected". The problem is that the left and right side are a part of ONE block, which is TabContainer.
Are there any suggestions to how would I format the CSS of the Button to align right underneath TabContainer's menu? I could add the button as a part of the menu but, then I would have to set the control to AutoPostback, which defeats its purpose in this case in the first place... Any suggestions would be appreciated!
EDIT:
Here is the existing CSS
.ajax_tabController .ajax__tab_tab
{
background-color: #3c6f91;
padding: 5px;
border: 1px solid #ffffff;
color:#ffffff;
border-left: 3px solid #5AB0DB;
}
.ajax_tabController .ajax__tab_hover .ajax__tab_tab
{
background-color:#5AB0DB;
text-decoration:none;
}
.ajax_tabController .ajax__tab_active .ajax__tab_tab
{
background-color:#5AB0DB;
text-decoration: underline;
}
Also, there is CSS that overrides some settings to make TabContainer Vertical instead of Horizontal. I know, that there is a property .UseVerticalStripPlacement but it messes up with the height of the control and throws a JavaScript error.
.ajax__tab_header
{
float: left;
}
.ajax__tab_body
{
margin-left: 160px;
}
.ajax__tab_outer
{
display: block !important;
}
.ajax__tab_tab
{
width: 210px;
height: auto !important;
}
You need to position the top of the button relative to the bottom of the tab elements. This can be done with jquery. See How to position one element relative to another with jQuery?
It's going to be a bit hit and miss, but try something along the lines of:
.updatePcrButton {
position: absolute;
top: 100px; /* These will be whatever the measurement is to */
left: 5px; /* be directly under the last element */
z-index: 99; /* Arbitrary amount to put it above any other elements */
}
This is pretty messy to be honest - it relies on your not changing the position of the control thereafter.
Perhaps a better way would be to add an extra tab to the TabContainer and handle any Tab clicks yourself.
-- Edit -- May be more useful --
Nikita, I had completely forgotten about this as it was in an old Classic ASP app of mine, but you could try these two JS functions that are probably more useful to you:
function curTop(obj){
rv = 0;
while(obj) {
rv += obj.offsetTop;
obj = obj.offsetParent;
}
return rv;
}
function curLeft(obj){
rv = 0;
while(obj) {
rv += obj.offsetLeft;
obj = obj.offsetParent;
}
return rv;
}
They pull the position from the specified object. If you add the height of the button that you want to position under then you may find this improves the location for you and prevents any funny business with CSS.
Kind regards,
Westie.

Resources