Chrome addon to replace string on Facebook not working? - javascript

I'm using the following javascript inside the Chrome extension Web Override to attempt to replace certain text on all Facebook pages, but it is not working.
document.addEventListener('DOMContentLoaded', function() {
document.body.innerHTML = document.body.innerHTML.replace('Friend Name', 'Silly Nickname');
}, false);
setTimeout(function(){
document.body.innerHTML = document.body.innerHTML.replace('Friend Name', 'Silly Nickname');
}, 3000);
If I manually run the replace function in the console after page load it does what I expect. Why isn't it running automatically?
The only console error I'm getting is as follows, but I don't think it's related to this plugin/code because it shouldn't be loading jquery.
Refused to load the script 'https://code.jquery.com/jquery-3.1.1.min.js' because it violates the following Content Security Policy directive
Unfortunately I can't be sure because the source is VM1771:7.
If it is the JQuery thing, is there anything I can do? If not, what is wrong with the code?

String.prototype.replace expects either a string or a regex as the first argument, and in case of a string, it only replaces the first occurrence. That occurrence could be in some metadata, class name, etc.
If you want all occurrences to be replaced, you should use the regex option:
document.body.innerHTML = document.body.innerHTML.replace(/Friend Name/g, 'Silly Nickname');
The g flag here means "global", i.e apply this to all occurrences. You could also use gi for case insensitivity.

Related

href attribute set, javascript sees as empty string

