How to style hyperlink after scheme is removed with Javascript? - javascript

So I am trying to display a url that is caught by Javascript. It is returned to JS in the form http://i.mygreatsite.com, but I would like to cut the schema off to make it cleaner, and have the actual code look something like
<a href=http://i.mygreatsite.com>i.mygreatsite.com</a>
Before I tried doing this, I had to set some special attributes on the url, namely setting target to blank so it would open in a new tab and changing the color of the hyperlink to black, as the rest of the links on the page are blue. I went about it like this:
init: function() {
this.on("success", function(file, responseText) {
var span = document.createElement('span');
var a = document.createElement('a');
a.href = responseText;
a.innerHTML = responseText;
a.setAttribute('target', '_blank');
a.style.color="black";
span.appendChild(a);
span.setAttribute("style", "position: absolute; box-sizing: border-box; -webkit-box-sizing: border-box; bottom: -28px; left: 3px; right: 3px; height: 28px; word-wrap: break-word; line-height: 28px; text-overflow: ellipsis; ");
file.previewTemplate.appendChild(span);
});
}
Everything worked fine with it, but when I went to remove the schema I did it by using regex:
repl = responseText.replace(/(https?:\/\/(\S+))/i, "<a href='$1'>$2</a>");
a.href = repl;
a.innerHTML = repl;
a.setAttribute('target', '_blank');
a.style.color="black";
Now the schema is removed, but none of the attributes I set previously that were working before are there now. The URL is blue and opens in the same tab. Am I missing something here? Thanks.

What you've ended up with is an anchor within another anchor:
<a target="_blank" style="XXX">myurl</a>
That's because of setting the innerHTML of the anchor you're trying to create. Setting styles on an element will not cascade (you should really use CSS Stylesheets instead) and of course the target element will not apply as it's technically not the hyperlink you're clicking on!
Instead, just set the innerHTML using the $2 result of your Regex.
Edit
So your updated code would need to be similar to:
repl = responseText.replace(/(https?:\/\/(\S+))/i, "$2");
a.href = responseText;
a.innerHTML = repl;
a.setAttribute('target', '_blank');
a.style.color="black";
//Or if you wanted to use CSS stylesheets
a.className = "myCssClass"

Related

How to keep a URL get from the current address un-encoded in JavaScript?

