Is it possible to run something before DOMContentLoaded? - events

I want to inject stylesheets and scripts before DOMContentLoaded.
In Google Chrome it is possible using run_at = document_start.
Is there something similar in Firefox addons? Can I run things before gBrowser.addEventListener("DOMContentLoaded" ? How?

The current workaround I'm using is the following
gBrowser.addEventListener("DOMNodeInserted",
function (e)
{
if (typeof(e.relatedNode.tagName) != "undefined" &&
e.relatedNode.tagName == "DIV")
{
var window = e.relatedNode.ownerDocument.defaultView;
if (window.MyScript) return; // if it was injected
// ignore other events
if (/siteregex/i.test(window.location.href))
{
Initialize(window); // inject scripts
}
}
},
true);
DIV is the first element on body, so it will load right after this node. I won't have to wait for the whole page.

Related

Cypress Click if item exist

I need a way to easily trigger a click() event only if an element exist on page.
the fact that the element (confirm modal dialog) itself exist is not an issue for my test, but this can stop next steps. so I want to click OK only if the dialog is shown.
I tried something like this, but it didn't work:
cy.get('body').find("button[data-cy=sometag]").then(items => {
if(items.length) {
cy.get('button[data-cy=sometag]').click();
}
});
If you want to test that the modal exists but don't want to fail the test if it doesn't, use a jQuery selector.
const found = Cypress.$('button[data-cy=sometag]').length
Modals are likely to animate on opening, so you you will need to repeat the check a few times, which you can do in a function
function clearModal(selector, timeout = 1000, attempts = 0)
if (attempts > (timeout / 100)) {
return; // modal never opened
}
if (!Cypress.$(selector).length) { // not there yet, try again
cy.wait(100)
clearModal(selector, timeout, ++attempts)
else {
Cypress.$(selector).click() // modal is up, now close it
}
}
clearModal('button[data-cy=sometag]')
If you use the find like this cy.get('body').find("button[data-cy=sometag]") this will fail always whenever the element is not present. Instead you can use the find command inside the If condition and check its length.
cy.get('body').then($body => {
if ($body.find("button[data-cy=sometag]").length > 0) {
cy.get('button[data-cy=sometag]').click();
} else {
//Do something
}
})
Instead of body, you can also use the parent element of the element in question, which you know for sure is visible and present on the page every time.

How can I check with Google Apps Script whether the sidebar opened by "SpreadsheetApp.getUi().showSidebar(html);" is open or not open?

Background: The sidebar cannot be opened with onOpen().
"PropertiesService.getScriptProperties();" should not be used because it is only suitable for one user (possible overlaps). If the sidebar is open, nothing should happen to prevent it from being reloaded, otherwise it should be opened. A global variable could not be overwritten within a function for the next execution.
function sidebar() {
if (? == 'off') {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('Title');
SpreadsheetApp.getUi()
.showSidebar(html);
}
}
With getUserProperties() it works per user per script. A sidebar can be opened with onOpen() by adding a trigger to the respective script for onOpen() at https://script.google.com/home/.
var status = PropertiesService.getUserProperties(); // global variable
function onOpen() {
status.setProperty('sidebar', 'off');
sidebar();
}
function sidebar() {
if (status.getProperty('sidebar') == 'off') {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('Title');
SpreadsheetApp.getUi()
.showSidebar(html);
status.setProperty('sidebar', 'on');
}
}
This is what I found to work in this particular situation. It's not perfect, but it is functional and pretty simple:
.html
window.setInterval(function(){
google.script.run.collectPing();
}, 10000);
.gs
function collectPing() {
CacheService.getDocumentCache().put('sidebar', 'on', 15);
}
While the sidebar is open, it calls the server-side every 10 seconds and sets a property in the cache which lasts for 15 seconds. You can then write a function on the server-side that looks at the cache and does something based on the cache property. I just came up with this, so it is relatively untested, though my first try seems to indicate that it works.

Make Pinterest Profile Widget Secure

I am using the below page to create a Pinterest Profile widget:
https://business.pinterest.com/en/widget-builder#do_embed_user
The problem is that when the widget displays the images use non secure links. I need to display the widget on a secure page so need them to be https://
Any ideas how I can go about this?
Ok so after a bit of research I have made a pretty intense hack to make this work. Pintrest does serve https content, it is just that for some reason they have not included this in their API. So I have stepped through the API and found the attribute setter that sets attributes to any elements the API creates.
Anyway.. here is the fiddle: https://jsfiddle.net/nanff007/1/ (make sure to https)
And here is the code that performs the magic...
This is a workaround/hack or whatever you want to call it. It will not work forever. It may also not work in all countries as the akamai urls may change. The best option would be to raise a request ticket with Pintrest.
(function() {
$('a[data-pin-do]').each(function () {
$(this).attr('data-pin-dont', $(this).attr('data-pin-do'));
$(this).removeAttr('data-pin-do');
});
var timer = setInterval(function () {
for (prop in window) {
if (prop.search(/^PIN_/) > -1 && typeof window[prop] != 'boolean') {
clearInterval(timer);
window[prop].f.set = function (el, att, string) {
if(att == 'src' && el.tagName.toLowerCase() == 'img') {
string = string.replace(/(^http:\/\/)/i, "https://s-");
}
if (typeof el[att] === 'string') {
el[att] = string;
} else {
el.setAttribute(att, string);
}
};
$('a[data-pin-dont]').each(function () {
$(this).attr('data-pin-do', $(this).attr('data-pin-dont'));
$(this).removeAttr('data-pin-dont');
});
window[prop].f.init();
break;
}
}
}, 100);
}());
Just Remove the https: and start with // as the beginning of the link.
For Example:
< a href="//sub-domain.example.com">Acme Widgets
Remove the spaces before > and after < in the above example

protractor click action relies on ptor.sleep(). How can I resolve correctly?

I'm a newbie trying to not rely so much or at all on using ptor.sleep() calls, especially after the click below. The line below never gets the value (they all return Nan)unless I include the ptor.sleep(1000); call after the click() below.
I've made various attempts to make the array elem to resolve before the results of the list after clicking, wrapping the click in the function, etc, but nothing I've tried works without the sleep calls. Already read up on protractor control flow.
devCountString = parseInt(arr[i]);
Thanks for any insights, maybe something obvious I've missed so that I can remove the ptor.sleep() calls.
my spec:
describe('\n == patch List suite results == \n', function() {
// login already was done in config files, onPrepare function.
var ptor, noFilterCount;
// needed here if we turn ptor.ignoreSynchronization = false;
beforeEach(function() {
ptor = protractor.getInstance();
ptor.ignoreSynchronization = true;
browser.get('https://my.abc.com:3000/fixes');
ptor.sleep(1200);
}); //end beforeEach()
it('11 - verify filter fewer', function() {
var sevStringElm, sevString;
var applicableCount;
ptor.ignoreSynchronization = false;
ptor.sleep(500);
sevStringElm = element(by.css("input.form-control.bf-spinner"));
sevStringElm.clear();
ptor.sleep(500);
sevStringElm.sendKeys( '8' );
ptor.sleep(500);
// click on the "fewer" spinner, wrap the click to wrap the .
var fewerPromise = element(by.css("span.bf-spinner-toggle:nth-child(2)")).click();
ptor.sleep(1000);
// now get the list of clickable elements in each device card. by title
var applicableDevicesElm = element.all(by.css("[title$='Applicable\ Devices']"));
applicableDevicesElm.getText().then(function(arr) {
console.log("arr.length= "+arr.length);
for (var i = 0; i < arr.length; i++) {
devCountString = parseInt(arr[i]);
expect(devCountString).toBeLessThan( 9 );
};
});
});
Everytime an action goes to the webdriver, Protractor will put that into the flow queue as shown in the documentation. As a result, when you get to inspect your elements after the click, the queue should have resolved the dependencies and have your state ready for the finder. In any case, even if you don't want to have the implicit wrapping that Protractor does on its actions (which are always asyc), you can put a .then(function(){}) after the click and put the post click logic in that anonymous calback function.
On a side note, you should have to use ptor anymore. Use browser instead that mixes in the protractor instance capabilities. Example: browser.sleep(1000)

Force context menu to appear for form inputs

I'm trying to develop a ff addon that allows a user to right-click on a form element and perform a task associated with it.
Unfortunately somebody decided that the context menu shouldn't appear for form inputs in ff and despite long discussions https://bugzilla.mozilla.org/show_bug.cgi?id=433168, they still don't appear for checkboxes, radios or selects.
I did find this: https://developer.mozilla.org/en-US/docs/Offering_a_context_menu_for_form_controls but I cannot think how to translate the code to work with the new add-on SDK.
I tried dumping the javascript shown into a content script and also via the observer-service but to no avail.
I also cannot find the source for the recommended extension https://addons.mozilla.org/en-US/firefox/addon/form-control-context-menu/ which considering it was 'created specifically to demonstrate how to do this' is pretty frustrating.
This seems like very basic addon functionality, any help or links to easier documentation would be greatly appreciated.
** UPDATE **
I have added the following code in a file, required from main, that seems to do the trick.
var {WindowTracker} = require("window-utils");
var tracker = WindowTracker({
onTrack: function(window){
if (window.location.href == "chrome://browser/content/browser.xul") {
// This is a browser window, replace
// window.nsContextMenu.prototype.setTarget function
window.setTargetOriginal = window.nsContextMenu.prototype.setTarget;
window.nsContextMenu.prototype.setTarget = function(aNode, aRangeParent, aRangeOffset) {
window.setTargetOriginal.apply(this, arguments);
this.shouldDisplay = true;
};
};
}
, onUntrack: function(window) {
if (window.location.href == "chrome://browser/content/browser.xul") {
// In case we were called because the extension is uninstalled - restore
// original window.nsContextMenu.prototype.setTarget function
window.nsContextMenu.prototype.setTarget = window.setTargetOriginal;
};
}
});
Unfortunately this still does not bring up a context menu for disabled inputs, but this is not a show-stopper for me.
Many Thanks
The important piece of code in this extension can be seen here. It is very simple - it replaces nsContextMenu.prototype.setTarget function in each browser window and makes sure that it sets shouldDisplay flag for form controls.
The only problem translating this to Add-on SDK is that the high-level modules don't give you direct access to browser windows. You have to use the deprecated window-utils module. Something like this should work:
var {WindowTracker} = require("sdk/deprecated/window-utils");
var tracker = WindowTracker({
onTrack: function(window)
{
if (window.location.href == "chrome://browser/content/browser.xul")
{
// This is a browser window, replace
// window.nsContextMenu.prototype.setTarget function
}
},
onUntrack: function(window)
{
if (window.location.href == "chrome://browser/content/browser.xul")
{
// In case we were called because the extension is uninstalled - restore
// original window.nsContextMenu.prototype.setTarget function
}
}
});
Note that WindowTracker is supposed to be replaced in some future SDK version. Also, for reference: nsContextMenu implementation

Resources