Replacing tag without losing inner tags in JavaScript - appendchild

Let suppose I have this HTML code :
<div id="actual">
<ol>
<li>robots</li>
<li>wrong</li>
<li>hi</li>
<li>bye</li>
</ol>
</div>
i want to replace ol by ul without losing the inner tags (li)and thier content
i tried that:
const actual = document.getElementById('actual');
const ulReplace = document.createElement('ul');
actual.children[0].replaceWith(ulReplace);
but i replace the ol by ul and remove every thing inside it.
also i try to clone the content and re-append it after but also i lose it when removed

Related

Skeleton page with v-cloak: how to target loading div with css ? Vue

I'm using Webpack/Laravel and injecting vuejs on id #app in my page so to have skeleton loading page I want to have this markup
//client side, will show after ~0.2 seconds
<div id="app" v-cloak>
<hello-world>
</div
//server side, show for ~0.2 s then disappear
<div id="app__loading" v-cloak>
<div class="skeleton">
<span class="skeleton_ribs"></span>
</div>
</div>
I managed to display loading gif in background as pseudo element when v-cloak and everything inside from #app__loading is removed, but if I add normal elements in markup they appear at the bottom of the page after #app loads
[v-cloak] > * { display:none }
[v-cloak] + #app__loading::before {
content: url('https://i.pinimg.com/originals/65/ba/48/65ba488626025cff82f091336fbf94bb.gif');
display: flex;
justify-content: center;
align-items: center;
}
But I would like something like this to work with markup inside #app__loading, but it doesn't work
[v-cloak] > * { display:none }
#app-loader{
display: block;
}
[v-cloak] #app::finish-loading{
[v-cloak] #app-loader{
display: none!important;
}
}
You seem to be expecting the content your initial element to be found in the template of app root element. When using $mount() function, Vue completely replaces the target element with the template of the mounted element.
This replacement is somewhat masked by the fact that, out of the box, the index.html contains a <div id="app"> which gets replaced by the <div id="app">...</div> in your App.vue template.
But they're actually not related (and not the same element). If you changed the id of the one in index.html you'd need to change the target el in main.(js|ts). And obviously, you could change the id of the one in App.vue as well.
Now, to solve your issue, you could simply place v-cloak on the div in your App.vue. From what you've shown so far, that should make it work as expected.
For more complex use cases (i.e: if you wanted to trigger a particular event bound to the initial element) the way to go would be to wrap the initial placeholder in a parent, bind to the parent and, later on, in Vue, target the parent with this.$el.closest('.some-class') or with this.$el.parentElement() to access the binding.
If you still can't get the expected result, please create a mcve (you could use codesanbox.io) and describe in detail what is the expected behavior.
To make your headache smaller till you find proper vue solution, you can grab loader by id and when Vue instance mounts - give display none
export default {
mounted() {
document.querySelector('#app__loading').style.display = 'none';
},
}

Comment out a part of Vue template element

