codemirror - detect and create links inside editor - javascript

I am using codemirror, configured to display javascript.
I have code like this:
...
var ref = 'http://www.example.com/test.html';
var ref2 = 'http://www.example.com/test2.html';
...
When displaying the editor it would be great if I could click on the links that might be present in the editor. The link would open the page on a different tab obviously.
is there an easy way to achieve this ?

Not really easy, but what you'd do is:
Write an overlay mode that recognizes such links. Basically, this is a mode that spits out a custom token type when it finds something that looks like a link, and null otherwise. You can use the simple mode addon to make this easier. You can use this token type's CSS class (for example "link" becomes cm-link) to style your links.
Make your editor use your overlay by calling the addOverlay method.
Register a mousedown event handler on your editor (instance.getWrapperElement().addEventListener(...)).
In this handler, check whether the event's target has the link CSS class. If it does, the user is clicking a link.
If so, use the coordsChar method, using the coordinates from your mouse event, to find the position in the document that was clicked. Extract the actual link from the document text around that position, and follow it.
(Or, even better, instead of directly interfering with the click, which might be intended to put the cursor in the link or select it, show a widget containing a regular link whenever the cursor is inside of link text.)

Here is a solution I came up with:
demo here: plunkr
code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css"/>
<style>
html, body { height:100%; }
.CodeMirror .cm-url { color: blue; }
</style>
</head>
<body>
<script>
var cm = CodeMirror(document.body);
cm.setValue('hover over the links below\nlink1 https://plnkr.co/edit/5m31E14HUEhSXrXtOkNJ some text\nlink2 google.com\n');
hyperlinkOverlay(cm);
function hoverWidgetOnOverlay(cm, overlayClass, widget) {
cm.addWidget({line:0, ch:0}, widget, true);
widget.style.position = 'fixed';
widget.style.zIndex=100000;
widget.style.top=widget.style.left='-1000px'; // hide it
widget.dataset.token=null;
cm.getWrapperElement().addEventListener('mousemove', e => {
let onToken=e.target.classList.contains("cm-"+overlayClass), onWidget=(e.target===widget || widget.contains(e.target));
if (onToken && e.target.innerText!==widget.dataset.token) { // entered token, show widget
var rect = e.target.getBoundingClientRect();
widget.style.left=rect.left+'px';
widget.style.top=rect.bottom+'px';
//let charCoords=cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY }));
//widget.style.left=(e.pageX-5)+'px';
//widget.style.top=(cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY })).bottom-1)+'px';
widget.dataset.token=e.target.innerText;
if (typeof widget.onShown==='function') widget.onShown();
} else if ((e.target===widget || widget.contains(e.target))) { // entered widget, call widget.onEntered
if (widget.dataset.entered==='true' && typeof widget.onEntered==='function') widget.onEntered();
widget.dataset.entered='true';
} else if (!onToken && widget.style.left!=='-1000px') { // we stepped outside
widget.style.top=widget.style.left='-1000px'; // hide it
delete widget.dataset.token;
widget.dataset.entered='false';
if (typeof widget.onHidden==='function') widget.onHidden();
}
return true;
});
}
function hyperlinkOverlay(cm) {
if (!cm) return;
const rx_word = "\" "; // Define what separates a word
function isUrl(s) {
if (!isUrl.rx_url) {
// taken from https://gist.github.com/dperini/729294
isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
// valid prefixes
isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.'];
// taken from https://w3techs.com/technologies/overview/top_level_domain/all
isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi'];
}
if (!isUrl.rx_url.test(s)) return false;
for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true;
for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true;
return false;
}
cm.addOverlay({
token: function(stream) {
let ch = stream.peek();
let word = "";
if (rx_word.includes(ch) || ch==='\uE000' || ch==='\uE001') {
stream.next();
return null;
}
while ((ch = stream.peek()) && !rx_word.includes(ch)) {
word += ch;
stream.next();
}
if (isUrl(word)) return "url"; // CSS class: cm-url
}},
{ opaque : true } // opaque will remove any spelling overlay etc
);
let widget=document.createElement('button');
widget.innerHTML='→'
widget.onclick=function(e) {
if (!widget.dataset.token) return;
let link=widget.dataset.token;
if (!(new RegExp('^(?:(?:https?|ftp):\/\/)', 'i')).test(link)) link="http:\/\/"+link;
window.open(link, '_blank');
return true;
};
hoverWidgetOnOverlay(cm, 'url', widget);
}
</script>
</body>
</html>

Here is a starting point, but it need to be improved.
LIVE DEMO
function makeHyperLink(innerTextInside)
{
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
if(all[i].innerText == innerTextInside)
{
all[i].innerHTML="<a target='_blank' href='https://google.com'>THIS IS A LINK TO GOOGLE</a>"
}
}
}

Related

Popunder run automatically