I have a JavaScript that replaces part of the href of links with the current URL (window.location.href). But I find that the URL replaced is encoded, meaning it is not exactly the same as the original URL.
Desired result: ?redirect=www.example.com/path/slug
Not desired: ?redirect=www.example.com%2path%2slug
I tried to use something like decodeURI near the end of the script but failed.
Here is the working script:
( Also trying on CodePen: [https://codepen.io/pen/MWVMmZW][1] )
$(function () {
$("a[href*='redirect']").each(function () {
const url_str = $(this).attr("href");
const this_url = new URL(url_str);
if (this_url.searchParams.get("redirect")) {
// Get the current url from the browser
// Remove protocol
const current_url = window.location.href.split("://")[1];
// Remove the last slash
let regex = /\/$/;
let clean_url = current_url.replace(regex, "");
const redirect = this_url.searchParams.set("redirect", clean_url);
$(this).attr("href", this_url.href);
}
});
});
body {
padding: 10px 20px;
}
a {
display: block;
margin: 0 0 5px 0;
text-decoration: none;
}
hr {
height: 0px;
margin: 30px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Objective:<br>To change whatever text after <strong>?redirect=</strong> in the links to the current visiting URL using JavaScript. ( only after <strong>?redirect=</strong> )</p>
Link A
Link B
Link C
<p>So, if the current address is https://www.example.com/about/dog<br>The above links should change to:<br>→ https://app.example.com/?redirect=www.example.com/about/dog</p>
<hr />
<p>Other URLs remain unchanged on the web page.</p>
Other Link 01
Other Link 02
Other Link 03
The correct answer is to alter the final part like it follows:
const redirect = this_url.searchParams.set("redirect", clean_url);
$(this).attr("href", decodeURIComponent(this_url.href));

Read JSON and implement it in HTML

First of all, sorry for my bad English, isn't the best ;)
So I'm new to working with JavaScript, Ajax and, jQuery. Since a young age I've been interested in coding. A friend of mine wants an update on their website I made for them a little while ago. They have a small podcast/radio station.
What I'm trying to do is make an automatic link between the podcasts they post on MixCloud and their website. I followed some tutorials and grave throw the forms on this website, but I can't get the script to work properly and get the information out of the JSON file that MixCloud makes with their API.
This is what I've got so far. I can't figure out what I'm doing wrong since I'm very very new to this. I tried different methods, but this is the closest I've got.
const Http = new XMLHttpRequest();
const url = 'https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange = (e) => {
console.log(Http.responseText)
}
function append_json(XMLHttpRequest) {
//Set Up the template
var s = $("#postTemplate")[0].innerHTML.trim();
var holder = document.createElement('div');
holder.innerHTML = s;
var template = holder.childNodes;
var episode = document.getElementById('episodes');
Object.keys(XMLHttpRequest).forEach(function(object) {
//Clone Template
var newEpisode = $(template).clone();
//Populate it
$(newEpisode).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
});
}
$("document").ready(function() {
append_json(XMLHttpRequest);
});
.episodes {
background: white;
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(320px, 380px));
grid-auto-rows: 370px;
grid-auto-flow: dense;
justify-content: center;
padding-top: 10px;
}
.episode {
background: rgb(255, 255, 255);
border: 1px solid grey;
text-align: center;
}
.episodetitle {
font-size: 20px;
color: red
}
.coverimg {
width: 320px;
max-height: 320px
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="episodes">
<script type="text/template" id="postTemplate">
<div class="episode">
<img class="coverimg" src="">
<p class="episodetitle"></p>
</div>
</script>
</div>
For some reason, I can't get the data out of the JSON file and it won't show in the HTML. I built this script with a lot of help from this article: Populate grid <div> & <p> with JSON data file
Can someone help me out and get it working with me?
The JSON file that needs to be read is:
https://api.mixcloud.com/itmotr-radio/cloudcasts/
There's a few things going on so I will address each individually, and you can put them together as the learning :) Your general structure is OK though, nice going so far!
jquery
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">/script>
this is an old version, use
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
AJAX
const Http = new XMLHttpRequest();
const url='https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange=(e)=>{
console.log(Http.responseText)
}
This is all taken care of within jquery automatically. Have a read of the AJAX documentation. This is a good example to learn with, it's quite simple (lots of defaults you can use).
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
//for example (psuedo code..)
for(var i = 0; i < data.length;i++){
//Use the data variable passed in with the success function.
createNewElement(data[i]) // do something with each object in the array (see below)
}
})
Create new element
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
As you have jquery already we can use a lot of the functions easily. The element to append we can build in jquery, or just use a string in javascript containing your HTML. As you are adding in dynamic data, it makes sense to make the elements.
createNewElement(datum){
// This function creates a new element each time it is called and appends it to the
let $para = $('<p></p>') // make new <p> element
.addClass('episodetitle') // add the class property and actual classes
.text(thing.episodetitle) // set the text content of the element
//we have created "<p class='episodetitle'>This is the Title</p>"
//Alernatively we can do it all in one go
let $img = $('<img class="coverimg" src="'+datum.imagesource+'"/>')
// Now we create the container div for these 2 elements
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para) // Add the para into our div
.append($img) // append the image element into the div
$(".episodes").append($newEpisode); // append the div to the coagulate div
}
#Tobin
So now I edited my script to this:
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
let $para = $('<p></p>').addClass('episodetitle').text(thing.episodetitle)
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para)
// GETTING A ERROR :28 Uncaught SyntaxError: Identifier '$para' has already been declared. When trying to do the same for the coverimg.
let $para = $('<p></p>').addClass('coverimg').text(thing.coverimg)
let $newEpisode = $('<div></div>').addClass('coverimg')
$newEpisode.append($para)
//Append it
$(".episodes").append(newEpisode);
}
})
But now de second $para gives me an error because it's already declared...
But I made one change in the first script, changed a 'newItem' to 'newEpisode' and now it renders my layout, but none of the information in the JSON file is loaded in. And it makes 5 items, while there are supposed to be 2 'files' in the JSON file. What goes wrong here?

