How adding more links on the extension page action - google-chrome

I'm developing an extension page action that works only in a specific domain, can I add more than one link to the page action? My background.js is this.
it is possible to add more links in background.html for the extension page action?
//background.js
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'www.exemple.com' },
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);

Yes, you can register a page action for multiple sites by adding multiple PageStateMatchers to the list of conditions.
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostSuffix: 'example.com' }
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostSuffix: 'example.net' }
}),
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}]);
});
});
Note: I replaced urlContains with hostSuffix because you wanted to show the page action on certain domains, not on all pages whose URL contain the website's host (e.g. you probably don't want to match http://localhost/path/containing/www.example.com). See the documentation of the UrlFilter type for more ways to match pages.

With regular expressions you can match multiple domains with a single rule.
For example the following matches any Google search page in every country.
pageUrl: { urlMatches: '^(www\.)?(google.).*\/search\?', schemes: ['https'] },

Related

Vega-Lite: "1 in X" custom legend labels

I'm working on a choropleth map that shows the share of the population that has confirmed positive case of Covid-19 in each political jurisdiction. Similar to this example in the per capita Mapbox graphic on this page of the The New York Times.
I figured out just about every detail expect how to customize the legend. Currently, the labels display the shareOfPop as a number. Though, I want to prefix each label with "1 in ${shareOfPop}", and to add a suffix to the final label "1 in ${shareOfPop} or more".
enter image description here.
I've created this map in an Observable Notebook.
Things I've tried so far...
Making us of the custom legend encodings
To specify label text:
vl.color()
.fieldQ('shareOfPop')
.scale(
{
scheme: "yelloworangered",
domain: [250, 10],
clamp: true,
}
)
.legend({
title: "Share of Pop.",
encode: {
labels: {text: "1 in ${datum.value}"}
}
})
Register a custom formatter
Which I doubt I've accomplished correctly.
Here's what my configuration looks like (which is based on the config in the Introduction to Vega-Lite notebook).
vl = {
const [vega, vegalite, api, tooltip] = await Promise.all([
'vega#5.13.0',
'vega-lite#4.14.1',
'vega-lite-api#0.11.0',
'vega-tooltip#0.22.1'
].map(module => require(module)));
const options = {
config: {
// allow custom format types
customFormatTypes: true,
config: {
view: {continuousWidth: 400, continuousHeight: 300},
mark: {tooltip: null}
}
},
init: view => {
// initialize tooltip handler
view.tooltip(new tooltip.Handler().call);
// enable horizontal scrolling for large plots
if (view.container()) view.container().style['overflow-x'] = 'auto';
// register a custom expression function...am I doing this right???
vega.expressionFunction('1inX', function(datum) {
return `1 in ${datum}`
})
},
view: {
// view constructor options
loader: vega.loader({baseURL: 'https://cdn.jsdelivr.net/npm/vega-datasets#1/'}),
renderer: 'canvas'
}
};
return api.register(vega, vegalite, options);
}
Then I specify this custom formatType when defining the mark:
vl.color()
.fieldQ('shareOfPop')
.scale(
{
scheme: "yelloworangered",
domain: [250, 10],
clamp: true,
}
)
.legend({
title: "Share of Pop.",
formatType: "1inX",
})
)
Neither of these approaches produced any noticeable change.
Gonna answer my own question here.
Turns out Legend has a general labelExpr property that allows you to specify a Vega expression for customizing the label.
In my case, I wanted to always prepend the string "1 in ", and also append "+" when over may domain limit. Here's how I did it using the join() and if() functions.
...
vl.color()
.legend(
{
labelExpr: "join(['1 in ', datum.value, if(datum.value >= 250, '+', '')], '')"
}
)
This property isn't documented for Legend, though it is for for Axis).

Modify MediaWiki Search Form

Is there a way to modify the MediaWiki search form in the page header other than by editing Vector.php?
Basically, I would like to change/extend the markup of the the HTML form and add a JavaScript listener for Ajax calls.
Unfortunately, I can't seem to be able to find an appropriate hook.
That's not easily possible, if you want to change the HTML. But to add a JavaScript listener you usually don't need to add something directly to the input where you want to listen for events.
You could, e.g., use jQuery to add a listener to the search input. For this you could create a new extension (read this manual for a quick start). In your extension, you create a new resource module:
{
"#comment": "Other configuration options may follow here"
"ResourceFileModulePaths": {
"localBasePath": "",
"remoteSkinPath": "ExampleExt"
},
"ResourceModules": {
"ext.ExampleExt.js": {
"scripts": [
"resources/ext.ExampleExt.js/script.js"
]
}
},
"#comment": "Other configuration options may follow here"
}
Now, you can add the script file, which you defined in the module:
( function ( $ ) {
$( '#searchInput' ).on( 'change', function () {
// do whatever you want when the input
// value changed
}
}( jQuery ) );
The code in the function (in the second parameter of the on() function) will run whenever the value of the search input changes.
Now, you only need to load your module when MediaWiki output's the page. The easiest way is to use the BeforePageDisplay hook:
Register the hook handler:
{
"#comment": "Other configuration options may follow here"
"Hooks": {
"BeforePageDisplay": [
"ExampleExtHooks::onBeforePageDisplay"
],
},
"#comment": "Other configuration options may follow here"
}
Handle the hook (in ExampleExtHooks class, which needs to be created and added to the Autoload classes):
public static function onBeforePageDisplay( OutputPage &$output, Skin &$skin ) {
$output->addModules( array(
'ext.ExampleExt.js',
) );
return true;
}
First, I added a hook:
$wgHooks['BeforePageDisplay'][] = 'MyNamespace\Hooks::onBeforePageDisplay';
The hook is pretty simple:
public static function onBeforePageDisplay( \OutputPage &$out, \Skin &$skin ) {
$skin->template = '\MyNamespace\Template';
}
Finally, the Template class overrides the renderNavigation() method, which renders the search form:
<?php
namespace XtxSearch;
class Template extends \VectorTemplate {
protected function renderNavigation( $elements ) {
...
}
}

Creating Chrome extensions to hide DIV display:none; on a specific page

I'm trying to create my first Chrome extension.
It's basically an adblocker for specific elements, in this case - the Facebook comments section.
It works with the all_urls but not with that specific domain.
Manifest file:
{
"name": "My extension",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": ["http://visir.is/*"], //where your script should be injected
"css": ["style.css"] //the name of the file to be injected
}
]
}
style.css file:
.fbcomment {
display: none;
}
Any ideas how to correct "matches"?
I have tried *://visir.is/* as specified in https://developer.chrome.com/extensions/match_patterns but it only works with all_urls
Viktor,
You are on the wrong way. Your extension should work on Facebook site, and so the matches statement in the manifest must be exactly as the following:
"matches": ["https://www.facebook.com/*"]
Than you need to find all the comments in the timeline (most probably by css class), detect the presence of the target site address (//visir.is/) and then hide these comments.
Because the timeline dynamically load more posts you will also need to observe the new nodes and apply your function on them too (see the example from my Chrome extension below):
var obs = new MutationObserver(function (mutations, observer) {
for (var i = 0; i < mutations[0].addedNodes.length; i++) {
if (mutations[0].addedNodes[i].nodeType == 1) {
$(mutations[0].addedNodes[i]).find(".userContentWrapper").each(function () {
injectFBMButton($(this));
});
}
}
injectMainButton();
});
obs.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false });