I have a code that inserts a popunder into all the links on my page.
However, I need something that makes this popunder / tabunder run automatically, regardless of the click.
I've tried in many ways but I can't.
Can someone help me?
window.onload = function() {
var puURL = 'http://google.com';
var puTS = Math.round(+new Date()/1000);
console.log('T.'+localStorage.puTS+'/'+puTS);
if (typeof localStorage.puTS == 'undefined' || parseInt(localStorage.puTS) <= (puTS - 3600)) {
var links = document.getElementsByTagName('a');
for(var i = 0, len = links.length; i < len; i++) {
links[i].onclick = function (e) {
var puHref = this.getAttribute("href");
var puTarget = this.getAttribute("target");
if (puHref !== '#' && puHref !== 'javascript:void(0)') {
e.preventDefault();
if (puTarget == '_blank') {
window.open(window.location.href);
}
window.open(puHref);
window.location.href = puURL;
localStorage.puTS = puTS;
}
}
}
}
};
I have placed your script locally under the HEAD Tag section and the function is triggered when I open the HTML file. I assume that the issue lays in the script placement.
If your script is stored outside the project (is external), make sure that you navigate to the correct root and double-check for spelling. Here is an example:
index.html
<!DOCTYPE html>
<html>
<head>
<script src="project/javascript_folder/myscript.js"></script>
</head>
<body>
...
</body>
</html>
You can check out W3Schools File Paths for more detail.
If you open your browsers DEV-TOOLS (by pressing the Right-Click button on your mouse while you hover over the page) and navigate to the console section, you should see the successful output from your function:
In my case, it is T.undefined/... where "..." represents a randomly generated number in the length of 10.

Get Href Link; if JPG to skip

I've created a loader for my website (the whole front end is custom,so as of right now i can edit about 95% of everything I have except for woocommerce plugin).
Super simple one, it follows this logic, if the anchor is an # or the page itself it wont do anything (which is what I wanted) but the woocommerce plugin to generate my image gallery is a link that isn't the page itself or a #. Which means I need to collect the path-name of the extension that if it ends on jpg png or any image file to continue; and skip over the rest of the animation and allow the plugin to run its course.
Ive use Barba JS, SWUP and other animations with woocommerce and this is the only one that doesnt interrupt or have so many conditions with woocommerce.
function fadeInPage() {
if (!window.AnimationEvent) { return; }
var fader = document.getElementById('fader');
fader.classList.add('fade-out');
}
document.addEventListener('DOMContentLoaded', function() {
if (!window.AnimationEvent) { return }
var anchors = document.getElementsByTagName('a');
******* for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].hostname !== window.location.hostname || anchors[idx].pathname === window.location.pathname) *******
{
continue;
}
anchors[idx].addEventListener('click', function(event) {
var fader = document.getElementById('fader'),
anchor = event.currentTarget;
var listener = function() {
window.location = anchor.href;
fader.removeEventListener('animationend', listener);
};
fader.addEventListener('animationend', listener);
event.preventDefault();
fader.classList.add('fade-in');
});
}
});
window.addEventListener('pageshow', function (event) {
if (!event.persisted) {
return;
}
var fader = document.getElementById('fader');
fader.classList.remove('fade-in');
});
I starred what i need changed. the animation works, the page transition works. I need the animation to recognize if the a tag ends with an jpg or png to skip and not do the animation and treat the link as if the animation wasn't there.
Never used woocommerce so I don't totally understand the use case, but you can get the file extension of a link like so:
for (var idx = 0; idx < anchors.length; idx += 1) {
let fileType = anchors[idx].href.split('.').pop();
//Do whatever
}
Or if you want to compare it to a preset list of extensions you can use a regex:
for (var idx = 0; idx < anchors.length; idx += 1) {
if (anchors[idx].href.match(/\.(jpg|png)$/)) {
//Do whatever
}
}

Stop javascript redirection on href="javascript:void"

I've been using a script which prefixes redirect.php on "onmouseevent" triggers. But I don't want it on certain sites, like google etc. Please see the code below:
var matchavailable = 0;
var disallowinks = "google,microsoft,yahoo";
$n("a").mousedown(function () {
var linkArray = disallowlinks.split(',');
for (var i = 0; i < linkArray.length; i++) {
if ($n(this).attr('href').indexOf(linkArray[i]) > 0) {
matchavailable = 1;
break;
}
else {
matchavailable = 0;
}
}
if (matchavailable == 0) {
if ($n(this).hasClass('linked')) {
}
else
{
$n(this).attr('href', "http://yoursite.com/redirect.php?q=" + encodeURIComponent($n(this).attr('href')));
$n(this).attr('target', '_blank');
$n(this).addClass("linked");
}
}
});
The javascript runs so far so good on all anchor tags. Just that, I have a popup which I show on my website and when I try to close the popup (X marks the spot), the redirect.php gets prefixed on that as well.
So my question is, how do we disallow the script to NOT run on anchor tags with the value starting with "javascript" ?
For example, i don't want it to run on:
<a href="javascript:void"> or <a href="any random parameter">
How do I go about this? WOuld be great to get some help

