add multiple chrome inline installations for different link tags same domain - google-chrome

I have a Chrome extension, and a Chrome app. I need inline install for both of them on the same domain.
As per Googles instructions (for one inline install) I add the header link tag:
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID">
Then add the onclick function in the body:
<button onclick="chrome.webstore.install()" id="install-button">Add to Chrome</button>
<script>
if (chrome.app.isInstalled) {
document.getElementById('install-button').style.display = 'none';
}
</script>
What I need to know is how to add two instances. One for the extension, and one for the app. Do I add two link tags in the header, then edit the onclick function?
This is what Google says to do for multiple instances, but I don't understand where to edit the onclick function to differentiate between the two.
To actually begin inline installation, the
chrome.webstore.install(url, successCallback, failureCallback)
function must be called. This function can only be called in response
to a user gesture, for example within a click event handler; an
exception will be thrown if it is not. The function can have the
following parameters:
url (optional string) If you have more than one tag on your
page with the chrome-webstore-item relation, you can choose which item
you'd like to install by passing in its URL here. If it is omitted,
then the first (or only) link will be used. An exception will be
thrown if the passed in URL does not exist on the page.
successCallback (optional function) This function is invoked when
inline installation successfully completes (after the dialog is shown
and the user agrees to add the item to Chrome). You may wish to use
this to hide the user interface element that prompted the user to
install the app or extension.
failureCallback (optional function) This
function is invoked when inline installation does not successfully
complete. Possible reasons for this include the user canceling the
dialog, the linked item not being found in the store, or the install
being initiated from a non-verified site. The callback is given a
failure detail string as a parameter. You may wish to inspect or log
that string for debugging purposes, but you should not rely on
specific strings being passed back.
I currently have one link tag in my header for the extension. I need to add another inline installation, on a different page, same domain, but this second onclick code needs to be different so it doesn't refer to the existing link tag in my header.
Many thanks.

<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID1">
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/itemID2">
<button onclick="chrome.webstore.install('https://chrome.google.com/webstore/detail/itemID1')" id="install-button-1">Add App to Chrome</button>
<button onclick="chrome.webstore.install('https://chrome.google.com/webstore/detail/itemID2')" id="install-button-2">Add Extension to Chrome</button>

The very same docs page shows a method for the extensions.
Basically, your extension can inject a <div id="somethingYouExpect"> into the DOM, and the page's script can detect that.
It's a bit clunky though: I was trying to get it to work for test code and didn't manage to do so in a good way, as content scripts are injected either before DOM is constructed at all or after document ready fires. You can bypass that with mutation observers, but meh and your button will be visible for a split second.
You can save yourself some pain, if you're just hiding an element, by injecting a css file hiding it. Or, you can hide the elements from injected code. Either way is somewhat layout-sensitive though.
If you HAVE to be layout-independent and at the same time want something more complex than element hiding, either go the (div inject + mutation observer) route or you can try window.postMessage approach to signal the page to hide the element.
Step by step guide for the extension / CSS variant.
Suppose your extension install UI is contained in an element with id extension-install.
Add a content script to the manifest file:
"content_scripts": [
{
"matches": ["*://yourdomain/*"],
"css": ["iaminstalled.css"],
"run_at": "document_start"
}
],
The CSS:
#extension-install {
display: none !important;
}
So, to recap:
To allow installs of both the app and the extension, you need two <link> tags in the head
To install either you pass the url parameter to chrome.webstore.install
If the app is installed, it will define chrome.app.isInstalled in the page's context. You can check for it from the page to hide the install button.
If the extension is installed, it can inject CSS/JS into page to hide the install button.

Related

Chrome Automatically Highlighting Address Bar On New Tab Open [duplicate]