Can you rename the "Option" label ? ( Chrome-Extension )

I tried this : https://developer.chrome.com/extensions/options.html and made an option page.
So a selection has been added under my extension icon with the name of Option.
My question is that is there a way to rename Option and change it something like Setting or some words in other languages ?
The "Options" label at chrome://extensions is automatically adapted to the user's language. Extensions cannot change the value of this label.
The value of the "Options" option at the dropdown menu at the extension's button cannot be customized either, but you can create a new context menu item under the button as of Chrome 38. E.g.
chrome.contextMenus.create({
id: 'show-settings', // or any other name
title: 'Settings',
contexts: ['page_action', 'browser_action']
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if (info.menuItemId == 'show-settings') {
chrome.tabs.create({
url: chrome.runtime.getURL('settings.html')
});
}
});
I suggest to just stick to "Options" though, because users do already know what the option does. Consistency in UI/UX is important, imagine how you productive you'd be if every application had a different way of (e.g.) closing/quiting the application.
manifest.json to test the previous script:
{
"name": "Contextmenu on browserAction button",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "Right-click to see a context menu"
},
"permissions": [
"contextMenus"
]
}
Easier way to trigger events.
chrome.contextMenus.create({
title: 'GitHub',
contexts: ['page_action'],
onclick: () => console.log('GitHub'),
});

How do I get a Chrome Extension PageAction icon to appear in the address bar?

I'm trying to build a Chrome Extension that appears as an icon in the address bar which, when clicked, sets contenteditable=true on all elements on the page, and then when clicked again sets them back to contenteditable=false.
However, I'm falling at the first hurdle... The icon isn't even showing up in the address bar.
Here's my manifest file:
{
"name": "Caret",
"version": "1.0",
"description": "Allows you to edit the content on any webpage",
"page_action": {
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["jquery.js", "caret.js"]
}
],
"permissions" : [
"tabs"
]
}
and here's the caret.js script:
chrome.browserAction.onClicked.addListener(function(Tab) {
$("*").attr("contenteditable",true);
});
This is my first attempt at an extension, so it's quite probably a newbie mistake, but I'd really appreciate any help or advice!
Ok, turns out I needed to use chrome.pageAction.show(tab.id);, which meant I needed to get the ID of the current tab, which is achieved with:
chrome.tabs.getSelected(null, function(tab) {
chrome.pageAction.show(tab.id);
});
BUT it turns out you can't use chrome.tabs within a content script, so I had to switch to using a background page instead.
This is no longer possible as of last release.
Chrome extension page action appearing outside of address bar
https://groups.google.com/a/chromium.org/forum/#!searchin/chromium-extensions/upcoming/chromium-extensions/7As9MKhav5E/dNiZDoSCCQAJ
My answer to this other question gives the solution. FYI, the second code issue noted in that answer is also relevant to your code: You want the icon to appear for all pages, so you should use browser_action, not page_action. Either will work, but using a page action on every page goes against convention and makes for a less consistent end-user experience.
I had a similar problem, here are the steps I followed to solve it:
I altered my manifest.json to include the following:
{
"background": {
"scripts": ["background.js"],
"persistent":false
},
"page_action": {
"default_icon": "logo.png",
"default_title": "onhover title",
"default_popup": "popup.html"
}
}
Then I inserted the following code into my background script:
// When the extension is installed or upgraded ...
chrome.runtime.onInstalled.addListener(function() {
// Replace all rules ...
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
// With a new rule ...
chrome.declarativeContent.onPageChanged.addRules([
{
// That fires when on website and has class
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostContains: 'myurl', schemes: ['https', 'http'] },
css: [".cssClass"]
})
],
// And shows the extension's page action.
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
The documentation for this can be found here... https://developer.chrome.com/extensions/declarativeContent
I did this:
chrome.tabs.onUpdated.addListener(function(id, info, tab){
if (tab.url.toLowerCase().indexOf("contratado.me") > -1){
chrome.pageAction.show(tab.id);
}
});