Javascript modification of CSS class url change for background image

I am trying to get a background image to change based on a setting in the database, for right now I'm just trying to get a a way of simply modifying the image used without using the data base but I'm hitting a snag. Without the javascript the image appears fine, with the javascript it is simply not there; leading me to believe there is an issue finding the path written to the css.
Thanks in advance for any help!
<script type="text/javascript" language="javascript">
function changecss(myclass, element) {
var CSSRules
var link1 = "url('../../graphics/MainMenuBG0.gif')";
var link2 = "url('../../graphics/MainMenuBG1.gif')";
if (document.all) {
CSSRules = 'rules';
}
else if (document.getElementById) {
CSSRules = 'cssRules';
}
for (var i = 0; i < document.styleSheets[0][CSSRules].length; i++) {
if (document.styleSheets[0][CSSRules][i].selectorText == myclass) {
if (document.styleSheets[0][CSSRules][i].style[element] == link1) {
document.styleSheets[0][CSSRules][i].style[element] = link2;
} else {
document.styleSheets[0][CSSRules][i].style[element] = link1;
}
}
}
}
</script>
You should try something like this :
if (document.styleSheets[0][CSSRules][i].style.getProperty('background-image') == link1) {
document.styleSheets[0][CSSRules][i].style.setProperty('background-image', link2);
} else {
document.styleSheets[0][CSSRules][i].style.setProperty('background-image', link1);
}

Changing Attribute with Javascript-Header Problems

The following HTML displays a fancy font on my site, due some alterations I made to <h2>
<section id="content">
<article>
<h2 id="titletext">Welcome to <span>Pomona High School!</span></h2>
<p id="infotext" style="width: 773px; height: 28px;" >Welcome to the new Pomona High School site! Please give us feedback!</p>
<br />
</article>
</section>​
This displays quite fine in the site.
When the user now goes to the taskbar and chooses one of the submenu items, the <h2> text will change to a specified string value. I went into the Javascript editor and produced the following.
window.onhashchange = function() { //when the hash changes (the '#' part)
var loc = window.location + ""; //get the current location (from the address bar)
var curHash = loc.substr(loc.lastIndexOf("#")); //get what's after the '#'
if (curHash == "#mission") { //else if it's #mission
document.getElementById('titletext').innerHTML = 'Mission Statement';
}
else {
document.getElementById('titletext').innerHTML = 'Welcome to Pomona High School';
}
};​
Linking one of the menu items to #mission, I was succesful in changing the text. But the font changed to the default <h2> font.
I need help on how to bring my custom font onto strings in Javascript. Thanks in advance!
CSS stylsheet for <h2>:
h2 {
font-size: 30px;
line-height: 1.2em;
font-weight: normal;
color: #212222;
margin-bottom: 22px;
}
h2 span {
color: #8a8a8a;
}
And here's the two custom font files (too big to copy and paste to Stack Overflow):-
Regular Font
Light Font
Your code is actually replacing
Welcome to <span>Pomona High School!</span>
with
Welcome to Pomona High School!
Notice, no element. Just set it with the span tag, and you will be fine.
Source: MDN Docs
Here's what MDN has to say about this:
The hashchange event fires when a window's hash changes (see
location.hash).
Syntax:-
window.onhashchange = funcRef;
<body onhashchange="funcRef();">
window.addEventListener("hashchange", funcRef, false);
I think that passing function() { ... } is a function reference but could you try defining the function first and then passing a named reference? The code would go:
function hashChange() { //when the hash changes (the '#' part)
var loc = window.location + ""; //get the current location (from the address bar)
var curHash = loc.substr(loc.lastIndexOf("#")); //get what's after the '#'
if (curHash == "#mission") { //else if it's #mission
document.getElementById('titletext').innerHTML = 'Mission Statement';
}
else {
document.getElementById('titletext').innerHTML = 'Welcome to Pomona High School';
}
};
window.onhashchange = hashChange;
​
OK, I'm confused. There must be something else going on as it's working for me in this JSFiddle...
Your code removes the <span> in the <h2> on hash change which was presumably giving the styling. So it should really be:
window.onhashchange = function() { //when the hash changes (the '#' part)
var loc = window.location + ""; //get the current location (from the address bar)
var curHash = loc.substr(loc.lastIndexOf("#")); //get what's after the '#'
if (curHash == "#mission") { //else if it's #mission
document.getElementById('titletext').innerHTML = '<span>Mission Statement</span>';
}
else {
document.getElementById('titletext').innerHTML = 'Welcome to <span>Pomona High School</span>';
}​
}
Also, I think you're mixing up the if and else statements. This:
else if(curHash == "#mission") {
...
}
else {
...
}
should really be:
if(curHash == "#mission") {
...
}
else if {
...
}

Categories

Resources