Mouse over the <a> tag

There is a prompt in the lower left corner When I put the mouse over the tag,
and can u tell me how to forbid this phenomenon.enter image description here
As commented, the behaviour that you wish to stop is a browser's feature.
To avoid this, you will have to simulate anchor's behaviour on your own but as you said you have many anchors and you cannot manually convert them to buttons, you can try following code:
function maskAnchors() {
var els = document.querySelectorAll('a[href]');
console.log("Anchors Found: ", els.length)
for (var i = 0; i < els.length; i++) {
els[i].setAttribute("data-url", els[i].getAttribute('href'));
els[i].removeAttribute("href");
els[i].addEventListener("click", handleClick)
}
}
function handleClick() {
var url = this.getAttribute('data-url');
window.open(url)
}
document.getElementById('btnAdd').addEventListener("click", function() {
var container = document.querySelector('.content');
var link = document.createElement('a')
link.href = "www.google.com";
link.textContent = "This is a newly added link";
container.append(link)
})
document.getElementById('btnMask').addEventListener("click", maskAnchors)
window.addEventListener('load', maskAnchors)
.maskedAnchor {
color: -webkit-link;
text-decoration: underline;
cursor: auto;
}
<div class="content">
Google
Facebook
StackOverflow
YouTube
Example
<a>blabla</a>
</div>
<button id="btnAdd">Add Anchor</button>
<button id="btnMask">Run masking</button>
Note:
Removing href will change styling. You will also have to do that manually.
This will not handle any anchors added dynamically after execution of this function. You will have to call this function again. I have optimised function to only fetch anchors that has href
Hope it helps!

How to print only a selected HTML element?

