ui.position.left not working with css margin: 0 auto - javascript

I want to build a scrollable menu that should use margin: 0 auto;
Below is my codepen where it is working fine because I didn't use css margin: 0 auto (refer css panel .wrap class).
But this has two issues:
It is not scrolling end to end - Codepen url: codepen.io/VK009/pen/PRKmNP
While using margin: 0 auto; in .wrap and it's stops working properly because of ui.offset.left- Codepen url:- codepen.io/VK009/pen/yKobVP
How can I make the menu use margin: 0 auto and scroll end to end.

Add This CSS on this ID. Hope this will work.
#nav_main{
overflow-x:scroll;
}

Try to use ui.offset instead of ui.position...The idea is here to drag the element using the difference between the parent width and child width...
var parentPos = $('.samNan').offset();
var parentWidth = $('.samNan').outerWidth();
var childWidth = $('.wrap').outerWidth();
var diff = parentWidth - childWidth;
$(".wrap").draggable({
drag: function(event, ui) {
if (ui.offset.left <= parentPos.left && ui.offset.left >= diff + parentPos.left) {
ui.offset.left = parentPos.left;
} else {
return false;
}
},
scroll: false,
axis: "x"
});
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.samNan {
width: 400px;
position: relative;
margin: 0 auto;
overflow: hidden;
border: 1px solid;
}
.wrap {
background: #ccc;
white-space: nowrap;
display: inline-block;
padding: 20px;
}
#nav_main {
margin: 0;
padding: 0;
}
#nav_main li {
display: inline-block;
}
#nav_main li a {
margin: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
<div class="samNan">
<div class="wrap">
<ul id="nav_main">
<li class="">Menu 1</li>
<li class="">Menu 2</li>
<li class="">Menu 3</li>
<li class="">Menu 4</li>
<li class="">Menu 5</li>
<li class="">Menu 6</li>
<li class="">Menu 7</li>
<li class="">Menu 8</li>
<li class="">Menu 9</li>
<li class="">Menu 10</li>
<li class="">Menu 11</li>
<li class="">Menu 12</li>
<li class="">Menu 13</li>
<li class="">Menu 14</li>
<li class="">Menu 15</li>
</ul>
</div>
</div>

Related

Setting Floating UI shift on multiple elements

