Develop vs code extension to edit text - javascript

I want to build an extension that edits all the links in a file in the editor. If should be something like this
BEFORE:
<img src="assets/images/avatars/avatar-1.jpg" alt="">
<link rel="stylesheet" href="assets/css/icons.css">
<link rel="stylesheet" href="assets/css/uikit.css">
<link rel="stylesheet" href="assets/css/style.css">
AFTER:
<img src="{% static 'assets/images/avatars/avatar-1.jpg' %}" alt="">
<link rel="stylesheet" href="{% static 'assets/css/icons.css' %}">
<link rel="stylesheet" href="{% static 'assets/css/uikit.css' %}">
<link rel="stylesheet" href="{% static 'assets/css/style.css' %}">
This is the code of my extension.js file so far
const vscode = require('vscode');
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('auto-django.autoDjango', function () {
const editor = vscode.window.activeTextEditor
const selection = editor.selection
const text = editor.document.getText(selection)
var regexp = /<img[^>]+src\s*=\s*['"]([^'"]+)['"][^>]*>/g;
var match = regexp.exec(text);
var src = match[1];
const newText = `{% static '${src}' %}`
editor.edit(builder => builder.replace(selection, newText))
});
context.subscriptions.push(disposable);
}
And all this code does is that it takes the first image src link and changes it to the edited link, that is good, but it also replaces it with the whole text in the editor.
But what i want to do is that it should just replace with each of the links in the editor.
Any help will be appreciated.
Thanks

First thing I see:
editor.document.getText(some Range) takes a Range not a Selection - that is why it is returning all the document text - it does that when the argument is invalid.
editor.document.getText(new vscode.Range(selection.start, selection.end))
should get you the text of the selection.

Related

How to conditionally load file?

Could somebody suggest me a way for loading css or javascript file conditionally i.e only if url is accessible?
for example on my page I have the following files:
<html>
...
<link rel="stylesheet" type="text/css" href="https://service.test/css/a.css"/>
<script type="text/javascript" src="https://services.test/js/a.js"></script>
...
</html>
Is there any way to check if https://service.test/css/a.css is accessible then if yes load this resource (same for https://services.test/js/a.js)?
You could try something like this. but it will only work for the stylesheets that are in head section.
<html>
<link rel="stylesheet" type="text/css" href="https://service.test/css/a.css"/>
<body>
</body>
<script>
// you will have to manuall define the pairs (keys are stylesheets and values are scripts you want to load)
const pairs = {
"https://service.test/css/a.css": "https://services.test/js/a.js"
}
let styles = document.querySelectorAll("link[rel='stylesheet'][type='text/css'][href]");
styles.forEach(s => {
if(pairs[s.href]){
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = pairs[s.href];
document.getElementsByTagName('head')[0].appendChild(script);
}
});
</script>
</html>

Remove the link tag if it contains a particular string - javascript

I need to strip all the tags containing a specific string,
How can I achieve this in javascript?
this is the string
<link rel="stylesheet" href="https://REMOVEME">
<link rel="stylesheet" href="https://ccc">
<link rel="stylesheet" href="https://abc/REMOVEME">
<div>yes</div>
and this the result
<link rel="stylesheet" href="https://ccc">
<div>yes</div>
Such tasks are better not done with regular expressions.
Instead use the DOM interface available to JavaScript, for instance with this ES6 function:
function removeLinks(html, match) {
var container = document.createElement('span');
container.innerHTML = html;
Array.from(container.querySelectorAll('link[href*=' + CSS.escape(match) + ']'))
.forEach( link => link.parentNode.removeChild(link) );
return container.innerHTML;
}
// Sample input
var html = '<link rel="stylesheet" href="https://REMOVEME">' +
'<link rel="stylesheet" href="https://ccc">' +
'<link rel="stylesheet" href="https://abc/REMOVEME">' +
'<div>yes</div>';
// Remove links that match REMOVEME
html = removeLinks(html, 'REMOVEME');
// Output result
console.log(html);
htmlString.replace(/<link[^>]*href="[^>]*REMOVEME[^>]*"[^>]*>/gi,'')

Get the HTML body of a <link> element with an ID via jQuery