Sometimes it is needed to comment out some element attribute without having to remember it in order to restore it quickly after some tests.
Commenting out whole element is achievable with HTML commenting syntax
<div>
<!-- <h2>Hello</h2> -->
<span>hi</span>
</div>
However this won't work with a single attribute (causes rendering error)
<my-comp id="my_comp_1"
v-model="value"
<!-- :disabled="!isValid" -->
#click="handleClick">
</my-comp>
The best approach I could see and used before was to make a tag backup by copying whole element and settings v-if="false" for it (or comment out whole copied element) and continue to experiment with original one
I don't think you can put an HTML comment inside a component tag, for much the same reason you can't put comments inside an HTML element opening tag. It's not valid markup in either situation. I think the closest you could come would be to place the comment in the quotes:
:disabled="// !isValid"
Which would have the same effect as:
:disabled=""
Depending on whether your component can handle that value being missing, that might fit your needs.
Prefix the attribute value with data- or Wrap with data attribute.
<my-comp id="my_comp_1"
v-model="value"
data-:disabled="!isValid"
data-_click="handleClick"> # `#` could not be used
</my-comp>
or
<my-comp id="my_comp_1"
v-model="value"
data='
:disabled="!isValid"
#click="handleClick">
'>
</my-comp>
I'll with the attribute set to something like data-FIXME.
I got these solutions to work. I thought of solution 1.
Starting code:
<div
v-for="foo in foos"
:key="foo.id"
#click="foo.on = !foo.on /* JavaScript comment. */"
>
<label>
{{ foo.name }} {{foo.on}}
</label>
</div>
The Vue directive HTML attribute that needs to be disabled: #click="foo.on = !foo.on"
How the final div tag will run:
<div
v-for="foo in foos"
:key="foo.id"
>
Solutions 1 and 2 keep the disabled attribute inside its tag. I didn't find a good way to make a "raw string". To keep the attribute in the tag, the outer and inner quotes must be different.
sol. 1: I made a new v-bind attribute (:lang) to put the disabled attribute in.
:lang='en /* #click="foo.on = !foo.on" */'
Sol. 2: Pick a Vue directive. Put the attribute in.
v-for="foo in foos /* #click='foo.on = !foo.on' */"
Solutions 3 and 4 put the attribute outside the tag.
Sol. 3:
<div v-if="false">
#click="foo.on = !foo.on"
</div>
Sol. 4: <!-- #click="foo.on = !foo.on" -->
One way to remove/hide component attributes is to create a custom directive for it.
Let's say you create a directive called v-hide and put it in your component as:
<my-comp v-model="value" #click="handleClick" v-hide :disable='true'></my-comp>
And the output would be:
<my-comp v-model="value" #click="handleClick"></my-comp>
Here is a working example:
Vue.component ('my-component', {
template: `<p> A custom template </p>`
})
Vue.directive('hide', {
inserted: function (el) {
console.log('el before hide', el)
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
console.log('el after hide', el)
}
})
new Vue({
el: '#app',
data () {
return {
someValue: 'Hello'
}
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<my-component v-model='someValue' v-hide :disable='true'></my-component>
</div>

Selenium webdriver: How to find nested tags?

A webpage contains
<div class="divclass">
<ul>
<li>
"hello world 1"
<img src="abc1.jpg">
</li>
<li>
"hello world 2"
<img src="abc2.jpg">
</li>
</ul>
</div>
I am able to get data under div using
element = driver.find_element(class: "divclass")
element.text.split("\n")
But I want all links respective to the achieved data
I tried using
driver.find_elements(:css, "div.divclass a").map(&:text)
but failed.
How can I get related links to the data?
If you want to get the href attribute try the below code(I am not familiar with ruby so I am posting the code in Java).
List<WebElement> elements = driver.findElements(By.xpath("//*[#class='divclass']//a"));
for(WebElement webElement:elements){
System.out.println(webElement.getAttribute("href"));
}
The xpath points to all the a tags under the div tag with class name =divclass.
If you want to get the text of all the links, you can use the blow code:
List<WebElement> elements = driver.findElements(By.xpath("//*[#class='divclass']//a"));
for(WebElement webElement:elements){
System.out.println(webElement.getText());
}
Hope it helps.
In ruby
element = driver.find_elements(:xpath, "//*[#class='divclass']//a")
list = element.collect{|e| hash ={e.text => e.attribute("href")}}
will return corresponding links with data in array of hashes

displaySingle.imageWrapIfAny wrapp all images insted of single one

plugin.tt_news.displaySingle {
imageWrapIfAny = <div class="newsImageWrapper">|</div>
caption_stdWrap >
caption_stdWrap.wrap = <div class="captionHolder">|</div>
}
Can any one tell me why all my images go into div.newsImage wrapper insisted of single one??
If you want to wrap every single image with a new div, then use this Typoscript:
plugin.tt_news.displaySingle.imageWrapIfAny >
plugin.tt_news.displaySingle.image.wrap = <div class="newsImageWrapper">|</div>

printing jquery colorbox content

I am using colorbox to AJAX some external HTML onto a page.
My client wants to print this content direct from the page, therefore i used a print CSS loaded into the head of the document with colorbox's onComplete event hook.
The content that is loaded is a raft of legacy tables with inline styles which i can't seem to overwrite with the print CSS and when i view by media type the layout looks broken.
I put this down to only retrieving a chunk of the HTML with jQuery .find() rather than the whole page.
Would it be best to use an iframe with colorbox and load the whole HTML document including header. I assume this would preserve the layout better rather than retrieving a chunk.
I am not sure how to print the iframe's content. When i tried it printed an extremely small snapshot of the whole page with the iframe in the middle.
Am a bit lost on this one.
The jQuery i am using is as follows:
$('table.pricing > tbody > tr > th > p.price_report > a').colorbox({
title: "Price report",
transition: "elastic",
innerWidth: "733px",
innerHeight: "699px",
opacity: "0.5",
onComplete:function(){
// Ajax call to content
// insert Print CSS into head of document
}
});
The print CSS that is loaded merely hides the body content and then displays everything under #colorbox.
Apologies all the proper code is at work.
1) I would suggest switching to the "inline" colorbox option (but you don't have to):
<script type="text/javascript">
$(document).ready(function(){
$(".pricing").colorbox({width:"733px", height:"699px", iframe:false, open:true, overlayClose:true, opacity:.5, initialWidth:"300px", initialHeight:"100px", transition:"elastic", speed:350, close:"Close", photo:false, inline:true, href:"#price_report"});
});
</script>
2) Now add your html including the javascript and code to write your printable area:
<div style='display: none'>
<div id='price_report' class='pricing'>
<script type="text/javascript">
//<!--
function ClickHereToPrint(){
try{
var oIframe = document.getElementById('ifrmPrint');
var oContent = document.getElementById('pricingPrintArea').innerHTML;
var oDoc = (oIframe.contentWindow || oIframe.contentDocument);
if (oDoc.document) oDoc = oDoc.document;
oDoc.write("<html><head><title>My Printable Pricing Report!</title>");
oDoc.write("<link rel='stylesheet' href='link-to-my-styles/style.css' type='text/css' />");
oDoc.write("</head></body><body onload='this.focus(); this.print();' style='text-align: left; font-size: 8pt; width: 432pt;'>");
oDoc.write("<h3>My Pricing Report</h3>");
oDoc.write(oContent + "</body></html>");
oDoc.close();
}
catch(e){
self.print();
}
}
//-->
</script>
<iframe id='ifrmPrint' src='#' style="width:0pt; height:0pt; border: none;"></iframe>
<div id="pricingPrintArea">
<div class="myreport">
<p>Hello, I am a pricing report!</p>
</div>
</div>
</div>
</div>
3) Now add the print button wherever you wish:
<div id="print_btn">
<a href="#" onclick="ClickHereToPrint();" style="cursor: pointer;">
<span class="print_btn">
Click Here To Print This Report!
</span>
</a>
</div>
Note, the blank iframe included is where the javascript will write your printable area. You will also notice in the javascript that you can add a stylesheet, inline styles, a page title and more!
Keep in mind, this process will work similar for the ajax version of the colorbox, but if you go the route of the ajax method, you will have to write the printable div and print iframe and print javascript directly to that external file.
Theoretically, anything inside the printable region div (in this example: pricingPrintArea) will print, so as-long-as you wrap that around whatever you want to print, it will do so.
Important tip: Printers all read a Web page differently so try not to rely too much on inline styles and pixel dimensions for your printable version. That is why it is a good idea to create a stylesheet specifically for the printable page.
Hopefully that answers your question. (btw, you should be able to get this method to work with the ajax method of colorbox, but I haven't tested it).

Resources