I am currently working with jsPlumb & got stuck at saving & loading the containers. I figured out how to save the endpoints, connections & positions.
But I can't figure out, how to save the div containers, including their attributes, children & the children's attrubites.
Here's a snippet of the containers, any ideas how to stringify them?
<div class="window main node ui-draggable _jsPlumb_endpoint_anchor_" id="maincontainer1" data-nodetype="main" style="left: 663px; top: 200px; width: 230px; height: 200px;">
<div class="ctrl_container">
<div class="button_rm">x</div>
</div>
<div class="layer" id="layercontainer1_1" style="height: 80px; width: 100%; background: none repeat scroll 0% 0% transparent;">
<div class="window filter node" style="left:25px; top:5px;" name="3#2#ABC#" id="filtercontainer2_1_1">
<div class="ctrl_container">
<a class="filter_caption edit" href="#">Edit</a>
<div class="button_rm">x</div>
</div>
<div class="details_container">
<span id="filter_label" class="filter_label jtextfill" style="font-size: 22px;">PrimarySupportGrp = 123</span>
</div>
</div>
</div>
<div class="layer" id="layercontainer1_2" style="height: 90px; width: 100%; background: none repeat scroll 0% 0% rgba(0, 255, 255, 0.4);"><div class="line-separator"></div>
<div class="window filter node" style="left:25px; top:5px;" name="5#4#Yes#" id="filtercontainer2_2_1">
<div class="ctrl_container">
<a class="filter_caption edit" href="#">Edit</a>
<div class="button_rm">x</div>
</div>
<div style="" class="details_container">
<span id="filter_label" class="filter_label jtextfill" style="font-size: 14px;"> Site > Yes</span>
</div>
</div>
</div>
</div>
I don't suggest saving the complete children hierarchy, but if you want - why not use .html()
var data = [];
$(".layer").each(function(){
var html = $(this).html();
data.push(html);
});
OR
Just save what is required to re-render them at the correct position - left, top etc.
for(var i=0 ; i<length; i++){
var layerTemplate = "...div template html goes here";
var $layerTemplate = $(layerTemplate);
$layerTemplate.css({top : data[i].top , left : data[i].left});
$("#maincontainer1").append($layerTemplate);
}
Some time back I wrote a script for saving & re-rendering jsPlumb - https://github.com/nitinsurana/jsPlumb-Persistence
Related
I have a simple HTML drawer that contains product recommendations. Javascript is used to toggle it open and close. In the HTML, there are 2 prices, the regular price and the discounted price. Both are visible on load. The JS is supposed to hide the discounted price(current price), if the current price is the same as the old price. Because then it's not necessary to show both(identical prices). But if there is an offer, it's supposed to show both.
The problem is, my javascript for opening and closing the drawer is working, but the code for hiding/showing both prices aren't. And I know the code is fine because it works on another product recommendation template I'm using(which isn't a drawer, but normal on-page element).
I've tried putting the price-code before the drawer-function code, but then the drawer doesn't respond to clicks and does not open anymore.
When I use Preview in the software I'm using to inject product recommendations(Dynamic Yield), the prices are shown correctly. It's only when I preview it on the website itself, that it doesn't work. Both prices are shown even if they match.
Here is the JS:
(function() {
var container = document.querySelectorAll('.dy-sliding-drawer-container')[0];
var handler = container.querySelector('.dy-sliding-handle');
function toggle() {
if (container.className.indexOf('dy-open') > -1) {
container.className = container.className.replace('dy-open','');
} else {
container.className = container.className.trim() + ' dy-open';
}
}
handler.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
toggle();
});
})();
var mq = window.matchMedia( "(max-width: 599px)" );
var itemPrices = document.querySelectorAll('.price-box');
for(var i=0; i<itemPrices.length; i++){
var discount_price_element = itemPrices[i].getElementsByClassName("dynamic-price")[0];
var price_element = itemPrices[i].getElementsByClassName("regular-price")[0];
if(parseFloat(discount_price_element.innerHTML) == parseFloat(price_element.innerHTML)){
discount_price_element.style.display = "none";
if (mq.matches) {
price_element.style.fontSize = "16px";
price_element.style.paddingTop = "15px";
} else {
price_element.style.fontSize = "20px";
}
price_element.style.fontWeight = "700";
} else {
price_element.style.textDecoration = "line-through";
price_element.style.paddingLeft = "10px";
}
}
Is there anything I can do to make both codes work together? I've tried putting them in the same function, with no luck.
Here is the HTML(I guess the only relevant code here is the .price-box div, but I'm gonna paste everything in case you need it):
<div>
<div class="dy-sliding-drawer-container" data-dy-strategy-container="">
<div class="dy-sliding-handle">
<div class="dy-sliding-handle-text">
${Title}
</div>
</div>
<div class="dy-sliding-items-container dy-open">
${#Recommendation}
<a href="${Item Link}" class="dy-rv-rcom-item">
<div class="dy-rv-rcom-item-image-container item-${SKU}" style=" background-image: url(${Item Image}); background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;min-height: 50px;
min-width: 50px;">
</div>
<div class="dy-rv-rcom-item-name">${Item Name}</div>
<div class="dy-rv-rcom-item-price">
<div class="price-box">
<span class="dynamic-price">${product_price_dynamic},-</span>
<span class="regular-price">${price},-</span>
</div>
</div>
<!-- button -->
<div class="product-item-actions add-to-cart-button-dy">
<div class="actions-primary">
<form data-role="tocart-form" action="https://www.norli.no/checkout/cart/add/uenc/${uenc}/product/${product_id}/" method="post">
<input type="hidden" name="product" value="${product_id}" tabindex="0">
<input type="hidden" name="uenc" value="${uenc}" tabindex="0">
<input name="form_key" type="hidden" value="${formkey}" tabindex="0">
<button type="submit" title="Handlekurv" class="action tocart primary" tabindex="0">
<span class="tocart--short">Legg til</span>
</button>
</form>
</div>
</div>
<div class="product actions product-item-actions read-more-button-dy" style="display: none !important;">
<div class="actions-primary">
<div class="fieldset">
<div class="actions">
<span class="out-of-stock-view-more lesmer-button" style="color:#FFF; display: none !important;">Les mer</span>
</div>
</div>
</div>
</div>
<!-- button end -->
</a>
${/Recommendation}
</div>
</div>
</div>
And if the CSS is needed, heres is the CSS for the relevant classes(old price and new price:
.price-box{
display: flex;
align-items: flex-end;
}
.dynamic-price{
color:#dd1768;
font-size:18px;
font-weight:700;
letter-spacing:-1.5px !important;
padding-bottom:0px !important;
margin-bottom:0px !important;
}
.regular-price{
font-size:14px;
letter-spacing:-1px !important;
padding-bottom:0px !important;
margin-bottom:0px !important;
font-weight: 400;
}
Could anybody help me out? Keep in mind that the Javascript works fine for recommendation widgets which loads on-page, but not with this click-to-open drawer. Appreciate any help.
Your script does basically work - provided the variables in your template have been
replaced by actual values before the markup is rendered into the DOM. I have modified your data a little bit to demonstrate the correct behaviour on some same-price and some differing-price .price-box examples.
I also took the liberty of shortening your very verbose scripts. I have probably gone a bit too far, especially my .reduce() construct is not easy to read. But look at it as an extreme way of avoiding creating variable names.
(function(){
var container = document.querySelector('.dy-sliding-drawer-container');
container.querySelector('.dy-sliding-handle').onclick=e=>
container.classList.toggle("dy-open");
})();
// var mq = window.matchMedia( "(max-width: 599px)" );
document.querySelectorAll('.price-box').forEach(p=>{
[...p.querySelectorAll("span")].reduce((a,c)=>a.style.display=(a.textContent==c.textContent?"none":""))});
.dy-open {background-color:yellow}
.price-box{
display: flex;
align-items: flex-end;
}
.dynamic-price{
color:#dd1768;
font-size:18px;
font-weight:700;
letter-spacing:-1.5px !important;
padding-bottom:0px !important;
margin-bottom:0px !important;
}
.regular-price{
font-size:14px;
letter-spacing:-1px !important;
padding-bottom:0px !important;
margin-bottom:0px !important;
font-weight: 400;
}
<div>
<div class="dy-sliding-drawer-container" data-dy-strategy-container="">
<div class="dy-sliding-handle">
<div class="dy-sliding-handle-text">
${Title}
</div>
</div>
<div class="dy-sliding-items-container">
${#Recommendation}
<a href="#${Item Link}" class="dy-rv-rcom-item">
<div class="dy-rv-rcom-item-image-container item-${SKU}" style=" background-image: url(${Item Image}); background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;min-height: 50px;
min-width: 50px;">
</div>
<div class="dy-rv-rcom-item-name">${Item Name}</div>
<div class="dy-rv-rcom-item-price">
<div class="price-box">
<span class="dynamic-price">50,-</span>
<span class="regular-price">50,-</span>
</div>
</div>
<div class="dy-rv-rcom-item-name">${Item Name}</div>
<div class="dy-rv-rcom-item-price">
<div class="price-box">
<span class="dynamic-price">50,-</span>
<span class="regular-price">60,-</span>
</div>
</div>
<div class="dy-rv-rcom-item-name">${Item Name}</div>
<div class="dy-rv-rcom-item-price">
<div class="price-box">
<span class="dynamic-price">60,-</span>
<span class="regular-price">60,-</span>
</div>
</div>
<!-- button -->
<div class="product-item-actions add-to-cart-button-dy">
<div class="actions-primary">
<form data-role="tocart-form" action="https://www.norli.no/checkout/cart/add/uenc/${uenc}/product/${product_id}/" method="post">
<input type="hidden" name="product" value="${product_id}" tabindex="0">
<input type="hidden" name="uenc" value="${uenc}" tabindex="0">
<input name="form_key" type="hidden" value="${formkey}" tabindex="0">
<button type="submit" title="Handlekurv" class="action tocart primary" tabindex="0">
<span class="tocart--short">Legg til</span>
</button>
</form>
</div>
</div>
<div class="product actions product-item-actions read-more-button-dy" style="display: none !important;">
<div class="actions-primary">
<div class="fieldset">
<div class="actions">
<span class="out-of-stock-view-more lesmer-button" style="color:#FFF; display: none !important;">Les mer</span>
</div>
</div>
</div>
</div>
<!-- button end -->
</a>
${/Recommendation}
</div>
</div>
</div>
Explanation:
The .reduce() over all the <span>s in a .price-box div relies on the fact that the "reduced price" span always comes before the "regular price" one and that you will always have exactly two elements. When reduce() is called without the second (starting value) argument it takes the first array element (the "reduced price" span) as the starting value (a). The (only) "current" value in the iteration (c) will then be the regular price span. When the .textContent of both elements are the same the a span will be hidden, otherwise it will remain visible.
My aim is to do a thumbnail gallery which will enlarge thumbnail in a new row after the thumbnail has been clicked [Edited for clarity]:
I am not sure how to do it properly (if there is a proper way). How would you conceptually approach this task?
Flexbox seems to be nice for the first part, but then add cell on calculated position by JS OR split the flexbox into two? And in every case redo everything completely in there was a resize?
A help would be also to know how this kind of gallery is called, because I was unable to find any info on Google. Thank you!
This is an example showing how a container could use display:flex; to show a number of div.item as pictures in a gallery.
Each of such div.item gets attached an handler for the click event, that will clone, populate and attach to dom the template defined to represent a preview.
The preview will show a bigger picture of the thumbnail clicked and some further details that the demo just limits to the item index number. Such bigger picture must be defined in the attribute data-original-image-url of the img thumbnail.
I was inspired to this question Gallery with bigger previews "in place" to craft the trick needed to determine the last item of a given row in a flex container.
Consider that the pictures url are fake here so the demo won't show any picture but just broken urls. I faked the size of items setting a arbitrary different width for each of them and setting the height fixed in a css class.
//Add click event handler to every div.item in any .gallery
let items = document.querySelectorAll('.gallery > div.item');
for(let item of items){
item.addEventListener('click', onItemClick);
}
/*
When an item gets clicked,
It shows a preview, bound to the item clicked, on the next line
*/
function onItemClick(event){
//the clicked item
//(currentTarget retrieves the item that had the listener not the actual element clicked)
//so in this case it will be always the div.item (never the picture itself)
clickedItem = event.currentTarget;
//determines the index (1 based) of the clicked item relative to its container
const itemIndex
= Array.from(clickedItem.parentElement.querySelectorAll('.item')).indexOf(clickedItem) + 1;
//removes all .preview elements inside the parent of the clicked item
clickedItem.parentElement.querySelectorAll('.preview').forEach( (o, i) => {
o.remove();
});
//retrieves the url for the bigger picture of the item clicked
let urlBiggerImage = clickedItem.querySelector('img').getAttribute('data-original-image-url');
//retrieves the last item in the row where the item clicked lays
let lastItemOfRow = getLastItemOfRow(clickedItem);
//retrieves the html template for the preview
const template = document.getElementById("template_preview");
//clones the template to prepare the node as a concrete preview for the current item
const preview = template.content.cloneNode(true);
//sets the img src of the preview using the value of this item.data[original-image-url]
preview.querySelector('img').src = urlBiggerImage;
//sets the description of the preview
preview.querySelector('.col:nth-child(2) p').innerText = `You selected the item n.${itemIndex}`;
//appends the preview item after the last item in the row where item clicked lays
lastItemOfRow.after( preview );
}
/*
Retrieves the last item in the row (of the flexbox container)
given an item determining the row to examine
Inspired by:
https://stackoverflow.com/questions/72096795/gallery-with-bigger-previews-in-place/72096982
*/
const getLastItemOfRow = (item) => {
const grid = item.parentElement;
const gridItems = Array.from(grid.querySelectorAll('.item'));
const itemIndex = gridItems.indexOf(item);
const baseOffset = item.offsetTop;
let breakIndex = gridItems.findIndex(item => item.offsetTop > baseOffset) -1;
breakIndex = (breakIndex < 0) ? itemIndex : breakIndex;
return gridItems[breakIndex];
}
.gallery{
display: flex;
flex-wrap: wrap;
gap: 10px 10px;
padding: 10px;
border: solid 1px gray;
/*Here you can define an arbitrary width for the container*/
width: 430px;
}
.item{
display: block;
height: 50px;
background: red;
color: white;
font-weight: 700;
cursor: pointer;
}
.item > img{
height: 50px;
}
.preview{
border: solid 1px black;
flex: 0 0 100%;
}
.preview > .col{
display: inline-block;
padding: 5px;
vertical-align: middle;
}
.bigger {
width: 200px;
height: 100px;
}
<template id="template_preview">
<div class="preview">
<div class="col">
<img class="bigger" src=""/>
</div>
<div class="col">
<p>You selected the picture n:</p>
</div>
</div>
</template>
<!-- You can have many .gallery container -->
<div class="gallery">
<!-- Each .item will count as an item with preview -->
<div class="item">
<img src="/img/1.jpg" title="1" style="width: 100px;" data-original-image-url="/img/bigger/1.jpg"/>
</div>
<div class="item">
<img src="/img/2.jpg" title="2" style="width: 70px;" data-original-image-url="/img/bigger/2.jpg"/>
</div>
<div class="item">
<img src="/img/3.jpg" title="3" style="width: 180px;" data-original-image-url="/img/bigger/3.jpg"/>
</div>
<div class="item">
<img src="/img/4.jpg" title="4" style="width: 220px;" data-original-image-url="/img/bigger/4.jpg"/>
</div>
<div class="item">
<img src="/img/5.jpg" title="5" style="width: 40px;" data-original-image-url="/img/bigger/5.jpg"/>
</div>
<div class="item">
<img src="/img/6.jpg" title="6" style="width: 80px;" data-original-image-url="/img/bigger/6.jpg"/>
</div>
<div class="item">
<img src="/img/7.jpg" title="7" style="width: 50px;" data-original-image-url="/img/bigger/7.jpg"/>
</div>
<div class="item">
<img src="/img/8.jpg" title="8" style="width: 50px;" data-original-image-url="/img/bigger/8.jpg"/>
</div>
<div class="item">
<img src="/img/9.jpg" title="9" style="width: 50px;" data-original-image-url="/img/bigger/9.jpg"/>
</div>
<div class="item">
<img src="/img/10.jpg" title="10" style="width: 50px;" data-original-image-url="/img/bigger/10.jpg"/>
</div>
<div class="item">
<img src="/img/11.jpg" title="11" style="width: 50px;" data-original-image-url="/img/bigger/11.jpg"/>
</div>
<div class="item">
<img src="/img/12.jpg" title="12" style="width: 50px;" data-original-image-url="/img/bigger/12.jpg"/>
</div>
<div class="item">
<img src="/img/13.jpg" title="13" style="width: 80px;" data-original-image-url="/img/bigger/13.jpg"/>
</div>
<div class="item">
<img src="/img/14.jpg" title="14" style="width: 150px;" data-original-image-url="/img/bigger/14.jpg"/>
</div>
</div>
1.I am trying to get a fixed position div (#externalPopupHeader) to inherit the width of its parent width(#reportsWrap) with no success.
2 I am also trying to get the #externalPopupHeader div with the lengthy content to scroll horizontally WITHOUT the scroll bar being visible. This is required because I would then Like to use javascript to sync the column headings with the content below.
#reportsWrap{
min-width: 1050px;
overflow: hidden;
position: relative
}
#externalPopupHeader{
width: inherit // Have aslo tried min-width: 1050px, and width: 100%;
position: fixed;
top: 0
overflow-x: scroll // hidden disables the scrolling.
}
<div id="reportsWrap">
<div id="externalPopupHeader">
<div id="genConfigFieldsWrap">
<div class="genField">Record No.</div>
<div class="genField">Serial Number</div>
<div class="genField">Room Number</div>
<div class="genField">Codec IP</div>
<div class="genField">Model</div>
<div class="genField">Version</div>
<div class="genField">NTP Status</div>
<div class="genField">Speaker Track</div>
<div class="genField">Max RX Kbps</div>
<div class="genField">Max TX Kbps</div>
<div class="genField">Default Call Kbps</div>
<div class="genField">Remote View</div>
<div class="genField">Voice VLAN</div>
<div class="genFieldTrans">Transport</div>
<div class="genField">Olson Zone</div>
<div class="genField">Time Zone</div>
<div class="genField">Helpdesk</div>
<div class="genField">Provisioning</div>
</div>
</div>
<div id="innerReportWrap">
<div id="genConfigAnchor">
</div>
</div>
</div>
your code is ok. your div data is to small to check the original behavior.
try to add some more text to check.
<div class="genField">NTP Status NTP Status NTP Status NTP Status</div>
then you will see that it is correct.
you can check this example
https://jsfiddle.net/r61t50sb/1/
I'm using jQuery panzoom to zoom an image and some div elements. This works generally but the elements positioned on top of the image don't stay in their original locations. Is there anyway to keep the div elements where they were whilst being scaled?
JSFiddle: https://jsfiddle.net/828wu2dy/
HTML:
<section id="inverted-contain">
<div class="panzoom-elements">
<div class="item item1">ITEM 1</div>
<div class="item item2">ITEM 2</div>
<div class="panzoom">
<img src="http://www.hdwallpapers.in/walls/enchanted_forest-wide.jpg">
</div>
</div>
<div class="buttons">
<button class="zoom-in">Zoom In</button>
<button class="zoom-out">Zoom Out</button>
<input type="range" class="zoom-range">
<button class="reset">Reset</button>
</div>
</section>
JS:
(function() {
var $section = $('#inverted-contain');
$section.find('.panzoom').panzoom({
$zoomIn: $section.find(".zoom-in"),
$zoomOut: $section.find(".zoom-out"),
$zoomRange: $section.find(".zoom-range"),
$reset: $section.find(".reset"),
$set: $section.find('.panzoom-elements > div'),
startTransform: 'scale(0)',
increment: 0.1,
minScale: 1,
maxScale: 2,
contain: 'invert'
}).panzoom('zoom');
})();
CSS:
.panzoom-elements {
width: 50%;
height: 400px;
}
.item {
position: absolute;
z-index: 10;
}
.item.item1 {
color: white;
background: black;
width:50px;
height:50px;
top: 300px;
left: 100px;
}
.item.item2 {
color: white;
background: black;
width:50px;
height:50px;
top: 200px;
left: 150px;
}
The other problem is that it also doesn't drag horizontally.
I've tried everything I can think of.
Part 1:
To fix your 'item' problem - try putting 'item' elements on one level with 'img' - I mean put them inside div class='panzoom'.
Works for me. ^ ^
<section id="inverted-contain">
<div class="panzoom-elements">
<div class="panzoom">
<div class="item item1">ITEM 1</div>
<div class="item item2">ITEM 2</div>
<img src="http://www.hdwallpapers.in/walls/enchanted_forest-wide.jpg">
</div>
</div>
<div class="buttons">
<button class="zoom-in">Zoom In</button>
<button class="zoom-out">Zoom Out</button>
<input type="range" class="zoom-range">
<button class="reset">Reset</button>
</div>
</section>
The method of thought that led me to this answer: while learning panzoom documentation for API, and examining your fiddle, I found that 'img' or anything that could be seen as direct selector to it (I mean like $('.panzoom').child().first() is nowhere mentioned in your script. That means that most probably img is zooming in/out not by itself. What I thought next - it seem that it's parent is changing. That would mean that you need to put your items inside of that changing space - it is the most logical way to handle it... I tried to test that idea - and it worked.
Part 2:
The other problem is that it also doesn't drag horizontally.
Add this to your CSS
.panzoom{ width: 1920px;}
This is the size of the image. Works for me.
Perhaps you also could add to .panzoom height of image. It is not required in your case where image is horisontal but it could matter when image is vertical.
I am developing an app with many draggable and droppable elements. They all work except in this one case:
This should be draggable:
<div id="8093244595324" class="insertion ui-draggable" style="z-index: 4; position: relative;">
Test Accou...<br />0.330H
</div>
And here's some surrounding HTML.
<div class="paginationPageMargin" style="">
<div id="8195443196587" class="paginationPage" style="">
<div id="8290907158934" class="oneEighthPageLayer" style=""></div>
<div id="8222242963571" class="oneSixthPageLayer" style=""></div>
<div id="8460851026264" class="oneThirdPageLayer" style="">
<div id="8072616373566" style="height: 33%;">
<div id="8686623363113" class="oneThird insertionBlock" value=" " style="">
<div id="8093244595324" class="insertion ui-draggable" style="z-index: 4; position: relative;">
Test Accou...<br />0.330H
</div>
</div>
</div>
<div id="8810410276771" style="height: 33%;">
<div id="8605800682859" class="oneThird insertionBlock" value=" "></div>
</div>
<div id="8509644301764" style="height: 33%;">
<div id="8708665901661" class="oneThird insertionBlock" value=" "></div>
</div>
</div>
</div>Page 1
</div>
Note that there's some z-index stuff going on here. The draggable element itself is index 4. Each page layer div also has a z-index:
.oneThirdPageLayer {
z-index: 1;
height: 100%;
}
.oneSixthPageLayer {
z-index: 2;
height: 100%;
}
.oneEighthPageLayer {
z-index: 3;
height: 100%;
}
I'm not sure if the z-index stuff is relevant or not, as I've taken care to ensure that the element that I'm binding draggable to is on the top of the stack.
Here's the draggable binding:
$('.insertion').draggable({
start: handleDragStart
});
And handleDragStart:
function handleDragStart( event, ui ) {
var $insertion = ui.helper,
insertion = getInsertion($insertion.attr('id'));
// This insertion is in the air now... it has no blocks
insertion.insertionBlocks = [];
}
Any insight would be much appreciated.
I removed all z-index values except for the insertions.