I am trying to implement a print feature in HTML. I know I can print the whole page with window.print(), but how do I print only a specific page element? For example a particular <DIV>Some text to print</DIV>.
You could use a print specific CSS stylesheet and hide everything but what you want printed.
<div class="no-print">I won't print</div><div class="something-else">I will!</div>
Just the no-print class will be hidden, but anything with a print class will show.
<style type="text/css" media="print">
.no-print { display: none; }
</style>
If you are familiar to jQuery, you can use jQuery Print Element plugin like this:
$('SelectorToPrint').printElement();
Created something generic to use on any HTML element
HTMLElement.prototype.printMe = printMe;
function printMe(query){
var myframe = document.createElement('IFRAME');
myframe.domain = document.domain;
myframe.style.position = "absolute";
myframe.style.top = "-10000px";
document.body.appendChild(myframe);
myframe.contentDocument.write(this.innerHTML) ;
setTimeout(function(){
myframe.focus();
myframe.contentWindow.print();
myframe.parentNode.removeChild(myframe) ;// remove frame
},3000); // wait for images to load inside iframe
window.focus();
}
Usage:
document.getElementById('xyz').printMe();
document.getElementsByClassName('xyz')[0].printMe();
Hope this help
Regards
Gaurav Khurana
Simple html and pure javascript works best. Parameter "this" refers to current id, so that function is universal for all ids. By using "ref.textContent" instead of "ref.innerHTML" you can extract only textual content for printing.
html body:
<div id="monitor" onclick="idElementPrint(this)">element to print
<img src="example.jpg" width="200">
</div>
pure javascript:
/*or:
monitor.textContent = "click me to print content";
const imga = new Image(200); //width
imga.src = "./example.jpg";
monitor.appendChild(imga);
*/
const idElementPrint = ref => {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
const pri = iframe.contentWindow;
pri.document.open();
pri.document.write(ref.innerHTML);
pri.document.close();
pri.focus();
pri.print();
pri.onafterprint = () => { document.body.removeChild(iframe); }
}
If you are using JQuery, you can use clone to do the following:
function printElement(e) {
var ifr = document.createElement('iframe');
ifr.style='height: 0px; width: 0px; position: absolute'
document.body.appendChild(ifr);
$(e).clone().appendTo(ifr.contentDocument.body);
ifr.contentWindow.print();
ifr.parentElement.removeChild(ifr);
}
and use like so:
printElement(document.getElementById('myElementToPrint'))
If I understood you well you can use CSS3 to print your selected HTML element.
#media print {
body.print-element *:not(.print) {
display: none;
}
}
Notice, that you just need a selector. This allows you to easily print an element or the entire page using CSS classes.
Here you can check a working example: https://jsfiddle.net/gengns/d50m8ztu/
If you're using bootstrap, just add classname d-print-none to the elements you don't want to display in print
I found a solution that doesn't have the problems other solutions have. It copies the printed element to the body, and is fairly elegant and general:
CSS:
#media print {
body *:not(.printable, .printable *) {
// hide everything but printable elements and their children
display: none;
}
}
JS:
function printElement(e) {
let cloned = e.cloneNode(true);
document.body.appendChild(cloned);
cloned.classList.add("printable");
window.print();
document.body.removeChild(cloned);
}
The only limitation is that the element loses styles it inherited from its previous parents. But it works on arbitrary elements in the document structure
If you need to print the HTML element with pure JS, you can open a window that contains only the element you want to print (without any HTML-markup).
For instance, you can print the image itself without wrapping it in any HTML by opening this image in a new window as a file.
Note: 'visible=none' doesn't actually make the window invisible, but it allows to open it as a separate window (not a tab).
afterprint event allows us to close the window when the printing dialog is closed. event.target points to the opened window instance.
Note: afterprint MUST be assigned before calling .print(), otherwise it would not be called.
let win = window.open('/absolute/image/path.jpg', '__blank', 'visible=none');
win.addEventListener('afterprint', event => event.target.close() );
win.print();
Printing an Html or a Selected Html is easy using Print.Js
Add Print.Js Library
http://printjs.crabbly.com/
<form method="post" action="#" id="printJS-form">
...
</form>
<button type="button" onclick="printJS('printJS-form', 'html')">
Print Form
</button>
Add this method
function printDiv(divName) {
let specific_element = document.getElementById(divName).innerHTML;
let original_elements = document.body.innerHTML;
document.body.innerHTML = specific_element;
window.print();
document.body.innerHTML = original_elements;
}
This implementation will create and apply an ad-hoc temporary style that hides all the elements on print media except the one that we want to print. After the printing the temporary style is removed, so your document will get back to its initial state.
Feel free to adjust the ad-hoc style (like papar size, margins, etc) to fit your needs.
/**
* #description Print the given element using browser built-in function
* #param {HTMLElement} element
*/
function printElement(element) {
if (!element) {
throw new Error(`Invalid print target element`);
}
const printWrapper = "print-wrapper";
const printElement = "print-element";
const css = `
body.${printWrapper} *:not(.${printElement}) {
visibility:hidden;
}
body.${printWrapper} .${printElement} {
width: 210mm;
height: 297mm;
left:0;
top:0;
position:fixed;
}
body.${printWrapper} .${printElement} * {
visibility:initial;
margin: 0;
}
`;
const head = document.getElementsByTagName("head")[0];
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.setAttribute("media", "print");
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
document.body.classList.add(printWrapper);
element.classList.add(printElement);
window.print();
document.body.classList.remove(printWrapper);
element.classList.remove(printElement);
head.removeChild(style);
}
The simplest way to do it is:
elem = document.getElementById('elem').outerHTML
orig = document.documentElement.outerHTML
document.documentElement.outerHTML=elem
print()
document.documentElement.outerHTML = orig
function printDomElement(element) {
element.classList.add("printCss");
let printId = "printSvgId";
let name = ".printCss";
let rules = "-webkit-print-color-adjust:exact;height:100%;width:100%;position:fixed;top:0;left:0;margin:0;";
var style = document.createElement('style');
style.id = printId;
style.media = "print";
document.getElementsByTagName('head')[0].appendChild(style);
if (!(style.sheet || {}).insertRule)(style.styleSheet || style.sheet).addRule(name, rules);
else style.sheet.insertRule(name + "{" + rules + "}", 0);
window.print();
setTimeout(() => {
element.classList.remove("printCss");
let elem = document.getElementById(printId);
if (elem) elem.remove();
}, 500);
}
Set the style of the element you want to print to position:fixed,then make it cover the whole page.
Here is another (perhaps a more modern?) solution:
<link rel="stylesheet" media="print" href="print.css">

