space or not outputting in jQuery - javascript

I have the following being extracted from an XML and being put into a jQuery variable.
links.append($("<a href='"+alink+"'></a> ").html(desc));
...however the does not output onto the page. I need this to separate the hrefs on output
I have also tried
links.append($("<a href='"+alink+"'></a>").html(desc));
links.append($(" "));
Many thanks!

$("<a href='"+alink+"'></a> ")
Yeah, that's actually only creating the <a> element, and discarding the nbsp. When you pass a string into the $() function that looks like(*) HTML, jQuery creates the stretch of markup between the first < in the string and the last >. If you've got any leading or trailing content outside those, it gets thrown away(**). You could fool jQuery by saying:
$("<a href='"+alink+"'></a> <!-- don't ignore me! -->")
This doesn't seem to be documented anywhere, makes no sense whatsoever, and might be considered a bug, but it has been jQuery's normal behaviour for some time so it's probably not going away.
When you pass an HTML string to the append function (and other manipulation methods) directly instead of via the $ function, this behaviour does not occur. So:
links.append("<a href='"+alink+"'></a> ");
actually does keep the space. But a better way forward is to stop throwing HTML strings about, so you don't have to worry about alink containing ', < or & characters either, and work in a more DOM style:
var link= $('<a/>');
link.attr('href', alink);
link.html(desc);
links.append(link);
links.append('\xA0');
Or, more concisely, using jQuery 1.4's props argument shortcut:
links.append($('<a/>', {href: alink, html: desc}));
links.append('\xA0');
assuming that desc is really something that should contain HTML markup; if not, use text instead.
(I used \xA0, the JavaScript string literal way to include a character U+00A0 NON-BREAKING SPACE as it is a whole two characters shorter than the HTML entity reference. Woohoo!)
(*: how does it tell that a string is HTML? Why, by checking to see if there's a < and > character in it, in that order, of course. Meaning it'll get fooled if you try to use a selector that has those characters in. Brilliant, jQuery, brilliant.(***))
(**: why? see line 125 of jQuery 1.4.2. It builds the HTML fragment from match[1]—the group from the first < to the last > in quickExpr—and not the original string or match[0].)
(***: I'm being sarcastic. The insane over-overloading of the $ function is one of jQuery's worst features.)

You better style with css, something like :
links.append($("<a class='link' href='"+alink+"'></a>").html(desc));
in css :
a.link {
padding-left : 5px ;
padding-right : 5px ;
}

you could try
 

Related

Why are Javascript attribute query selectors valid when missing the end bracket?