I have the following in the header of my site
<link rel="stylesheet" id="swp-google-font-headline-css" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&ver=4.5.3" type="text/css" media="all">
I want to retrieve the full <link> content as shown above with jquery.
I tried
var a = jQuery('#swp-google-font-headline-css').get(0);
console.log(a, typeof a)
But the console output displayed the actual content, but it seem to be an object rather than a string and i specifically want it to be a string.
See demo https://jsfiddle.net/collizo4sky/qh6dnmg9/
Please help
Use outerHTML property of the Element
The outerHTML attribute of the element DOM interface gets the serialized HTML fragment describing the element including its descendants.
var a = jQuery('#swp-google-font-headline-css').get(0).outerHTML;
console.log(a,typeof a)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<link rel="stylesheet" id="swp-google-font-headline-css" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&ver=4.5.3" type="text/css" media="all">ffff
Maybe this is what you want:
var a = jQuery('#swp-google-font-headline-css').clone();
console.log(a[0]);
You can use innerHTML property on your a variable.
$(document).ready(function() {
var a = $('#swp-google-font-headline-css').get(0);
console.log(a.innerHTML);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" id="swp-google-font-headline-css" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&ver=4.5.3" type="text/css" media="all">
There are two means by which this can be achieved, the first – as already shown – is to use the Node.outerHTML property, which in your posted code can by achieved like so:
var a = jQuery('#swp-google-font-headline-css').get(0).outerHTML;
console.log(a, typeof a)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" id="swp-google-font-headline-css" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&ver=4.5.3" type="text/css" media="all">ffff
And the other approach is more of a shim, and achieved by appending the found-element, here the <a>, to another element and accessing the innerHTML of that parent element:
function getElementHTML(node) {
var wrapper = document.createElement('div');
wrapper.appendChild(node);
return wrapper.innerHTML;
}
console.log($('#swp-google-font-headline-css').get(0));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" id="swp-google-font-headline-css" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&ver=4.5.3" type="text/css" media="all">ffff
You can use outerHTML.
var b = a.outerHTML;
Demo: https://jsfiddle.net/qh6dnmg9/2/

Javascript: Change <link rel="stylesheet"> media attribute

If a user visits my website from a desktop computer, in my HTML I call a CSS style like this:
<link rel="stylesheet" type="text/css" href="desktop.css" media="all and (min-device-width:768px)" />
Using plain javascript (no framework) how can I change the media attribute from "all and (min-device-width:768px)" to "all and (min-width:768px)" ?
Thank you!
Give it an id and change the attribute value:
<link id="foo" rel="stylesheet" type="text/css" href="desktop.css" media="all and (min-device-width:768px)" />
And the jQuery part:
$("#foo").attr("media", "all and (min-width:768px)");
JSBIN
No jQuery version
document.querySelector("#foo").setAttribute("media", "all and (min-width:768px)");
// or
document.getElementById("foo").setAttribute("media", "all and (min-width:768px)");
if you don't have access to source code and can't set id for link, first you have to do is to filter links by media attribute. Then just set new attribute value to filtered:
var links = document.getElementsByTagName('link');
for(var i = 0; i < links.length; i++){
var link = links[i];
if(link.getAttribute('media') === 'all and (min-device-width:768px)')
link.setAttribute('media', 'all and (min-width:768px)');
}
fiddle

How to append straight markup to HEAD without jQuery?

I have a string containing HTML for stylesheets (created via the Rails asset pipeline), and I need to append this to the head and have the stylesheets actually load, in all major browsers. The string looks like this:
<link href="https://www.v.me/assets/core-28020ec7a202f8bc47a5d70d5aeb8477.css" media="screen" rel="stylesheet" type="text/css" />
<link href="https://www.v.me/assets/widgets-d4c93376a05ffe6d726371b89bc58731.css" media="screen" rel="stylesheet" type="text/css" />
<link href="https://www.v.me/assets/flowplayer-minimalist-3254ab41f4865c79282728f0012bb98d.css" media="screen" rel="stylesheet" type="text/css" />
<link href="https://www.v.me/assets/main-12765c4980ba6d109852c52830b34586.css" media="screen" rel="stylesheet" type="text/css" />
I need to do this without using jQuery. Is this possible?
I wish I had the URLs in an array, but I don't. As a last resort, I could consider using a regex to parse out the URLs, but I'd like to avoid this.
var pHead = document.getElementsByTagName('head')[0];
pHead.innerHTML = pHead.innerHTML + assetsString;
If CSSTags is a string containing the HTML for all your link tags then you can use:
document.getElementsByTagName('head')[0].innerHTML += CSSTags;
function addLink(linkURL,rel,type,media){
var link = document.createElement('link');
link.href = linkURL;
link.rel = rel? rel: 'stylesheet';
link.media = media ? media: 'screen';
link.type = type ? type: 'text/css';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(link, s)
}
addLink('https://www.v.me/assets/core-28020ec7a202f8bc47a5d70d5aeb8477.css')
There are few things which might be not obvious here, like inserting after the script tag instead of body or head. Refer here for more information
You could try this:
document.head.innerHTML +=
'<link href="https://www.v.me/assets/core-28020ec7a202f8bc47a5d70d5aeb8477.css" media="screen" rel="stylesheet" type="text/css" />'
+'<link href="https://www.v.me/assets/widgets-d4c93376a05ffe6d726371b89bc58731.css" media="screen" rel="stylesheet" type="text/css" />'
+'<link href="https://www.v.me/assets/flowplayer-minimalist-3254ab41f4865c79282728f0012bb98d.css" media="screen" rel="stylesheet" type="text/css" />'
+'<link href="https://www.v.me/assets/main-12765c4980ba6d109852c52830b34586.css" media="screen" rel="stylesheet" type="text/css" />'
;
For old browsers, first use
if(!document.head) document.head = document.getElementsByTagName('head')[0];
Edit: #Sriharsha warned that the code above could download again all the resources. That doesn't happen on Firefox 27, but if you want to avoid this for sure, you could use:
var tmpHead = document.implementation.createHTMLDocument().head;
tmpHead.innerHTML = myString;
for (var i=0, tmpLink; tmpLink = tmpHead.childNodes[i]; ++i) {
document.head.appendChild( tmpLink.cloneNode(false) );
}
Note that document.implementation.createHTMLDocument only works on new browsers.

Categories