I am experiencing odd behaviour in Chrome (v43.0.2357.134) whereby I am reading an anchor element's .href attribute, but in specific circumstances its value is an empty string.
I would like the .href value to be populated on all anchors.
Issue
Specifically, this is what is being observed:
//Bad (unwanted) behaviour
var currentElem = ; //Code to pick out an anchor element
console.info(currentElem.href); //"" (empty string)
console.info(currentElem.getAttribute('href'); //"path/to/other/page.html"
Edited to add/clarify: Note that in this screenshot, at the point of reaching the fourth line of code the value of nextPageUri is an empty string (otherwise would not have reached the debugger; line). The fifth line then populates nextPageUri with the .getAttribute('href') value, hence the value showing next to line two.
This is what is (correctly) seen within Firefox, and on the first TWO DOMs via Chrome:
//Good (desired) behaviour
var currentElem = ; //Code to pick out an anchor element
console.info(currentElem.href); //"http://example.org/root/dir/path/to/other/page.html"
console.info(currentElem.getAttribute('href'); //"path/to/other/page.html"
Background
Context: This is within a script to inline multiple pages of search results to a single page, and the anchor elements are located within a DOM retrieved via xmlHttpRequest. The code runs perfectly via Firefox for >100 pages.
Confusingly, the incorrect behaviour described above only occurs on the third and subsequent requests in the Chrome browser.
This is an issue with Chromium/Blink-based browsers: if you use DOMParser to parse string into a document, href properties with relative URI (i.e. doesn't start with http[s]) will be parsed as empty string.
To quote tkent from Chromium issue 291791:
That's because a document created by DOMParser doesn't have baseURI. Without baseURI, relative URI references are assumed as invalid.
Same thing happens if you use createHTMLDocument. (Chromium issue 568886)
Also, based on this test code posted by scarfacedeb on Github, src properties also exhibit the same behavior with relative URIs.
As you have pointed out, using getAttribute() instead of the dot notation works fine.
Chrome's "element.href" doesn't act any differently on the 3rd try than it does on the first 2 -- you mentioned that you are paginating, when this error happens. how does the "href" attribute on the Next Page link get set each time you arrive at the page? It seems likely that your code to evaluate the element's href attribute is simply running before the href is set -- as evidenced by your debugger being able to evaluate it after a pause.
Try and reproduce this issue in a plunkr.
I know you're checking if nextPageUri is empty.
But, could you try always using
nextPageUri = currentElem.getAttribute('href');
and see if that works?
I experienced a similar problem using a DOMParser for translating text/html pages coming from ajax requests and, after that, finding href's of <a> elements inside it.
For instructions purpose, this is how I'm using the parser
var parser = new DOMParser();
$.ajax({....}).done(function(request){
var page = parser.parseFromString(request, 'text/html');
});
Test yourself
If you want to test the behaviour of .href and .getAttribute("href") yourself, please run this code at chrome dev tools console:
parser = new DOMParser(); // create your DOMParser
// the next line creates a "document" element with an <a> tag inside it
parsed_page = parser.parseFromString('click here', 'text/html');
link = parsed_page.getElementsByTagName('a')[0]; // locate your <a> tag
link.href; // this line returns ""
link.getAttribute('href'); // this line returns "test"

How to allow for another index string to run a script

I have no script abilitiy, but i'd like to edit an existing script which is currently restricting the script from running on any page other then the one that has a certain string in the URL.
Here is the snippet of the script which limits it from running
if(location.href.indexOf("MODULE=MESSAGE")>0||location.href.indexOf("/message")>0)
This only allows the script to run on these pages
mysite/2014/home/11609?MODULE=MESSAGE1
and the pages range from Message1 to Message20
mysite/2014/home/11609?MODULE=MESSAGE20
I would like to also allow the script to be loaded and ran on these pages
mysite/2014/options?L=11609&O=247&SEQNO=1&PRINTER=1
where the SEQNO=1 ranges from 1 to SEQNO=20, just like the MESSAGE1-MESSAGE20 do
Can someone show me how i can edit that small snippet of script to allow the SEQNO string found in the url to work also.
Thanks
If you can't just remove the condition altogether (there's not enough context to know if that's an option), you can just add another or condition (||) like so:
if(location.href.indexOf("MODULE=MESSAGE")>0
||location.href.indexOf("/message")>0
||location.href.indexOf("SEQNO=")>0)
Note that the second clause there isn't actually being used in any of your examples, so could potentially be removed. Also note that this isn't actually checking for a number so it isn't restricted to Message1 to Message20 as you suggest. It would match Message21 or even MessageFoo. That may or may not be a problem for you. You can make the conditions as restrictive or as lose as makes sense.
If you just want to check for the existence of "SEQNO", simply duplicate what is being done for "MODULE_MESSAGE".
if(location.href.indexOf("MODULE=MESSAGE")>0 ||
location.href.indexOf("SEQNO=")>0 ||
location.href.indexOf("/message")>0)
If you want to also ensure that "MESSAGE" ends in 1-20, and "SEQNO=" ends in 1-20, you can use a regex.
// create the end part of the regex, which checks for numbers 1-20
var regexEnd = "([1-9]|1[0-9]|20)[^0-9]*$";
// create the individual regexes
var messageRegex = new RegExp("MODULE=MESSAGE" + regexEnd);
var seqnoRegex = new RegExp("SEQNO=" + regexEnd);
// now comes your if statement, using the regex test() function, which returns true if it matches
if(messageRegex.test(location.href) ||
seqnoRegex.test(location.href) ||
location.href.indexOf("/message")>0)

Uncaught Error: Syntax error, unrecognized expression: # Something

So I have the following code inside a React Component
handleClick: function(e) {
e.preventDefault();
var post = new AisisWriter.Models.Post()
var title = this.stripHtml($('#post-title').val());
var content = this.stripHtml($('#post-content').val());
post.set({title: title, content: content});
post.save().then(this.created, this.failed);
},
stripHtml: function(content){
if($(content)[0] !== undefined){
return $(content)[0].textContent;
}
return content;
},
The essential point is that I am trying to strip out any HTML that you try and send back, but keep other symbols such as # and so on for Markdown.
Any ways, the #post-content contains the following: # Something and apparently Jquery doesn't like it: Uncaught Error: Syntax error, unrecognized expression: # Something
How can I get around this?
JSBin of the issue
let me start with the solution first:
function stripHtml(){
content = strip($('#content').val());
alert(content);
}
function strip(content){
var content2 = jQuery.parseHTML(content);
if(content2[0].data !== undefined){
// This will remove all the html assuming there is any
return content2[0].data;
}
// Return the content if their is no html
return content;
}
to explain, starting with jQuery >= 1.9 documentation:
jQuery(htmlString) versus jQuery(selectorString)
Prior to 1.9, a string would be considered to be an HTML string if it
had HTML tags anywhere within the string. This has the potential to
cause inadvertent execution of code and reject valid selector strings.
As of 1.9, a string is only considered to be HTML if it starts with a
less-than ("<") character. The Migrate plugin can be used to restore
the pre-1.9 behavior.
If a string is known to be HTML but may start with arbitrary text that
is not an HTML tag, pass it to jQuery.parseHTML() which will return an
array of DOM nodes representing the markup. A jQuery collection can be
created from this, for example: $($.parseHTML(htmlString)). This would
be considered best practice when processing HTML templates for
example. Simple uses of literal strings such as
$("Testing").appendTo("body") are unaffected by this change.
Bottom line: HTML strings passed to jQuery() that start with something
other than a less-than character will be interpreted as a selector.
Since the string usually cannot be interpreted as a selector, the most
likely result will be an "invalid selector syntax" error thrown by the
Sizzle selector engine. Use jQuery.parseHTML() to parse arbitrary
HTML.
and due to that you need to use jQuery.parseHTML function first and access your object (0) data element which contains the required text.

Javascript Bookmarklet Unresponsive

Javascript newb here. Creating a bookmarklet to automate a simple task at work. Mostly a learning exercise. It will scan a transcript on CNN.com, for instance: (http://transcripts.cnn.com/TRANSCRIPTS/1302/28/acd.01.html). It will grab the lead stories at the top of the page, the name and title of the guests on the show, and format them so that they can be copy pasted into another document.
I've come up with a simple version that includes some jQuery that grabs the subheading and then uses a regular expression to find the names of the guests (it will also exclude everything between (begin videoclip) and (end videoclip), but I haven't gotten that far yet. It then alerts them (will eventually print them in a pop-up window, alert is just for troubleshooting purposes).
I'm using http://benalman.com/code/test/jquery-run-code-bookmarklet/ to create the bookmarklet. My problem is that once the bookmarklet is created it is completely unresponsive. Click on it and nothing happens. I've tried minimizing the code first with no result. My guess is that cnn.com's javascript is conflicting with mine but I'm not sure how to get around that. Or do I need to include some code to load and store the text on the current page? Here's the code (I've included comments, but I took these out when I used the bookmarklet generator.) Thanks for any help!
//Grabs the subheading
var leadStories=$(".cnnTransSubHead").text();
//Scans the webpage for guest name and title. Includes a regular expression to find any
//string that starts with a capital letter, includes a comma, and ends in a colon.
var scanForGuests=/[A-Z ].+,[A-Z0-9 ].+:/g;
//Joins the array created by scanForGuests with a semicolon instead of a comma
var guests=scanForGuests.join(‘; ‘);
//Creates an alert in the proper format including stories and guests.
alert(“Lead Stories: “ + leadStories + “. ” + guests + “. SEE TRANSCRIPT FIELD FOR FULL TRANSCRIPT.“)
Go to the page. Open up developer tools (ctrl+shift+j in chrome) and paste your code in the console to see what's wrong.
The $ in var leadStories = $(".cnnTransSubHead").text(); is from jQuery and the link provided does not have jQuery loaded into the page.
On any modern browser you should be able to achieve the same results without jQuery:
var leadStories = document.getElementsByClassName('cnnTransSubHead')
.map(function(el) { return el.innerText } );
next we have:
var scanForGuests=/[A-Z ].+,[A-Z0-9 ].+:/g;
var guests=scanForGuests.join('; ');
scanForGuests IS a regular expression, you never actually matched it to anything - so .join() is going to throw an error. I'm not exactly sure what you're trying to do. Are you trying to scan the full text of the page for that regex? In that case something like this would be your best bet
document.body.innerText.match(scanForGuests);
keep in mind that while innerText removes html markup, it's far from perfect and what pops up in it is very much at the mercy of how the page's html is structured. That said, on my quick test it seems to work.
Finally, for something like this you should use an immediately invoked function or you're sticking all your variables into the global context.
So putting it all together you get something like this:
(function() {
var leadStories = document.getElementsByClassName('cnnTransSubHead')
.map(function(el) { return el.innerText } );
var scanForGuests=/[A-Z ].+,[A-Z0-9 ].+:/g;
var guests = document.body.innerText.match(scanForGuests).join("; ");
alert("Leads: " + leadStories + " Guests: " + guests);
})();

Making a URL W3C valid AND work in Ajax Request

I have a generic function that returns URLs. (It's a plugin function that returns URLs to resources [images, stylesheets] within a plugin).
I use GET parameters in those URLs.
If I want to use these URLs within a HTML page, to pass W3C validation, I need to mask ampersands as &
/plugin.php?plugin=xyz&resource=stylesheet&....
but, if I want to use the URL as the "url" parameter for a AJAX call, the ampersand is not interpreted correctly, screwing up my calls.
Can I do something get & work in AJAX calls?
I would very much like to avoid adding parameters to th URL generating function (intendedUse="ajax" or whatever) or manipulating the URL in Javascript, as this plugin model will be re-used many times (and possibly by many people) and I want it as simple as possible.
It seems to me that you're running into the problem of having one piece of your application cross multiple layers. In this case it's the plugin.
A URL as specified by RFC 1738 states that a URL should use a & token to separate key/value pairs from one another. However ampersand is a reserved token in HTML and therefore should be escaped into &. Since escaping the ampersands is an artifact of HTML, your plugin should probably not be escaping them directly. Instead you should have a function or something that escapes a canonical URL so that it can be embedded in HTML markup.
The only place that this is likely to actually happen is if you are:
Using XHTML
Serving it as text/html
Using inline <script>
This is not a happy combination, and the solution is in the spec.
Use external scripts if your script
uses < or & or ]]> or --.
The XHTML media types note includes the same advice, but also provides a workaround if you choose to ignore it.
Try returning JSON instead of just a string, that way your Javascript can read the URL value as an object, and you shouldn't have that issue. Other than that, try simply HTML decoding the string, using something like:
function escapeHTML (str)
{
var div = document.createElement('div');
var text = document.createTextNode(str);
div.appendChild(text);
return div.innerHTML;
};
Obviously you'll want to make sure you remove any reference to DOM elements you might create (which I've not done here to simplify the example).
I use this technique in the AJAX sites I create at my work and have used it many times to solve this problem.
When you have markup of the form:
<a href="?a=1&b=2">
Then the value of the href attribute is ?a=1&b=2. The & is only an escape sequence in HTML/XML and doesn't affect the value of the attribute. This is similar to:
<a href="<>">
Where the value of the attribute is <>.
If, instead, you have code of the form:
<script>
var s = "?a=1&b=2";
</script>
Then you can use a JavaScript function:
<script>
var amp = String.fromCharCode(38);
var s = "?a=1"+amp+"b=2";
</script>
This allows code that would otherwise only be valid HTML or only valid XHTML to be valid in both. (See Dorwald's comments for more info.)

Categories