With Chrome 27, it seems that extensions that override Chrome's New Tab Page can't take focus away from Chrome's Omnibox like they used to in previous versions of Chrome.
Is there a new way to focus an input box in a New Tab Page, or has this functionality been disabled completely? :(
To test this, create an extension folder with three files:
1. manifest.json:
{
"name": "Focus Test",
"version": "0",
"minimum_chrome_version": "27",
"chrome_url_overrides": {
"newtab": "newTab.html"
},
"manifest_version": 2
}
2. focus.js:
document.getElementById('foo').focus();
3. newTab.html:
<html>
<body>
<input id="foo" type="text" />
<script type="text/javascript" src="focus.js"></script>
</body>
</html>
Then, when you load the extension and open a new tab, the input field does not get focused on the new tab page.
I have also tried adding the autofocus attribute to the input field, but no luck either. The extension's new tab page can't take focus away from Chrome's Omnibox.
Any ideas? Is this a bug or a new "feature"?
ManifestV3 update
This answer is adapted from https://stackoverflow.com/a/11348302/1754517.
This has been tested with both Manifest V2 and V3.
Tested in Google Chrome 99.0.4844.51 64-bit (Windows 10).
Replace the content of focus.js with:
if (location.search !== "?x") {
location.search = "?x";
throw new Error; // load everything on the next page;
// stop execution on this page
}
Add the autofocus attribute to the <input>.
Go to the Extensions page in Chrome and click the Load unpacked button. Choose the folder of your extension.
Open your new tab page. You might see a modal dialogue reading Change back to Google?. Click Keep it to keep your custom new tab page.
Inline Javascript - Manifest V2 only
If you're inlining the Javascript in the HTML file, then you'll need to take some extra steps:
After adding your inline Javascript to your HTML file, open DevTools (F12 key) and observe the error output in the Console. Example output you should see:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem:".
Either the 'unsafe-inline' keyword, a hash ('sha256-MK0Gypb4mkZTI11eCOtWT+mGYcJNpN5zccvhfeaRb6E='), or a nonce ('nonce-...') is required to enable inline execution.
Select & copy this hash.
Add a line to manifest.json to allow the JS to run, pasting in the hash you just copied between the single-quotes. E.g.:
"content_security_policy": "script-src 'self' 'sha256-MK0Gypb4mkZTI11eCOtWT+mGYcJNpN5zccvhfeaRb6E='"
Go to the Extensions page again. Remove the extension, then re-add it using the Load unpacked button.
Open your new tab page. Your extension should now autofocus on the <input>.
Note inlining only works with Manifest V2; Manifest V3 returns a failure message when attempting to load the extension (even with a properly formed "content_security_policy" object in manifest.json, to replace the Manifest V2 "content_security_policy" string):
Failed to load extension
File C:\path\to\extension
Error 'content_security_policy.extension_pages': Insecure CSP value "'sha256-...'" in directive 'script-src'.
Could not load manifest.
As per the Chrome Extension Documentation,
Don't rely on the page having the keyboard focus.
The address bar always gets the focus first when the user creates a new tab.
See reference here: Override Pages
Here's the solution for Manifest v3
chrome.tabs.onCreated.addListener((tab) => {
if (tab.pendingUrl === 'chrome://newtab/') {
chrome.tabs.remove(tab.id)
chrome.tabs.create({
url: '/index.html',
})
}
})
I saw a pretty old blog which updates the new tab conditionally. However, simply updating the tab does not steal the focus. I had to close the pending tab and open a new one.
Cons: An ugly chrome-extension://akfdobdepdedlohhjdalbeadhkbelajj/index.html in the URL bar.
I have a cheap work around that allows stealing focus from address bar focus. It's not for everyone. I do actually do use this because I want to control a new tab focus just that bad in my own custom new tab solution:
<script>
alert('Use enter key to cancel this alert and then I will control your focus');
document.getElementById('...AckerAppleIsCrafty...').focus()
</script>
USE CASE: I built my own HTML chrome custom tab that has a search input that custom searches my history and bookmarks the way I like it too.
Cash me focusing outside how bout dat?

How can you click an href link but block the linked page from displaying

It was hard to encapsulate my question in the title.
I've rewritten a personal web page that made extensive use of javascript. I'm simplifying matters (or so I hope).
I use a home automation server that has a REST interface. I can send commands such as 'http://192.168.0.111/rest/nodes/7%2032%20CD%201/cmd/DON to turn on a light. I'm putting links on my simplified web page using an href tag. The problem is that it opens the rest interface page and displays the XML result. I'd like to avoid having that page show up. ie when you click on the link it 'goes' to the link but doesn't change the page.
This seems like it should/would not be possible but I've learned not to underestimate the community.
Any thoughts?
You can use the fetch function if your browser is modern enough:
document.querySelector(lightSelector).addEventListener('click', e => {
e.preventDefault(); // prevent the REST page from opening
fetch(lightURL).then // put promises here
})
The variables lightSelector and lightURL are expected to be defined somewhere.
The code listens for clicks on the link, and when one comes, we prevent the REST page from opening (your intention) then we send a request to your light URL with fetch. You can add some promises to deal with the response (e.g. print "light on" or "light off" for example) using then but that's another matter.
If you make the "link" a button, you can get rid of e.preventDefault(); which is the part preventing the REST page from opening.

Inject HTML signature into Gmail from hosted page

I have the basic shell of a Chrome extension done and have come to the point where I am trying to inject an HTML signature into Gmail using code hosted on an unindexed page on my site. The reason I want to do this is to be able to include web fonts, something that for the life me I can't figure out why Gmail hasn't allowed you to do from their font library.
In any regard, as I said, I have a right-click context menu option ready to trigger a script from my js function page and the extension loads without errors. I need to figure out the best way to inject the HTML into the email and without losing any of the formatting that has been done on the page.
I have created the extension manifest, set the permissions on the context menu and created a function to call back to the js page that will inject the signature.
var contextMenus = {};
contextMenus.createSignature =
chrome.contextMenus.create(
{"title": "Inject Signature",
"contexts": ["editable"]},
function (){
if(chrome.runtime.lastError){
console.error(chrome.runtime.lastError.message);
}
}
);
chrome.contextMenus.onClicked.addListener(contextMenuHandler);
function contextMenuHandler(info, tab){
if(info.menuItemId===contextMenus.createSignature){
chrome.tabs.executeScript({
file: 'js/signature.js'
});
}
}
The end result is nothing enters the page and get massive errors related to cross-site because the domain is not the same obviously. This has obviously been solved as there are numerous signature extensions out there. I would probably use one of theirs but a) I want to build it on my own, b) they all want you to use their templates, none of them that I have seen will let you just use your own code.
So, any ideas?