I want to use Floating UI to prevent dropdown menus from going off the left/right edge of the screen. The example code is as follows:
HTML:
<ul class="menu">
<li class="menu__item">
Item 1
<ul class="submenu">
<li>Item 1.1</li>
<li>Item 1.2</li>
<li>Item 1.3</li>
<li>Item 1.4</li>
<li>Item 1.5</li>
</ul>
</li>
<li class="menu__item">
Item 2
<ul class="submenu">
<li>Item 2.1</li>
<li>Item 2.2</li>
<li>Item 2.3</li>
<li>Item 2.4</li>
<li>Item 2.5</li>
</ul>
</li>
<li class="menu__item">
Item 3
<ul class="submenu">
<li>Item 3.1</li>
<li>Item 3.2</li>
<li>Item 3.3</li>
<li>Item 3.4</li>
<li>Item 3.5</li>
</ul>
</li>
<li class="menu__item">
Item 4
<ul class="submenu">
<li>Item 4.1</li>
<li>Item 4.2</li>
<li>Item 4.3</li>
<li>Item 4.4</li>
<li>Item 4.5</li>
</ul>
</li>
<li class="menu__item">
Item 5
<ul class="submenu">
<li>Item 5.1</li>
<li>Item 5.2</li>
<li>Item 5.3</li>
<li>Item 5.4</li>
<li>Item 5.5</li>
</ul>
</li>
</ul>
CSS:
* {
margin: 0;
padding: 0;
}
ul {
list-style-type: none;
display: flex;
}
a {
color: inherit;
text-decoration: none;
}
.menu {
display: flex;
gap: 5px;
justify-content: space-around;
color: white;
}
.menu > li {
position: relative;
background: blue;
padding: 0 30px;
height: 40px;
}
.submenu {
display: none;
position: absolute;
left: 50%;
top: 40px;
transform: translateX(-50%);
background: red;
}
.menu > li:hover .submenu {
display: flex;
}
.submenu li {
padding: 10px 20px;
}
.submenu a {
white-space: nowrap;
}
JS:
import { autoUpdate, computePosition, shift } from "https://cdn.skypack.dev/#floating-ui/dom#1.2.0";
const menuItems = document.querySelectorAll('.menu__item');
menuItems.forEach((item) => {
const reference = item.querySelector('.menu__link');
const floating = item.querySelector('.submenu');
computePosition(reference, floating, {
placement: "bottom",
middleware: [shift()]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`
});
});
});
There's a CodePen here.
However, I'm struggling to understand the documentation and the implementation I have doesn't seem to work. The red dropdowns should be center-aligned under the blue items where possible but Floating UI should adjust the positioning horizontally so that the first dropdown should have its left edge aligned to the left of the screen and the last dropdown should have its right edge aligned to the right of the screen.
Could anyone advise how to get this working and ensure that it maintains the correct positioning even after window resizing?
Many thanks.

Javascript dropdown for touch devices

I am trying to make the submenu open and close by class toggle.
WHy is the class on not toggled on click, to hide the submenu?
var u = document.querySelector('ul');
var l = u.querySelectorAll("li");
var a = u.querySelectorAll('li.hasul > a');
for(var i=0; i<a.length;i++){
a[i].addEventListener('click', function(){
l.forEach(function(i,n){
i.classList.remove('on');
});
event.target.parentNode.classList.toggle('on');
});
}
ul{display:flex; list-style:none;}
li{margin:5px;
position: relative;
font-size: 20px;
}
li ul{
border: 1px solid #ccc;
padding: 10px;
position: absolute;
left: 0;
width: 150px;
top: 40px;
display: none;
}
li.on{
border-bottom: 3px solid red;
}
li.on ul{
display: block;
}
a{text-decoration:none;display:block; padding: 5px;}
<ul>
<li class="hasul">Item 1
<ul>
<li>Level 2</li>
<li>Level 2</li>
<li>Level 2</li>
</ul>
</li>
<li class="hasul">Item 2
<ul>
<li>Level 2</li>
<li>Level 2</li>
<li>Level 2</li>
</ul>
</li>
</ul>
https://codepen.io/felixaj/pen/poyyper
You should use the touchstart event, not click for mobiles (check here)
add display:none; to the on css rule

Submenu dissappears on mouse hover

I want the dropdown menu behave like here: https://svyaznoy.ru
var timer;
$(".catalog-menu li").mouseenter(function() {
var that = this;
timer = setTimeout(function(){
$(that).children(".submenu").show();
}, 500);
}).mouseleave(function() {
var that = this;
clearTimeout(timer);
setTimeout(function () {
$(that).children(".submenu").hide();
}, 500);
});
ul {
list-style-type: none;
padding-left: 0;
}
ul.submenu {
display: none;
position: absolute;
left: 100%;
top: 1px;
margin-left: -1px;
}
li {
padding: 10px;
border: 1px solid #ddd;
margin-top: -1px;
}
li.submenu-item {
min-width: 110px;
}
ul.catalog-menu {
width: 150px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<ul class="catalog-menu">
<li>
<span>Apple</span>
<ul class="submenu">
<li class="submenu-item">
<span>Laptops</span>
<ul class="submenu">
<li class="submenu-item">Macbook 12</li>
<li class="submenu-item">Macbook Pro 13</li>
<li class="submenu-item">Macbook Pro 15</li>
<li class="submenu-item">Macbook Air Retina</li>
</ul>
</li>
<li class="submenu-item">
<span>iPhones</span>
<ul class="submenu">
<li class="submenu-item">iPhone 8</li>
<li class="submenu-item">iPhone 8 Plus</li>
<li class="submenu-item">iPhone X</li>
<li class="submenu-item">iPhone XS</li>
<li class="submenu-item">iPhone XS Max</li>
</ul>
</li>
</ul>
</li>
<li>Samsung</li>
<li>Xiaomi</li>
</ul>
It works somewhat similar to svyaznoy.ru, but have a bug.
For example, I hover on "Apple" menu item. Laptops and iPhones show up. Next I hover on "Laptops". Some apple laptop models show up. And here's where the bug shows: if my mouse pointer doesn't leave "Laptops" item and goes straight to laptops submenu - all is ok, but when it leaves "Laptops" on the way to laptops list, e.g. it hovers on iPhones for a moment, then laptops list hides, and I want it to stay there. How can I fix this bug?
jsfiddle: https://jsfiddle.net/16region/vtrj9wgk/30/
You can change display: none to visibility: hidden and add transition-delay. And so you wont need jquery/js
ul {
list-style-type: none;
padding-left: 0;
}
ul.submenu {
visibility: hidden;
position: absolute;
left: 100%;
top: 1px;
margin-left: -1px;
transition: 0s visibility;
transition-delay: 0.5s;
}
li {
padding: 10px;
border: 1px solid #ddd;
margin-top: -1px;
}
li:hover > ul.submenu {
visibility: visible;
}
li.submenu-item {
min-width: 110px;
}
ul.catalog-menu {
width: 150px;
position: relative;
}
<ul class="catalog-menu">
<li>
<span>Apple</span>
<ul class="submenu">
<li class="submenu-item">
<span>Laptops</span>
<ul class="submenu">
<li class="submenu-item">Macbook 12</li>
<li class="submenu-item">Macbook Pro 13</li>
<li class="submenu-item">Macbook Pro 15</li>
<li class="submenu-item">Macbook Air Retina</li>
</ul>
</li>
<li class="submenu-item">
<span>iPhones</span>
<ul class="submenu">
<li class="submenu-item">iPhone 8</li>
<li class="submenu-item">iPhone 8 Plus</li>
<li class="submenu-item">iPhone X</li>
<li class="submenu-item">iPhone XS</li>
<li class="submenu-item">iPhone XS Max</li>
</ul>
</li>
</ul>
</li>
<li>Samsung</li>
<li>Xiaomi</li>
</ul>

Custom index in jQuery sortable

I created sortable list of items using jQuery sortable library.
HTML :
<ul id="sortable">
<li id="item1" data-index="1">Item 1</li>
<li id="item2" data-index="2">Item 2</li>
<li id="item3" data-index="3">Item 3</li>
<li id="item4" data-index="4">Item 4</li>
<li id="item5" data-index="5">Item 5</li>
</ul>
JS :
(function($) {
$('#sortable').sortable({
stop: function(e, ui) {
console.log(ui.item.index()); // Returns 0,1,2 etc
}
});
})(jQuery);
How can I use data-index attribute of li tag as a custom index?
It should print custom index value instead of its own index value i.e 0,1,2 etc.
Working fiddle
You could use $(ui.item).data('index') check example below :
(function($) {
$('#sortable').sortable({
stop: function(e, ui) {
console.log($(ui.item).data('index')); // Returns 0,1,2 etc
}
});
})(jQuery);
Hope this helps.
(function($) {
$('#sortable').sortable({
stop: function(e, ui) {
alert($(ui.item).data('index')); // Returns 0,1,2 etc
}
});
})(jQuery);
#sortable { list-style-type: none; margin: 0; padding: 0; width: 60%; }
#sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; cursor:move; }
#sortable li span { position: absolute; margin-left: -1.3em; }
#sortable li.fixed{cursor:default; color:#959595; opacity:0.5;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
<link href="http://static.jquery.com/ui/css/demo-docs-theme/ui.theme.css" rel="stylesheet"/>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="http://jquery-ui.googlecode.com/svn/tags/latest/external/jquery.bgiframe-2.1.2.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/i18n/jquery-ui-i18n.min.js"></script>
<ul id="sortable">
<li id="item1" data-index="111">Item 1</li>
<li id="item2" data-index="222">Item 2</li>
<li id="item3" data-index="333">Item 3</li>
<li id="item4" data-index="444">Item 4</li>
<li id="item5" data-index="555">Item 5</li>
</ul>

How can I restrict jQuery UI connected lists drag and drop to single direction

I am using jQuery UI Connectedlist
Here drag and drop is working fine with both side from left to right and right to left.
How can I disable right to left ? It has to work only one way, from left to right.
I need also sorting to still work inside ul yellow items like in grey items.
$(function() {
$( "#sortable1, #sortable2" ).sortable({
connectWith: ".connectedSortable"
}).disableSelection();
});
#sortable1, #sortable2 {
border: 1px solid #eee;
width: 142px;
min-height: 20px;
list-style-type: none;
margin: 0;
padding: 5px 0 0 0;
float: left;
margin-right: 10px;
}
#sortable1 li, #sortable2 li {
margin: 0 5px 5px 5px;
padding: 5px;
font-size: 1.2em;
width: 120px;
}
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Sortable - Connect lists</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<body>
<ul id="sortable1" class="connectedSortable">
<li class="ui-state-default">Item 1</li>
<li class="ui-state-default">Item 2</li>
<li class="ui-state-default">Item 3</li>
<li class="ui-state-default">Item 4</li>
<li class="ui-state-default">Item 5</li>
</ul>
<ul id="sortable2" class="connectedSortable">
<li class="ui-state-highlight">Item 1</li>
<li class="ui-state-highlight">Item 2</li>
<li class="ui-state-highlight">Item 3</li>
<li class="ui-state-highlight">Item 4</li>
<li class="ui-state-highlight">Item 5</li>
</ul>
</body>
</html>
You could cancel the drag event in the right list sortable2 using receive event in sortable1 to prevent receiving any item from second list.
To drag grey lis back to the left side we will add helper class e.g s2 that will identify the sortable2 original items and cancel the drag only on them :
$("#sortable1").sortable({
receive: function(ev, ui) {
if(ui.item.hasClass("s2"))
ui.sender.sortable("cancel");
}
});
Hope this helps.
$(function() {
$( "#sortable1, #sortable2" ).sortable({
connectWith: ".connectedSortable"
}).disableSelection();
$("#sortable1").sortable({
receive: function(ev, ui) {
if(ui.item.hasClass("s2"))
ui.sender.sortable("cancel");
}
});
});
#sortable1, #sortable2 {
border: 1px solid #eee;
width: 142px;
min-height: 20px;
list-style-type: none;
margin: 0;
padding: 5px 0 0 0;
float: left;
margin-right: 10px;
}
#sortable1 li, #sortable2 li {
margin: 0 5px 5px 5px;
padding: 5px;
font-size: 1.2em;
width: 120px;
}
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Sortable - Connect lists</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<body>
<ul id="sortable1" class="connectedSortable">
<li class="ui-state-default">Item 1</li>
<li class="ui-state-default">Item 2</li>
<li class="ui-state-default">Item 3</li>
<li class="ui-state-default">Item 4</li>
<li class="ui-state-default">Item 5</li>
</ul>
<ul id="sortable2" class="connectedSortable">
<li class="ui-state-highlight s2">Item 1</li>
<li class="ui-state-highlight s2">Item 2</li>
<li class="ui-state-highlight s2">Item 3</li>
<li class="ui-state-highlight s2">Item 4</li>
<li class="ui-state-highlight s2">Item 5</li>
</ul>
</body>
</html>
Currently your connectWith selector matches both the sortable, i.e it's a two way connection. If you only want one way connection from left to right, just connect the left sortable to right sortable using a more specific selector (#sortable2) than a common one:
$(function() {
$("#sortable1").sortable({
connectWith: "#sortable2"
}).disableSelection();
$("#sortable2").sortable({}).disableSelection();
});
The demo below has the shorter code that does the same thing:
$(function() {
$(".connectedSortable").sortable({
connectWith: "#sortable2"
//----------^---------- #sortable2 connectWith #sortable2 has no effect
}).disableSelection();
});
#sortable1,
#sortable2 {
border: 1px solid #eee;
width: 142px;
min-height: 20px;
list-style-type: none;
margin: 0;
padding: 5px 0 0 0;
float: left;
margin-right: 10px;
}
#sortable1 li,
#sortable2 li {
margin: 0 5px 5px 5px;
padding: 5px;
font-size: 1.2em;
width: 120px;
}
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<ul id="sortable1" class="connectedSortable">
<li class="ui-state-default">Item 1</li>
<li class="ui-state-default">Item 2</li>
<li class="ui-state-default">Item 3</li>
<li class="ui-state-default">Item 4</li>
<li class="ui-state-default">Item 5</li>
</ul>
<ul id="sortable2" class="connectedSortable">
<li class="ui-state-highlight">Item 1</li>
<li class="ui-state-highlight">Item 2</li>
<li class="ui-state-highlight">Item 3</li>
<li class="ui-state-highlight">Item 4</li>
<li class="ui-state-highlight">Item 5</li>
</ul>
The options you are looking for are cancel and update (s2 inspired by the post above), it will disable the drag on matched elements.
$(function() {
$( "#sortable1, #sortable2" ).sortable({
connectWith: ".connectedSortable",
cancel: ".ui-state-highlight, .s2",
update: function( event, ui ) {ui.item.addClass("s2");}
}).disableSelection();
});

Categories

Resources