First of all, I am not a programmer. I do not know Javascript at all. I'm trying to create a Chrome extension that modifies my browser tab's title, by taking a specific string on a webpage. I know how to create Chrome extensions (just barely) and I just need to modify the Javascript to do what I want (which I do not know how).
I found the following script online and am trying to modify it but can't figure out how to get it working. Here is the script:
https://pastebin.com/dY1LSdjT
// Fire this event any time the mouse is moving. Sucks for performance, but it's a better experience
document.addEventListener("mousemove", function() {
// This will get us the banner
let bannerTextElements = document.getElementsByClassName("dijitReset dijitInputField dijitInputContainer");
console.log(bannerTextElements);
console.log(bannerTextElements[0]);
if (bannerTextElements[0]) {
console.log("ok!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
console.log(bannerTextElements[0].innerHTML);
// This will get us the text
let bannerTextLine = bannerTextElements[0].getElementsByClassName("dijitReset dijitInputInner");
console.log(bannerTextLine);
document.title = bannerTextLine[0].innerHTML
}
}, false);
And here's the website viewed in developer mode. I would like to get the text "blahhhh" and use that for the title of my browser tab.
Below is a different webpage and the difference here is that the "div class" names will change. The numbers in those class will change to different numbers, but the structure and the overall name remains the same. For example, "ms-Button-label label-549" may change to "ms-Button-label label-640". This happens whenever you refresh the page. I found that the "viewport" id name doesn't change though, so I think if we can use that as a reference and then just look at the nested div classes and reference them and extract the value (in this case Crystal Mountain).
Fixing your code
You got like 95% of everything you need.
The one thing you are missing right now is that the fact that an input element does not posses an "innerHTML" (That is why it isn't closed like this: <input>renderedText</input>). Instead you want to check for it's value:
document.title = bannerTextLine[0].value;
Some Improvements:
Search by ID
You have a well defined input which can be more easily obtained by looking it up using the id:
let bannerTextLine = document.getElementById('lanDeviceIndex_searchBox');
End result:
const bannerTextLine = document.getElementById('lanDeviceIndex_searchBox');
bannerTextLine.addEventListener("blur", function() {
if (bannerTextLine != null) {
document.title = bannerTextLine.value;
}
});
This is the entire JS code. Note that I changed the event to blur which activates when the form is left, this should be optimal for your case.
Related
I want to Change the value assigned to a Document Property in spot fire. Lets say i have created a new document property called "Test1" as a string and assign it a value "a". Is there are way to change this value using Javascript every time i load the spotfire dashboard ?
I'm unaware of a way to use JavaScript for this, but you can assign a string document property via custom expression (if it's a List Box) or run an IronPython script each time the value changes. So, you could set the expression to the current date, datetimenow() and then every time it's loaded the IronPython script would fire. However, I don't see why you'd need the property control for this.
I suppose it really depends on what you want the document property to be set to. Is it data from your tables? Output from complex code? These are all things to consider.
1) Create an input type property control using the Document Property you want to change.
2) Edit Html to assign parent element an id say "testInput". And add the script as shown below in the Edit HTML window.
<span id="testInput"><SpotfireControl id="7db34e6c423240f59fc99e6b80fa23ec" /></span>
<script>
$("#testInput input").val("after");
$("#testInput input").focus();
$("#testInput input").blur();
</script>
3) This script will change the document property value to "after" whenever you open a file.
As you comment seemed to suggest, something you can do is write this code in Python and attach the script to an action control, e.i. a Link or a Button. Something simple like: Document.Properties["Test1"] = newValue
or even: Document.Properties[changingProperty] = newValue
allowing the code to be more reusable.
Then you insert Javascript into the Text Area as well to the effect of: $("#VeryLongSpotfireControlID").click();
Which should simulate clicking on action control, which in turn triggers the Python script to update the value. Just be careful not to use this approach when it would result in reloading the text area HTML, as this will re-trigger the Javascript, thus creating an endless loop.
I believe I have found a possible solution/work-around for the issue, entirely based on pure JavaScript (since TIBCO removed jQuery starting from Spotfire X). The solution is to force a simulated Enter Keystroke while focusing the input box to trigger updating the Document Property. (No data function and R needed)
HTML (SpotfireControl Element is an single line input-box for a Doc. Prop.):
<div id="container"><SpotfireControl id="b8534f13dc62416db6d4eaab16030f5e" /></div>
JS (focus and blur might no longer be needed for this solution, but I'm still keeping them just in case):
const inputConfirmationEvent = new KeyboardEvent("keypress", {
keyCode: 13,
bubbles: true,
cancelable: false
});
var elem = document.querySelector("#container input");
elem.value = "stringValue";
elem.blur();
elem.focus();
document.querySelector("#container input").dispatchEvent(inputConfirmationEvent);
Hope it helps someone.
Best,
Aaron
the problem at the moment is that when the windows get resized some text gets cut off. I've seen websites where when the window resizes the text changes to an abbreviation or another word. People were telling me that this is angular js but since then I've tried finding something related to it and couldn't. So i'm back to using good old javascript and here is my code
http://jsfiddle.net/duy8zvmm/71/
The problem is that i don't want this first
var myspan = document.getElementById('players-signedup');
if (myspan.innerText) {
myspan.innerText = "Players";
}
else
if (myspan.textContent) {
myspan.textContent = "Players";
}
and can't understand why i need it there, because the resize if statements i have do work, i have tested using background colors on a div. So i can't understand why they aren't working here
I've just started using casperjs after trying to use python (selenium / requests and mechanise) to scrape a page only after some javascript loaded some dynamic content on the page.
Since this was very hard to do or very slow with selenium it was suggested I turn to Casper js (which requires phantomjs).
One thing I am wondering (I am quite new to javascript) is relating to a javascript onclick event.
The page I want to scrape by default shows ten names per page, and at the bottom has options to show (5) or show (100).
After diving into this code and inspecting it with firebug I am wondering if it is possible to change the onclick=loaditems(100) to something like... onclick=loaditems(Load X items), where X could be 200. (or whatever number it needs to be to load all the content on one page and make it easier for scraping. Is this possible?
update
* reviewer asked for the code used to select the 100 items per page....
The code (HTML) is..
<a title="Show 100 items per page"
onclick="lconn.profiles.Friending.setItemsPerPage(this,100)" href="javascript:void(0);">100</a>
and the Xpath is...
/html/body/div/div[2]/div[3]/div[3]/span/div/div/div/div/div[2]/div/div/form/div??/div[4]/div/ul/li[4]/a
problem
I am able to edit the onclick command and change the value to a higher number, however I do not know how to then execute it with the higher number of elements I want to display per page to see if it works.
I used a simple CSS selector for this task. You can change the onclick attribute with string operations. In this case I replace "100" with num. I also added a clickIt argument to click the changed link.
casper.changeItemsPerPageLink = function(num, clickIt){
casper.evaluate(function(num, clickIt){
num = ""+num;
var a = document.querySelector('a[title="Show 100 items per page"]');
a.innerHTML = num;
a.title = a.title.replace("100", num);
a.setAttribute("onclick", a.getAttribute("onclick").replace("100", num));
if (clickIt) {
a.click();
}
}, num, clickIt);
};
See my test code gist.
I have a pretty specific scenario where I would like to select all elements with jQuery, make a CSS change, save the elements, then reverse the change I made.
The Goal
I created a jQuery plugin called jQuery.sendFeedback. This plugin allows the user to highlight areas of the screen, as shown in this demo. When they submit their feedback the plugin grabs all the HTML on the page and dumps it into a callback function. Like so:
$('*').each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
var feedbackInformation = {
subject: $feedbackSubject.val(),
details: $feedbackDetails.val(),
html: '<html>' + $('html').html() + '</html>'
};
if (settings.feedbackSent)
settings.feedbackSent(feedbackInformation);
The callback function accepts this feedback information and makes an AJAX call to store the page HTML on the server (this HTML includes the red box highlights the user drew on the screen). When someone from tech support needs to view the user's "screen shot" they navigate to a page that serves up the stored HTML so the developer can see where the user drew their highlights on the screen.
My original problem was that different screen resolutions made the elements different sizes and the red highlights would highlight the wrong areas as the screen changed. This was fixed pretty easily by selecting all elements on the page and manually setting their height and width to their current height and width when the user takes the snap shot. This makes all the element sizes static, which is perfect.
$('*').each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
The Problem
The issue with this is that when the plugin is done transmitting this HTML the page currently being viewed now has static heights and widths on every element. This prevents dropdown menus and some other things from operating as they should. I cannot think of an easy way to reverse the change I made to the DOM without refreshing the page (which may very well end up being my only option). I'd prefer not to refresh the page.
Attempted Solution
What I need is a way to manipulate the HTML that I'm sending to the server, but not the DOM. I tried to change the above code to pull out the HTML first, then do the operation on the string containing the HTML (thus not affecting the DOM), but I'm not quite sure what I'm doing here.
var html = '<html>' + $('html').html() + '</html>';
$('*', html).each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
This did not work. So either I need to be able to manipulate the string of HTML or I need to be able to manipulate the DOM and undo the manipulation afterward. I'm not quite sure what to do here.
Update
I employed the solution that I posted below it is working beautifully now. Now I am wondering if there is a way to statically write all the css for each element to the element, eliminating the need for style sheets to be referenced.
I think you are mostly on the right track by trying to make the modifications to the HTML as a string rather than on the current page for the user.
If you check this post, you might also want to follow the recommendation of creating a temporary <div> on the page, cloning your intended content to the new <div> ensuring it is invisible using "display:none." By also putting a custom Id on the new <div> you can safely apply your static sizing CSS to those elements using more careful selectors. Once you have sent the content to the server, you can blow away the new <div> completely.
Maybe?
After much pain and suffering I figured a crude but effective method for reverting my modifications to the DOM. Though I hadn't gotten around to trying #fdfrye's suggestion of cloning, I will be trying that next to see if there is a mroe elegant solution. In the meantime, here is the new code in case anyone else can benefit from it:
$('*').each(function () {
if ($(this).attr('style'))
$(this).data('oldStyle', $(this).attr('style'));
else
$(this).data('oldStyle', 'none');
$(this).width($(this).width());
$(this).height($(this).height());
});
var html = '<html>' + $('html').html() + '</html>';
$('*').each(function () {
if ($(this).data('oldStyle') != 'none')
$(this).attr('style', $(this).data('oldStyle'));
else
$(this).removeAttr('style');
});
When I'm looping through every element and modifying the css, I log the original value onto the element as data. After I assign the DOM HTML to a variable I then loop through all elements again and restore the style attribute to its original value. If there was no style attribute then I log 'none' to the element data and then remove the style attribute entirely when looping through again.
This is more performance heavy than I wish it was since it loops through all elements twice; it takes a few seconds to finish. Not horrible but it seems like a little much for such a small task. Anyway, it works. I get a string with fixed-sized HTML elements and the DOM goes back to normal as if the plugin never touched it.
I generate some html content dynamically like:
var content = "<head><title>testtitle</title></head><body>testbody</body>";
Then I get myself a new tab with about:blank, and now I want to display my generated html in this tab. If the tab's contentDocument is newDoc, I thought I just do:
newDoc.documentElement.innerHTML = content;
However, that doesn't work. It seems to have no effect at all. In firebug it seems to work once but screws up firebug at the same time, so I can't verify, source view remains unchanged.
I then tried:
newDoc.getElementsByTagName("head")[0].innerHTML = headContent;
newDoc.body.innerHTML = bodyContent;
Which doesn't change the displayed empty page, also not in the source view, but if I alert newDoc.documentElement.innerHTML, it reflects the changes. It seems like this isn't the document that's displayed any more. Weird.
So my question: how do I do that? Specifically in a firefox extension, if that is important.
Is there maybe a href format with "text://..." instead of "file://..." or something?
Update:
It turns out that I can't only replace the full code this way, I can't even body.appendChild, but I'm sure I did that before, so I compared. Here I get my document this way:
var tab = getBrowser().addTab(); //make new tab
getBrowser().selectedTab = tab; //bring it to front
var browser = getBrowser().getBrowserForTab(tab); //get the window of the tab
var newDoc = browser.contentDocument;
Now I can do:
newDoc.location.href = url;
And this works, it loads the given page.
So I thought this is the correct document, but if I don't assign a url, but instead try to build the dom myself, it simply doesn't work.
If I do those changes to window.content.document after the tab is in front, it works. So how come these documents are different? If newDoc is the wrong one, how come assigning a location does anything?
Although I can get it to work now, I don't particularly like the solution of getting the document by bringing the tab to the front and then grabbing the window.content document, that feels like a hack and depends on timing.
I just found a nifty jQuery method that might accomplish this: http://api.jquery.com/html/#html2
I created a page with a button that calls the script:
$("html").html("<span>Hello <b>World</b></span>");
This replaces the entire page DOM.