I'm building a little Spotify app that displays tweets from the current Artist playing. I'm using Bocoup's jQuery Twitter plugin to grab and display the tweets: http://code.bocoup.com/jquery-twitter-plugin/
MANIFEST.JSON
{
"BundleType": "Application",
"AppIcon": {
"18x18": "tutorial.png"
},
"AppName": {
"en": "News"
},
"SupportedLanguages": [
"en"
],
"RequiredPermissions": [
"http://twitter.com"
"http://*.twitter.com"
"http://*.twimg.com"
],
"VendorIdentifier": "com.News",
"RequiredInterface": "1",
"BundleVersion": "0.2",
"BundleIdentifier": "News",
"AppName": "News",
"AppDescription": "Twitter updates from the Artist playing."
}
From the Index file:
<script type="text/javascript">
$(document).ready(function() {
$('#tweets').twitter({from: 'mediatemple', replies: false})
launch();
});
</script>
</head>
<body>
<div id="info">
</div>
<div id="news">
</div>
<div id="tweets">
</div>
</body>
Nothing displays in Spotify when I open my app, but if I open the index.html file in a browser, the tweets appear. What am I missing?
The RequiredPermissions JSON needs commas.
try:
"RequiredPermissions": [
"http://twitter.com",
"http://*.twitter.com",
"http://*.twimg.com"
],
Things fail silently if there is a problem in the manifest. Always use a JSON linter (http://jsonlint.com/) to verify at least the format is proper JSON.
UPDATE: After any changes to manifest.json you must restart Spotify.
Related
I am pretty new in the Chrome Extensions field.
I am trying to build an extension to visit some websites and collect information from their HTML.
I am having a hard time getting chrome.scripting.executeScript working properly.
Source Code
manifest.json
{
"name": "Scraper",
"description": "Simple Extension to Scrape Websites, and Push Them to ConnectionSphere for Data Enrichment",
"version": "2.0",
"permissions": ["storage", "webRequest", "scripting", "declarativeContent", "activeTab", "tabs", "downloads", "*://*/*", "http://connectionsphere.com:80/*", "http://connectionsphere.com/api1.0/emails/verify.json"],
"host_permissions": [ "https://www.amazon.com/*", "https://connectionsphere.com/*", "https://github.com/*" ],
"manifest_version": 3,
"icons": {
"48": "/48.png",
"128": "/128.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"48": "/48.png",
"128": "/128.png"
}
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<title>Scraper</title>
</head>
<body>
<div id="notify-wrapper">
<div id="notify-header">
<h1>Scraper!</h1>
</div>
<div id="notify-containers">
<div class="login-form">
<input type="button" id="start" name="start" value="Start" />
<p id="text" name="text"></p>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>
popup.js
'use strict';
let text = document.getElementById('text');
function upload_page() {
alert('b');
document.body.innerHTML = 'hola';
return document.title;
}
start.onclick = function() {
let page_url_value = 'https://github.com/';
text.innerHTML = 'Scraping page...';
chrome.tabs.query({active: true, currentWindow: true}, async function(tabs) {
// get the tab id
var tab_id = tabs[0].id;
// go to the page
chrome.tabs.update({url: page_url_value});
// fired when tab is updated
chrome.tabs.onUpdated.addListener(function openPage(tabID, changeInfo) {
// tab has finished loading
if(tab_id == tabID && changeInfo.status === 'complete') {
// remove tab onUpdate event as it may get duplicated
chrome.tabs.onUpdated.removeListener(openPage);
// execute content script
alert('a');
chrome.scripting.executeScript(
{
target: {tabId: tab_id, allFrames: true},
func: upload_page
},
// Get the value returned by do_login.
// Reference: https://developer.chrome.com/docs/extensions/reference/scripting/#handling-results
(injectionResults) => {
for (const frameResult of injectionResults)
text.innerHTML = frameResult.result;
}
);
}
});
});
};
The Problem
When the user clicks on the "start" button of the popup, the extension visits a page and calls chrome.scripting.executeScript to run a function that works with the DOM of such a page. But such execution is not performed (thealert('a') happens, but the alert('b') is never executed).
If I refresh the page manually from the browser and click on the "start" button again, then the chrome.scripting.executeScript runs.
I researched for an answer into other posts here, but I didn't find anything.
The answers in this post didn't help me.
I wrote a small test-unit to show the problem I am facing.
It worked after I removed the extension and added it again. Thanks!
How can you enable chrome extension on a specific web site? for an example
Activate or enable the chrome extension when you visit on a specific website say www.test.com
if the user browser through another than www.test.com then the icon should be deactivate or disable the chrome extension.
I have read about the pageAction and try to do the following:
manifest.js
{
"manifest_version": 2,
"name": "PageAction Sample",
"description": "PageAction Sample",
"version": "0.0.1",
"page_action": {
"default_icon": {
"32": "icon32.png"
}
},
"background": {
"scripts": [ "background.js" ],
"persistent": false
},
"permissions": [ "activeTab", "tabs" ]
}
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.url) {
if (changeInfo.url == 'test.com)) {
chrome.pageAction.show(tabId);
} else {
chrome.pageAction.hide(tabId);
}
}
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {
file: "login.js"
});
});
popup.html
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h3>Login Form</h3>
<form>
Username: <input id="username" type="text" name="username"> <br>
Password: <input id="password" type="password" name="password"> <br>
<input id="loginbutton" type="button" value="Login">
</form>
<script>
document.getElementById('loginbutton').onclick = function(event) {
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
setTimeout(function() {
alert('Username: ' + username + ' and Password: ' + password);
});
};
</script>
</body>
</html>
Show the UI (popup.html) page only the url is test.com
There are several problems here.
A bug in Chrome that always shows the extension's icon as active on all URLs.
You'll have to manually change the icon via chrome.pageAction.setIcon in onUpdated event. A more ergonomic/proper solution would be to use chrome.declarativeContent API (instead of onUpdated) with two actions: SetIcon and ShowPageAction (some demos).
Make a grayscale version of your main icon and specify it as the default icon in manifest.json, then use the above methods to set the normal icon on the matched site.
popup.html isn't specified anywhere. Add "default_popup": "popup.html" inside page_action section as shown in the documentation.
An inline <script> doesn't work in extensions by default so extract it to a separate popup.js file loaded as a standard tag like <script src=popup.js></script>.
chrome.pageAction.onClicked won't work with default_popup so move the contents of onClicked listener (executeScript block) into popup.js, right at the start of it or inside a click listener for some button.
Open the correct devtools console to observe the errors and output instead of using alert.
I'm trying to create a chrome extension, so I'm doing tutorials to learn and reading a bunch, but I'm struggling. I'm doing this tutorial. But long-term, from the extension I need users to be able to login to their account, then as they're browsing, send the url that they're at to their account.
popup.html
<!doctype html>
<html>
<head>
<title>Add a Snippet</title>
<script src="popup.js"></script>
<link rel="stylesheet" type="text/css" href="popup.css">
</head>
<body>
<h1>Add a Snippet</h1>
<form id="form">
<textarea id="code"></textarea>
<button type="submit" id="checkPage">Add Snippet</button>
</form>
</body>
</html>
popup.js
What I REALLY don't understand is that according to the console.log lines that I have in there and the error, it's loading the DOMContent, and it doesn't have any problem with finding the form by the id (let f = document.getElementById('form');). But it bombs when I try to attach an event listener?
document.addEventListener('DOMContentLoaded', function() {
console.log('the domcontentloaded');
let f = document.getElementById('form');
f.addEventListener('submit', function(e){
console.log('the form was submitted');
e.preventDefault();
})
}, false);
manifest.json
{
"name": "My Awesome Plugin",
"description": "This extension will be awesome",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "This is Awesome"
},
"background": {
"scripts": ["jquery-2.2.3.min.js", "background.js","popup.js"],
"persistent": false
},
"permissions": [
"activeTab",
"declarativeContent",
"https://ajax.googleapis.com/",
"storage",
"tabs",
"http://*/*",
"https://*/*"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["login.js"]
}
],
"manifest_version": 2
}
login.js
console.log('login.js is ready to party');
When I load, I get this in the background inspector (or whatever it's called). So it's not finding the form.
So I looked at the elements, and I'm confused because it's not showing the form or the textarea. But when I click on the chrome extension icon, it's there.
1/Remove popup.js from "background/scripts" section of your manifest.
2/Add popup.js as a script reference in your popup.html file.
This way, popup.js will operate in the context of the popup.html DOM.
I'm developing a chrome extension and I want to display in the popup (when a user click extension icon) a page that has an url of localhost, in this page I will check if a user is logged in my site and depend on status I will display content in the page.
So I tried these:
First:
create a popup.html (that doesn't contain the iframe)
in popup.js create an iframe and give it an src, width, height. than append it to the body.
Second:
in the popup.html add the iframe with the src of localhost.
in popup.js create an iframe and give it an src, width, height. than append it to the body.
Neither the first nor the second works. and I get this:
But when I use a normal site in src, like http://bing.com it works and show the page of bing.com
This is a MVCE example that I developed:
The HTML files are:
index.html is the file that is served through the web server
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
popup.html is the extension popup content
<html>
<body>
<div id="container">
</div>
<script src="content.js"></script>
</body>
</html>
with the manifest for the extension:
manifest.json
{
"manifest_version": 2,
"name": "Test Popup",
"version": "0.1",
"browser_action": {
"default_title": "Popup Test",
"default_popup": "popup.html"
},
"permissions": [
"tabs", "<all_urls>"
],
"content_scripts": [
{
"matches": [
"http://*/*"
],
"js": [
"content.js"
]
}
]
}
All you need is a server for the external file to include, I used ruby:
serve.rb
require 'webrick'
s = WEBrick::HTTPServer.new(:Port => 8888, :DocumentRoot => Dir.pwd).start
All the magic happens in the content javascript:
content.js
function addiframe() {
div = document.getElementById("container");
var frame = document.createElement('iframe');
frame.setAttribute('width', '500px');
frame.setAttribute('height', '500px');
frame.setAttribute('frameborder', '0');
frame.setAttribute('id', 'inject');
frame.setAttribute('src', 'http://localhost:8888');
div.appendChild(frame);
};
addiframe();
and this is an image that shows the result:
My extension is intended to inject some HTML elements using local JavaScript libraries such PrimeUI, jQueryUI and its correspondent CSS stylesheets.
The best way I have found to do so, is to inject the HTML as follows:
// test.js
$.get(chrome.extension.getURL('/overlay.html'), function(data) {
$($.parseHTML(data)).appendTo('body');
}
// manifest.json
{
"name": "Test",
"version": "1.0",
"manifest_version": 2,
"options_page": "",
"description": "Test",
"browser_action": {
"default_title": "Test",
"default_popup": ""
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"js/jquery-3.1.1.min.js",
"js/test.js"
]
}
],
"permissions": [
"tabs"
],
"web_accessible_resources": [
"overlay.html",
"css/font-awesome.min.css",
"css/jquery-ui.min.css",
"css/primeui-all.min.css",
"js/jquery-3.1.1.min.js",
"js/jquery-ui.min.js",
"js/primeelements.min.js",
"js/primeui-all.min.js",
"js/main.js"
]
}
I have the required JavaScript libraries inside "js" folder in the root directory, for security reasons I do not retrieve them from a CDN.
My HTML contains CSS and JS on <head> section, but the styles nor the scripts applies in any way.
<html>
<head>
<link rel="stylesheet" href="css/font-awesome.min.css"/>
<link rel="stylesheet" href="css/jquery-ui.min.css"/>
<link rel="stylesheet" href="css/primeui-all.min.css"/>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="js/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/primeui-all.min.js"></script>
<script type="text/javascript" src="js/x-tag-core.min.js"></script>
<script type="text/javascript" src="js/primeelements.min.js"></script>
</head>
<body>
<button id="btn-show" type="button">Show</button>
<div id="dlg" title="Godfather I">
<p>The story begins as Don Vito Corleone, ...</p>
</div>
</body>
</html>
// main.js
$(function() {
$('#dlg').puidialog({
showEffect: 'fade',
hideEffect: 'fade',
minimizable: true,
maximizable: true,
responsive: true,
minWidth: 200,
modal: true,
buttons: [{
text: 'Yes',
icon: 'fa-check',
click: function() {
$('#dlg').puidialog('hide');
}
},
{
text: 'No',
icon: 'fa-close',
click: function() {
$('#dlg').puidialog('hide');
}
}
]
});
$('#btn-show').puibutton({
icon: 'fa-external-link-square',
click: function() {
$('#dlg').puidialog('show');
}
});
}
The button is successfully displayed but with no events are attached nor styles.
i.e: if I inject this code on StackOverflow my button get the styles from SO and not mine.
I want to avoid as much as possible JavaScript for creating elements, or injecting tags programmatically, to separate the View from the Controller.
How can I manage to use my styles and scripts with my injected HTML as we do ordinarily? I have tried adding them to web_accessible_resources, and other manifest fields unsuccessfully.
Makyen explained:
It is not possible to parse HTML with <head> elements hardcoded such <script> and <link>. Instead it should be injected in other way.
The ways I have chosen to inject the files are:
For the CSS:
// Test.js
/** CSS Injection */
var link = document.createElement("link");
link.href = chrome.extension.getURL("css/jquery-ui.min.css");
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
For the JS:
// Test.js
/** JavaScript Injection */
var s = document.createElement('script');
s.src = chrome.extension.getURL('js/jquery-3.1.1.min.js');
// "When an inline script is inserted in the document, it's immediately executed
// and the <script> tag can safely be removed". – Rob W.
s.onload = s.remove;
(document.head || document.documentElement).appendChild(s);
Trying to insert large amounts of code/libraries as into the page context using tags has a significant chance of interfering with the current contents/JavaScript of the page. Is there a reason that you are inserting scripts into the page context? Normally, you would have these inserted scripts (and CSS) as content scripts (manifest.json
content_scripts, or chrome.tabs.executeScript()/chrome.tabs.insertCSS(). not in the page context. – Makyen
With the above code I have successfully injected the files, but the styles and functions are applied only sometimes, I will edit when I fix this.