After reviewing MDN's Document.querySelector() docs, which points to the MDN CSS Attribute selectors doc for defining an attribute selector, which points to the W3C's Attribute selectors docs, I haven't been able to understand why an attribute selector with a missing end bracket is valid.
Some examples of valid attribute query selectors with the end bracket omitted:
// This question's title
const t1 = document.querySelector("[id='question-header'")
console.log("t1", t1)
// Even works when using a case insensitve query
const t2 = document.querySelector("[id='question-HEADER' i")
console.log("t2", t2)
Here's a runnable example:
const t1 = document.querySelector("[id='content'")
console.log("t1", t1)
// Even works when using a case insensitve query
const t2 = document.querySelector("[id='CONTENT' i")
console.log("t2", t2)
<div id="content">Javascript attribute query selector</div>
Is this because JS allows close-enough syntax? Or?
Edit I did find this other question, Cheerio attributeStartsWith selector, which had a missing end bracket and was the root cause of the issue. However, as one of the answers pointed out, JQuery allowed the missing end bracket while Cheerio failed.
Interesting enough, I actually found this issue while using Puppeteer and noticed two of my selectors missing an end bracket, yet everything had been running w/o issue.
I'll take a stab at this. Assuming I'm interpreting the spec's rules correctly (which I may not be) the section on how to handle error handling when parsing css would seem to allow for this.
a.) In The DOM standard for querySelector
The querySelector(selectors) method steps are to return the first
result of running scope-match a selectors string selectors against
this, if the result is not an empty list; otherwise null.
https://dom.spec.whatwg.org/#dom-parentnode-queryselector
b. ) That links to section 1.3. Selectors. Looking at section 1.3.1:
To scope-match a selectors string selectors against a node, run these steps:
Let s be the result of parse a selector selectors. [SELECTORS4]
c.) Parse a selector links off to the csswg v4 draft, which doesn't go into as much detail about error handling as the v3 draft. The v3 draft states (emphasis added by me):
§ 2.2. Error Handling
This section is not normative.
When errors occur in CSS, the parser attempts to recover gracefully,
throwing away only the minimum amount of content before returning to
parsing as normal. This is because errors aren’t always mistakes—new
syntax looks like an error to an old parser, and it’s useful to be
able to add new syntax to the language without worrying about
stylesheets that include it being completely broken in older UAs.
The precise error-recovery behavior is detailed in the parser itself,
but it’s simple enough that a short description is fairly accurate.
At the "top level" of a stylesheet, an starts an
at-rule. Anything else starts a qualified rule, and is included in the
rule’s prelude. This may produce an invalid selector, but that’s not
the concern of the CSS parser—at worst, it means the selector will
match nothing.
Once an at-rule starts, nothing is invalid from the
parser’s standpoint; it’s all part of the at-rule’s prelude.
Encountering a ends the at-rule immediately, while
encountering an opening curly-brace <{-token> starts the at-rule’s
body. The at-rule seeks forward, matching blocks (content surrounded
by (), {}, or []) until it finds a closing curly-brace <}-token> that
isn’t matched by anything else or inside of another block. The
contents of the at-rule are then interpreted according to the
at-rule’s own grammar.
Qualified rules work similarly, except that
semicolons don’t end them; instead, they are just taken in as part of
the rule’s prelude. When the first {} block is found, the contents are
always interpreted as a list of declarations.
When interpreting a list of declarations, unknown syntax at any point causes the parser to
throw away whatever declaration it’s currently building, and seek
forward until it finds a semicolon (or the end of the block). It then
starts fresh, trying to parse a declaration again.
If the stylesheet
ends while any rule, declaration, function, string, etc. are still
open, everything is automatically closed. This doesn’t make them
invalid, though they may be incomplete and thus thrown away when they
are verified against their grammar.
After each construct (declaration,
style rule, at-rule) is parsed, the user agent checks it against its
expected grammar. If it does not match the grammar, it’s invalid, and
gets ignored by the UA, which treats it as if it wasn’t there at all.
https://drafts.csswg.org/css-syntax-3/#error-handling
Bullets 3-5 allow for a css rule to end without proper closing delimiters. In a stylesheet, a rule is a "prelude" (selector) followed by a set of css declarations wrapped in braces. A selector with no rules after it is invalid and discarded.
<style>
div[foo]
</style>
and is treated the same as a selector without a proper closing delimiter
<style>
div[foo
</style>
A selector with rules after it missing a closing ; and/or } is a complete selector + rule, and so it is still valid. Both of these are valid:
<style>
.foo {
color:red;
</style>
or
<style>
.bar {
color:blue
</style>
Finally, given that document.querySelector only requires a selector with no rule following it, I would conclude that a selector with a missing closing delimiter is valid according to the spec. You can see the same behavior with the :is pseudo class selector:
document.querySelector("div:is(.foo");
document.querySelector("div:is([foo");

Javascript regex to replace ampersand in all links href on a page

I've been going through and trying to find an answer to this question that fits my need but either I'm too noob to make other use cases work, or their not specific enough for my case.
Basically I want to use javascript/jQuery to replace any and all ampersands (&) on a web page that may occur in a links href with just the word "and". I've tried a couple different versions of this with no luck
var link = $("a").attr('href');
link.replace(/&/g, "and");
Thank you
Your current code replaces the text of the element within the jQuery object, but does not update the element(s) in the DOM.
You can instead achieve what you need by providing a function to attr() which will be executed against all elements in the matched set. Try this:
$("a").attr('href', function(i, value) {
return value.replace(/&/g, "and");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
link
link
Sometimes when replacing &, I've found that even though I replaced &, I still have amp;. There is a fix to this:
var newUrl = "#Model.UrlToRedirect".replace(/&/gi, '%').replace(/%amp;/gi, '&');
With this solution you replace & twice and it will work. In my particular problem in an MVC app, window.location.href = #Model.UrlToRedirect, the url was already partially encoded and had a query string. I tried encoding/decoding, using Uri as the C# class, escape(), everything before coming up with this solution. The problem with using my above logic is other things could blow up the query string later. One solution is to put a hidden field or input on the form like this:
<input type="hidden" value="#Model.UrlToRedirect" id="url-redirect" />
then in your javascript:
window.location.href = document.getElementById("url-redirect").value;
in this way, javascript won't take the c# string and change it.

regular expression to unlink html code with javascript

I'm sorry,I can't believe this question is not solved in stackoverflow but I've been searching a lot and I don't find any solution.
I want to change HTML code with regular expressions in this way:
testing anchor
to
testing anchor
Only I want to unlink a text code without use DOM functions, the code is in a string not in the document and I don't want to remove other tags that the a ones.
If you really don't want to use DOM functions (why ?) you might do
str = str.replace(/<[^>]*>/g, '')
You can use it if you're fairly confident you don't have a more complex HTML but it will fail in many cases, for example some nested tags, or > in an attribute. You might fix some of the problems with more complex regular expressions but they aren't the right tool for this job in the general case.
If you don't want to remove other tags than a, do this :
str = str.replace(/<\/?a( [^>]*)?>/g, '')
This changes
<a>testing</a> <b>a</b>nchor<div>test</div><aaa>E</aaa>
to
testing <b>a</b>nchor<div>test</div><aaa>E</aaa>
I know you only want regex, for future viewers, here is a trivial solution using DOM methods.
var a = document.createElement("div");
a.innerHTML = 'testing anchor';
var wordsOnly = a.textContent || a.innerText;
This will not fail on complicated use cases, allows nested tags and it's perfectly clear what's happening:
Hey browser! Create an element
Put that HTML in it
Give me back just the text, that's what I want now.
NOTE:
The element we're creating will not be added to the actual DOM since we're not adding it anywhere, it'll stay invisible. Here is a fiddle to illustrate how this works.
As has been mentioned, you cannot parse HTML with regular expressions. The principal reason is that HTML elements nest and regular expressions cannot handle that.
That said, with a few restrictions which I will mention, you can do the following :
string.replace (/(\b\w+\s*)<a\s+href="([^"]*)">(.*)<\/a>/g, '$1 $3')
This requires there to be a word before the tag, spacing between the word and the tag is optional, no attributes other than the href specified in the <a> tag and you accept anything between the <a> and the .
You can create a DOM object from the string, use DOM methods to parse, without having had appended said DOM object to the document

Is it possible to get jquery objects from an html string thats not in the DOM?

For example in javascript code running on the page we have something like:
var data = '<html>\n <body>\n I want this text ...\n </body>\n</html>';
I'd like to use and at least know if its possible to get the text in the body of that html string without throwing the whole html string into the DOM and selecting from there.
First, it's a string:
var arbitrary = '<html><body>\nSomething<p>This</p>...</body></html>';
Now jQuery turns it into an unattached DOM fragment, applying its internal .clean() method to strip away things like the extra <html>, <body>, etc.
var $frag = $( arbitrary );
You can manipulate this with jQuery functions, even if it's still a fragment:
alert( $frag.filter('p').get() ); // says "<p>This</p>"
Or of course just get the text content as in your question:
alert( $frag.text() ); // includes "This" in my contrived example
// along with line breaks and other text, etc
You can also later attach the fragment to the DOM:
$('div#something_real').append( $frag );
Where possible, it's often a good strategy to do complicated manipulation on fragments while they're unattached, and then slip them into the "real" page when you're done.
The correct answer to this question, in this exact phrasing, is NO.
If you write something like var a = $("<div>test</div>"), jQuery will add that div to the DOM, and then construct a jQuery object around it.
If you want to do without bothering the DOM, you will have to parse it yourself. Regular expressions are your friend.
It would be easiest, I think, to put that into the DOM and get it from there, then remove it from the DOM again.
Jquery itself is full of tricks like this. It's adding all sorts off stuff into the DOM all the time, including when you build something using $('<p>some html</p>'). So if you went down that road you'd still effectively be placing stuff into the DOM then removing it again, temporarily, except that it'd be Jquery doing it.
John Resig (jQuery author) created a pure JS HTML parser that you might find useful. An example from that page:
var dom = HTMLtoDOM("<p>Data: <input disabled>");
dom.getElementsByTagName("body").length == 1
dom.getElementsByTagName("p").length == 1
Buuuut... This question contains a constraint that I think you need to be more critical of. Rather than working around a hard-coded HTML string in a JS variable, can you not reconsider why it's that way in the first place? WHAT is that hard-coded string used for?
If it's just sitting there in the script, re-write it as a proper object.
If it's the response from an AJAX call, there is a perfectly good jQuery AJAX API already there. (Added: although jQuery just returns it as a string without any ability to parse it, so I guess you're back to square one there.)
Before throwing it in the DOM that is just a plain string.
You can sure use REGEX.

Read out JavaScript onClick function body and use it for another onClick

I try to copy an onClick function from an image to an span object.
But I don't get it.
I have tried it directly with onClick=img.onClick, onClick=new Function(img.onClick) and more.
if (img.onclick != undefined)
{
var imgClick = img.onclick;
strNewHTML = strNewHTML + " onMouseOver=\"this.style.background"
+ "= '#cecece'\" onMouseOut=\"this.style.background = ''\" onclick=\""+imgClick+"\">";
}
Can anyone help me?
Thanks!
span.onclick= img.onclick;
JavaScript is case-sensitive and DOM event handler properties are all lower-case.
edit:
if (img.onclick != undefined) {
strNewHTML = strNewHTML + " onMouseOver=\"this.style.background"
+ "= '#cecece'\" onMouseOut=\"this.style.background = ''\" onclick=\""+imgClick+"\">";
}
Well that's a completely different thing. You're creating an HTML string. But the onclick DOM property contains a function object. function objects can't be added into strings. (They would get converted to what you get if you call somefunction.toString(), which is not something that will work as an event handler.)
If you wanted to fetch the textual value of the onclick attribute to add into HTML, you'd have to do it with the span.getAttribute('onclick') method. But that won't work in IE due to bugs in its implementation of getAttribute, so you'd have to resort to span.getAttributeNode('onclick').value. And then when you added it into the HTML string, you'd have to HTML-escape it, so that any <, & and " characters in it came out as < etc., otherwise they'll break the markup.
However, this is really ugly; don't do it. In reality, HTML string-slinging invariably sucks. Especially when you've got JavaScript code inside HTML inside a JavaScript string. The escaping rules get insane and if you make a mistake escaping content that comes from user input, you've given yourself a cross-site-scripting security hole.
Instead, use DOM methods. This takes all the escaping out of the equation and it's generally more readable than hacked-together HTML markup strings. Then you can freely assign onclick to whatever function you like. eg.:
var span= document.createElement('span');
if (img.onclick)
span.onclick= img.onclick;
span.onmouseover= function() {
this.style.background= '#CECECE';
};
span.onmouseout= function() {
this.style.background= '';
};
someparentelement.appendChild(span);
Also consider replacing the mouseover/mouseout with a simple CSS :hover rule, for maintainability. The only browser that still needs help with :hover is IE6.

Categories