Add CSS to <head> with JavaScript?

Is there a way to add css from a string in the javascript file to the head of a document with javascript?
Let's say we have a webpage, which has a lightbox script, this script requires a css file to function.
Now adding this css file with <link> will make the css file download even for people that don't have js enabled.
I know that I can dynamically load the css file with the script, but that also means that there will be 2 http requests, and in cases where there is little to no css in the file I find this inefficient.
So I thought to myself, what if you could put the css that you have in the css file, into the script, have the script parse the css and add it into the head, or even better just have the script add the css directly into the <head> of the document.
But I have found nothing online that suggests that this is possible, so is it possible to add css to the head with js?
Edit + SOLUTION:
I edited roryf's answer to work cross browser (except IE5)
Javascript:
function addcss(css){
var head = document.getElementsByTagName('head')[0];
var s = document.createElement('style');
s.setAttribute('type', 'text/css');
if (s.styleSheet) { // IE
s.styleSheet.cssText = css;
} else { // the world
s.appendChild(document.createTextNode(css));
}
head.appendChild(s);
}
Edit: As Atspulgs comment suggest, you can achieve the same without jQuery using the querySelector:
document.head.innerHTML += '<link rel="stylesheet" href="styles.css" type="text/css"/>';
Older answer below.
You could use the jQuery library to select your head element and append HTML to it, in a manner like:
$('head').append('<link rel="stylesheet" href="style2.css" type="text/css" />');
You can find a complete tutorial for this problem here
As you are trying to add a string of CSS to <head> with JavaScript?
injecting a string of CSS into a page it is easier to do this with the <link> element than the <style> element.
The following adds p { color: green; } rule to the page.
<link rel="stylesheet" type="text/css" href="data:text/css;charset=UTF-8,p%20%7B%20color%3A%20green%3B%20%7D" />
You can create this in JavaScript simply by URL encoding your string of CSS and adding it the HREF attribute. Much simpler than all the quirks of <style> elements or directly accessing stylesheets.
var linkElement = this.document.createElement('link');
linkElement.setAttribute('rel', 'stylesheet');
linkElement.setAttribute('type', 'text/css');
linkElement.setAttribute('href', 'data:text/css;charset=UTF-8,' + encodeURIComponent(myStringOfstyles));
This will work in IE 5.5 upwards
The solution you have marked will work but this solution requires fewer dom operations and only a single element.
If you don't want to rely on a javascript library, you can use document.write() to spit out the required css, wrapped in style tags, straight into the document head:
<head>
<script type="text/javascript">
document.write("<style>body { background-color:#000 }</style>");
</script>
# other stuff..
</head>
This way you avoid firing an extra HTTP request.
There are other solutions that have been suggested / added / removed, but I don't see any point in overcomplicating something that already works fine cross-browser. Good luck!
http://jsbin.com/oqede3/edit
A simple non-jQuery solution, albeit with a bit of a hack for IE:
var css = ".lightbox { width: 400px; height: 400px; border: 1px solid #333}";
var htmlDiv = document.createElement('div');
htmlDiv.innerHTML = '<p>foo</p><style>' + css + '</style>';
document.getElementsByTagName('head')[0].appendChild(htmlDiv.childNodes[1]);
It seems IE does not allow setting innerText, innerHTML or using appendChild on style elements. Here is a bug report which demonstrates this, although I think it identifies the problem incorrectly. The workaround above is from the comments on the bug report and has been tested in IE6 and IE9.
Whether you use this, document.write or a more complex solution will really depend on your situation.
Here's a simple way.
/**
* Add css to the document
* #param {string} css
*/
function addCssToDocument(css){
var style = document.createElement('style')
style.innerText = css
document.head.appendChild(style)
}
Here's a function that will dynamically create a CSS rule in all major browsers. createCssRule takes a selector (e.g. "p.purpleText"), a rule (e.g. "color: purple;") and optionally a Document (the current document is used by default):
var addRule;
if (typeof document.styleSheets != "undefined" && document.styleSheets) {
addRule = function(selector, rule) {
var styleSheets = document.styleSheets, styleSheet;
if (styleSheets && styleSheets.length) {
styleSheet = styleSheets[styleSheets.length - 1];
if (styleSheet.addRule) {
styleSheet.addRule(selector, rule)
} else if (typeof styleSheet.cssText == "string") {
styleSheet.cssText = selector + " {" + rule + "}";
} else if (styleSheet.insertRule && styleSheet.cssRules) {
styleSheet.insertRule(selector + " {" + rule + "}", styleSheet.cssRules.length);
}
}
}
} else {
addRule = function(selector, rule, el, doc) {
el.appendChild(doc.createTextNode(selector + " {" + rule + "}"));
};
}
function createCssRule(selector, rule, doc) {
doc = doc || document;
var head = doc.getElementsByTagName("head")[0];
if (head && addRule) {
var styleEl = doc.createElement("style");
styleEl.type = "text/css";
styleEl.media = "screen";
head.appendChild(styleEl);
addRule(selector, rule, styleEl, doc);
styleEl = null;
}
};
createCssRule("body", "background-color: purple;");
In one call:
document.head.appendChild(Object.assign(document.createElement("style"), {textContent: `
select, button, input, details, summary { cursor: pointer }
input { padding: 0.5rem }
button, select { margin: 0.5rem }
#media (max-width:640px) { button { width: 100% } i {display: block } }
`
}))
Shortest One liner:
const addCSS = css => document.head.appendChild(document.createElement("style")).innerHTML = css;
// Usage:
addCSS("body{background:red}");
Late to the party, quite similar to all solution but appends only once the script to the head:
export const injectHeadCss = () => {
let style: HTMLStyleElement | null = document.head.querySelector('style[my-style]');
if (style !== null) {
return;
}
style = document.createElement('style');
style.setAttribute('my-style', '');
style.innerHTML = `
.class1 {
background: pink;
}
.class2 {
background: purple;
}
`;
document.head.append(style);
};
Maximizing compatibility, working for most things made 2009-2022 and likely beyond. This solution is intentionally not made with ES6 etc; using an arrow function, let-variable, append (2014) etc.
This short version adds styling to the head-section of a web page and can also be done via the DOM to access the head-section to maximize compatibility further - since querySelector wasn't widely adapted until 2009.
Note that innerHTML / write nowadays isn't recommended for production.
Just copy+paste it into the console to try it out and a page like this gets some nice additions;
function ahsf(styling){ document.querySelector('head').innerHTML+="<style>"+ styling +"</style>";}
//Called with
ahsf(" * { border: 1px dashed #f09 !important; } ");

Categories

Resources