Can't download or copy SVG without body element - javascript

How do I successfully copy to clipboard the SVG content on this page?
https://cdn.dribbble.com/assets/dribbble-ball-icon-e94956d5f010d19607348176b0ae90def55d61871a43cb4bcb6d771d8d235471.svg
I get an error at the select() method that looks like this:
Uncaught TypeError: el.select is not a function
at <anonymous>:1:4
This is my code at the moment that can be run in the console.
function copyClip() {
const docEl = document.documentElement
const string = new XMLSerializer().serializeToString(docEl)
const el = document.createElement('textarea')
docEl.insertAdjacentElement('beforeend', el)
el.value = string
el.select()
document.execCommand('copy')
}
copyClip()

One answer to this is to use a different execution of copying to clipboard but I don't understand why the select method in the original question isn't working. This function works:
const docEl = document.documentElement
const string = new XMLSerializer().serializeToString(docEl)
navigator.clipboard.writeText(string).then(
function () {
alert('The SVG was copied to your clipboard.')
},
function (err) {
alert('Could not copy:', err)
}
)

Related

Uncaught ReferenceError: variable is not defined javascript

I want to create a DOM element from an HTML string. Inside that string, I have a button that should call a global function called downloadFile with predefined arguments.
My first try:
<button onclick="downloadFile(${message_result})">Download</button>
But this failed to work.
Whole code looks like this
function downloadFile(result){
console.log(result)
}
(() => {
const msg = {user: 'User', message: 'Message', result: {}} // any
var markup = `
<h4>${msg.user}</h4>
<p>${msg.message}</p>
<button onclick="downloadFile(message_result)">Download</button>
`
document.body.innerHTML = markup
})()
the error:
Uncaught ReferenceError: message_result is not defined
at HTMLButtonElement.onclick
any suggestions how i can pass a variable into my function
Let's first solve your problem then talk about a better approach.
If we assume msg.result is a string: You need to wrap it with quote marks.
<button onclick="downloadFile('${message_result}')">Download</button>`;
But if your msg.result is not a simple string or you want to take the right path to the solution, then we need to move next approach.
// This is your downloadFile function
const downloadFile = (data) => {
console.log(data)
}
// This function creates download buttons
const createDownloadButton = (response) => {
const markup = `
<h4>${response.user}</h4>
<p>${response.message}</p>
<button>Download</button>
`
const container = document.createElement("div")
container.innerHTML = markup;
// Here, we assign "click" functionality dynamically even before we inject the element into DOM
container.getElementsByTagName("button")[0].addEventListener('click', () => {
downloadFile(response.result)
})
document.body.append(container)
}
// Fetch your response from an external service
const msg = {
user: 'Username',
message: 'Message',
result: {
file: {
link: 'https://stackoverflow.com'
}
}
}
// Call function to create download button
createDownloadButton(msg)
If message_result is a variable, like msg.message, then you need to reference it similarly.
var markup=`
<h4>${msg.user}</h4>
<p>${msg.message}</p>
<button onclick="downloadFile('${message_result}')">Download</button>`;

Selecting an html node's text content with htmlparser2 in Node.js

I want to parse some html with htmlparser2 module for Node.js. My task is to find a precise element by its ID and extract its text content.
I have read the documentation (quite limited) and I know how to setup my parser with the onopentag function but it only gives access to the tag name and its attributes (I cannot see the text). The ontext function extracts all text nodes from the given html string, but ignores all markup.
So here's my code.
const htmlparser = require("htmlparser2");
const file = '<h1 id="heading1">Some heading</h1><p>Foobar</p>';
const parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if (attribs.id === "heading1"){
console.log(/*how to extract text so I can get "Some heading" here*/);
}
},
ontext: function(text){
console.log(text); // Some heading \n Foobar
}
});
parser.parseComplete(file);
I expect the output of the function call to be 'Some heading'. I believe that there is some obvious solution but somehow it misses my mind.
Thank you.
You can do it like this using the library you asked about:
const htmlparser = require('htmlparser2');
const domUtils = require('domutils');
const file = '<h1 id="heading1">Some heading</h1><p>Foobar</p>';
var handler = new htmlparser.DomHandler(function(error, dom) {
if (error) {
console.log('Parsing had an error');
return;
} else {
const item = domUtils.findOne(element => {
const matches = element.attribs.id === 'heading1';
return matches;
}, dom);
if (item) {
console.log(item.children[0].data);
}
}
});
var parser = new htmlparser.Parser(handler);
parser.write(file);
parser.end();
The output you will get is "Some Heading". However, you will, in my opinion, find it easier to just use a querying library that is meant for it. You of course, don't need to do this, but you can note how much simpler the following code is: How do I get an element name in cheerio with node.js
Cheerio OR a querySelector API such as https://www.npmjs.com/package/node-html-parser if you prefer the native query selectors is much more lean.
You can compare that code to something more lean, such as the node-html-parser which supports simply querying:
const { parse } = require('node-html-parser');
const file = '<h1 id="heading1">Some heading</h1><p>Foobar</p>';
const root = parse(file);
const text = root.querySelector('#heading1').text;
console.log(text);

selectNodes function of ActiveXObject does not work in IE 11

I am trying to get this piece of code written in Javascript to work in IE 11. But when I try to access the length of the node it gives me 0. I am not sure why the below code is not able to find out the <somenode> node in XML. Does anyone have any idea?
try {
doc = new ActiveXObject("Msxml2.DOMDocument.6.0");
var xml_string = '<somenode><child>Hello</child></somenode>
<somenode><child>good bye</child></somenode>';
doc.loadXML(xml_string);
doc.setProperty("SelectionLanguage", "XPath");
var node = doc.selectNodes("/somenode");
console.log("node is "+node.length);
}
catch (e)
{
console.log("inside catch"+e);
}
NOTE: Your XML doesn't have a root element. I've added <xml> as the root.
try {
doc = new ActiveXObject("Msxml2.DOMDocument.6.0");
var xml_string = '<xml><somenode><child>Hello</child></somenode>
<somenode><child>good bye</child></somenode></xml>';
doc.loadXML(xml_string);
doc.setProperty("SelectionLanguage", "XPath");
var node = doc.selectNodes("/xml/somenode");
console.log("node is "+node.length);
}
catch (e)
{
console.log("inside catch"+e);
}

How to make Gnome Shell extension query for changes

I've been battling the horrendous Gnome API documentation and came up with this extension:
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const GLib = imports.gi.GLib;
let label;
function init() {
label = new St.Bin({ style_class: 'panel-label' });
let stuff = GLib.spawn_command_line_sync("cat /home/user/temp/hello")[1].toString();
let text = new St.Label({ text: stuff });
label.set_child(text);
}
function enable() {
Main.panel._rightBox.insert_child_at_index(label, 0);
}
function disable() {
Main.panel._rightBox.remove_child(label);
}
This should read whatever is in the hello file and display it in the top panel. However, if I change the contents of the hello file, I have to restart Gnome for that new content to be shown. Now, surely there is a way to do this dynamically but I just couldn't find anything in the documentation. The message in the panel should basically always mirror whatever is in the file. Any ideas how to do this?
You'll want to obtain a Gio.File handle for your hello file, and then monitor it:
let helloFile = Gio.File.new_for_path('/home/user/temp/hello');
let monitor = helloFile.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', function (file, otherFile, eventType) {
// change your UI here
});
This worked for me. It will refresh the label value each 30 seconds.
Add the following import
const Mainloop = imports.mainloop;
In your init method
Mainloop.timeout_add(30000, function () {
let stuff = GLib.spawn_command_line_sync("your_command")[1].toString();
let label = new St.Label({ text: stuff });
button.set_child(label);return true});

selectSingleNode overwrite/override crossbrowser

basically ive been tasked with fixing an none cross browser application. problem is its over use of the .selectSingleNode function. (which ofc is IE only).
i have a replacement being:
function selectOneNode(key, node) {
try {
Response = node.selectSingleNode(key);
}
catch (err) {
var xpe = new XPathEvaluator();
var nsResolver = xpe.createNSResolver(node.ownerDocument == null ? node.documentElement : node.ownerDocument.documentElement);
var results = xpe.evaluate(key, node, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
//Response.ErrorNumber = results.singleNodeValue.text.toString().ToInt();
Response = results.singleNodeValue;
}
return Response;
}
but this .selectSingleNode function is used well over 2000 times in many files, but have no idea how to override the .selectSingleNode function, so i don't need change every instance.
any help?
If u want to override some function you can just write it once again. I've had similar problem but with alert function. I've just done such thing:
function alert(){
//custom code goes here
}

Categories

Resources