HTML Imports with the Async flag - strange behaviour in Chrome

I am trying to optimise the loading of Polymer Elements in my Polymer based web app. In particular I am concentrating my effort around the initial start up screens. Users will have to log on if they don't have a valid jwt token held in a cookie.
index.html loads an application element <pas-app> which in turn loads an session manager (<pas-eession>). Since the normal startup will be when the user is already logged on the element that handles input of user name and password (<pas-logon>) is hidden behind a <template is="dom-if"> element inside of <pas-session>and I have added the async flag to its html import line in that element as well - thus :
<link rel="import" href="pas-logon.html" async>
However, in chrome (I don't experience this in firefox, where html imports are polyfilled) this async seems to flow over embedded <script> element inside the custom element. In particular I get a type error because the script to cause it to be regestered as a custom element thinks Polymer is not a function.
I suspect I am using the wrong kind of async flag - is there a way to specify that the html import should not block the current element, but should block the scripts inside itself when loaded.
I think I had the same problem today and found this question when searching for a solution. When using importHref async I get errors like [paper-radio-button::_flattenBehaviorsList]: behavior is null, check for missing or 404 import and dependencies are not loaded in the right order. When I change to async = false the error messages are gone.
It seems that this is a known bug of Polymer or probably Chrome https://github.com/Polymer/polymer/issues/2522

How to Include "onclick" Object in WordPress HTML

I'm using attempting to add an "onclick" object to a page in a singlesite (i.e. rather than multisite) WordPress that triggers an event. The code is:
Send a voice message
When attempting to save the code, WordPress strips the onclick object leaving:
Send a voice message
A user on another forum suggested that this restriction should only apply to multisite non-superadmin users. Again, this is a siglesite with only one admin user.
It is understood that WordPress removes "onclick" from HTML to prevent malicious code. Still, does anyone know how to resolve this?
Thanks.
It appears that with current Wordpress (I'm on 4.9.4), TinyMCE does the filtering directly on the editor screen, not when the form is submitted. The allowedtags and allowedposttags don't seem to matter, so the solution above does not solve the problem for me.
The method I have developed uses the tiny_mce_before_init filter to alter the allowed tags within TinyMCE. The trick is to add the extended_valid_elements setting with the updated versions of the elements allowed for a.
First, look in the page http://archive.tinymce.com/wiki.php/Configuration3x:valid_elements to find the current value for a, which right now is
a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur]
And add to the end of that the onclick attribute:
a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick]
Then use that in the filter function like this:
function allow_button_onclick_mce($settings) {
$settings['extended_valid_elements'] = "a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick]";
return $settings;
}
add_filter('tiny_mce_before_init', 'allow_button_onclick_mce');
which you install in your functions.php file in Wordpress. You can see it in action by toggling the text and visual view on the edit page. Without the extended list, the onclick goes away. With it, it remains.
You can solve this by changing the anchor tag into button and adding a script. For more info please refer to this link: Wordpress TinyMCE Strips OnClick & OnChange (need jQuery).
By resolving, I'm assuming you mean to allow the onclick attribute. You will want to be careful with this, because modifying the allowed tags does this for all your users.
You can modify the list of allowed tags and attributes, by adding this to your functions.php file:
function allow_onclick_content() {
global $allowedposttags, $allowedtags;
$newattribute = "onclick";
$allowedposttags["a"][$newattribute] = true;
$allowedtags["a"][$newattribute] = true; //unnecessary?
}
add_action( 'init', 'allow_onclick_content' );
I suggest trying it with only $allowedposttags first to see if that works for you. According to this other stackexchange post, you should only need allowedtags if you need it for comments or possibly non-logged-in users, but when I did something similar in the past, I needed both of them to work.
On a side note, if you want a list of all already allowed tags and attributes, look inside your /wp-includes/kses.php file.