Adding checkbox settings to a Safari extension - javascript

I wrote this extension that basically changes the look of a website using CSS and JS. But now I want to add some checkbox settings to the extension so users can toggle features of the website.
I tried reading the documentation, and searched all over the web. Even tried to look for demo extensions that I could reverse engineer, but to no avail.
Let's say I want to add a "Check Box", title it "sidebar" and given it a "key" value of "tg_sidebar". Can someone explain how I would add an event listener for this, and then trigger some jquery code?
[I think this StackOverflow query [http://stackoverflow.com/questions/3032945/safari-extension-how-to-respond-to-settings-changes] makes things clear, but it still doesn't explain much.]
Here's one thing that worked.
function numberChanged(event)
{
if(event.key == "tg_sidebar")
alert("Number has changed!");
}
safari.extension.settings.addEventListener("change",numberChanged,false);
[Screenshot of the Extension Settings window: http://dznr.org/56wi]
Now whenever I toggle the setting, I get an error. But replacing that alert function with say adding or removing a CSS class doesn't work.
I also tried using the code by the answerer below, but that doesn't do anything. Would have been perfect to be able to look at the code of some extension…
One more thing, in case it wasn't clear, is that the setting should make the change permanent. That is, when the setting is ticked, it should do that action every time the page loads.

Assuming you have it setup in your extensions.
It's pretty simple. Every time your function is called in your global.html call this:
var type = safari.extension.settings.yourSettingsCall;
example:
var type;
function performCommand(event)
{
if (event.command === "start-event") {
type = safari.extension.settings.tg_sidebar;
}
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("type", type);
}
then your inject.js add these:
safari.self.addEventListener("message", handleMessage, false);
and
function handleMessage(event){
if (event.name === "type") {
//run code
}
}

Related

JavaScript - My checkbox (which is checked by default) doesn't run it's script on page load

I apologize if this is something really simple, but I'm relatively new to JavaScript. I've scoured the web to find a solution but haven't found anything!
So I'm building a sort of "settings" UI for a Google Chrome extension popup and I'm using checkboxes to enable/disable options. I want one of the checkboxes to be checked by default, so I have the checked attribute defined in its HTML like so;
<input type="checkbox" id="option1" style="margin-left: 20px;" checked>
<!-- ^ Right here ^ -->
<script src="script.js"></script>
I implemented a script here so that if the checkbox is checked, a certain script will be programmatically injected. If it isn't checked, it will inject a different script. Code:
document.getElementById("option1").addEventListener("click", toggleOption1);
function toggleOption1() {
var option1 = document.getElementById("option1");
// if option1 is checked, run first script
if (option1.checked === true) {
chrome.tabs.executeScript({
file: 'optionEnabled.js'
});
// otherwise, run script 2
} else {
chrome.tabs.executeScript({
file: 'optionDisabled.js'
});
}
}
Now, this has worked great for me so far, it does exactly what it intends to do except for one thing:
I want the code to be run automatically because, duh, the checkbox is checked by default. The code only recognizes when the box is unchecked or checked by the user.
Note: I am aware that this line of code
document.getElementById("option1").addEventListener("click", toggleOption1);
means that the function is run on click and I should just use onclick="toggleOption1()" instead, but because I am making a chrome extension, inline scripts are not allowed.
Note 2: I would appreciate it if the solution could avoid JQuery or other external libraries, but if nothing else is available, I guess it's okay!
Note 3: I would provide a JSFiddle, but I don't believe there's a way to implement the chrome extension environment.
Anyone out there know a way to fix this? I've been confuzzled for several days and I'd really like to fix this issue.
Thanks in advance!
call
toggleOption1();
after
document.getElementById("option1").addEventListener("click", toggleOption1);
EDIT
You should use something like DOMContentsLoaded event to make sure the Data Object Model is loaded
JavaScript
window.addEventListener('DOMContentLoaded', (event) => {
document.getElementById("option1").addEventListener("click", toggleOption1);
toggleOption1();
});
function toggleOption1() {
var option1 = document.getElementById("option1");
// if option1 is checked, run first script
if (option1.checked === true) {
console.log("checked");
// chrome.tabs.executeScript({
// file: 'optionEnabled.js'
// });
// otherwise, run script 2
} else {
console.log("not checked");
// chrome.tabs.executeScript({
// file: 'optionDisabled.js'
// });
}
}
Since you know by default that checkbox is checked then you can simply execute your code
chrome.tabs.executeScript
From the background script and not from the popup script.
Background script is loaded once the extension is loaded.
Background script has one instance for all tabs.
update:
It will do it only one time when the extension is loaded. So no problem for the user to play with the checkbox after that from thr popup

Connecting a 'clicked' signal to the indicator

I wrote a PanelMenu.Button-derived class for shell 3.36 by following the tutorial at:
https://wiki.gnome.org/Projects/GnomeShell/Extensions/Writing
Everything works (after a few 3.36-related tweaks I had to do) but now I would like to have a single left click show/hide the application and single right click open the menu. For that I wanted to catch a 'clicked' signal but PanelMenu.Button only emits menu-set. I'd need something like this:
indicator.connect("clicked", () => GLib.spawn_command_line_async("my_app"));
Is there a widget that supports the 'clicked' signal?
I think looking for a another widget might be more work than it's worth. If you look here at the implementation, they're really just overriding the event vfunc to open the menu.
vfunc_event(event) {
if (this.menu &&
(event.type() == Clutter.EventType.TOUCH_BEGIN ||
event.type() == Clutter.EventType.BUTTON_PRESS))
this.menu.toggle();
return Clutter.EVENT_PROPAGATE;
}
If you've subclassed yourself and don't need the menu, you can simply do a similar thing just by redefining the virtual function like so (just put this in your subclass like a regular function):
vfunc_event() {
if ((event.type() == Clutter.EventType.TOUCH_BEGIN ||
event.type() == Clutter.EventType.BUTTON_PRESS))
GLib.spawn_command_line_async("my_app");
return Clutter.EVENT_PROPAGATE;
}
However, you may want to change the events to BUTTON_RELEASE and TOUCH_END so it happens when the user releases the button, giving them a chance to change their mind by dragging the mouse away.
Did you try:
indicator.connect("button-press-event", () => GLib.spawn_command_line_async("my_app"));
The signal you are looking for should be: button-press-event.
A single left mouse button click will trigger the button-press-event.
This signal works for me. My GNOME shell version is: 3.36.9
Regarding your second question:
is there a preferred way to show/hide a window of a running application?
This link may be able to help you or will hopefully at least give you some pointers in the right direction:
https://github.com/amivaleo/Show-Desktop-Button/blob/master/extension.js
Good Luck!

Google Chrome call a JS Script Console?

I'm trying basically, what is done here: Calling a Javascript Function from Console
Just in another way that I can't find out.
At reddit.com I'm trying to remove that Try the Redesign button. If you F12 using Google Chrome while in reddit.com you should be able to see Application, you click that and then go to scripts and search for OptIn using CTRL+F. Then you find the code, I'll just put some part of it in here.
function f() {
a("redesignbanner", "click", "r2banner_dismiss")
}
this
e.actions.on("onboarding:redesignbetabarClose", f),
e.actions.on("onboarding:redesignbetabarClickOptIn", c),
and this
initBanner: function() {
var n = $(".redesignbetabar");
if (!n.length)
return;
$("#redesign-beta-optin").on("click", function() {
e.actions.trigger("onboarding:redesignbetabarClickOptIn"),
t(function() {
e.onboardingBar.setDismissed(n.data(), !0),
window.location.reload(!0)
}, function(t, n, i) {
e.warn("Error opting in to redesign", n, ";", i)
})
})
}
Do you see that e.onboardingBar.setDismissed(n.data(), !0)? Basically, I tried to run this too, but I couldn't figure out how.
My point is to remove that button on the top right, which looks like this.
If you don't know how to get that button, I'll tried to figure out how and found out how to get it.
You go to the reddit account settings on the top right > scroll down and check, Use the redesign as my default experience > then you click on save
and then you go again to settings or if you are still there, just uncheck it and the button should appear, which is annoying and I can't get rid of it, seems that I didn't had this problem before also others have it but not all and thats weird.
Since Reddit wraps almost all of their JavaScript code in anonymous functions, you are unable to access the variables and functions defined within them. For example, see the following code:
(function() {
var x = 2;
})();
The variable x can not be accessed from anywhere except inside that anonymous function, and since that function has no name, there is no way to refer to it or access anything inside of it.
Reddit does the same thing with their code, meaning you can't call any of those methods. However, there is another way to hide the button using CSS. The button has the class "redesign-beta-optin", so the following CSS will hide the button:
.redesign-beta-optin { display: none }
This can be done with JavaScript like so:
document.getElementsByClassName("redesign-beta-optin")[0].style.display = "none"
EDIT
To get rid of the button permanently, you can use a Chrome extension such as Tampermonkey or Stylish that allows you to run JavaScript and CSS on certain web pages.
To do this with Tampermonkey, create a UserScript with the following contents:
// ==UserScript==
// #name Reddit Redesign Button Remover
// #description Remove reddit redesign button
// #author kmh
// #match https://*.reddit.com/*
// ==/UserScript==
document.getElementsByClassName("redesign-beta-optin")[0].style.display = "none";
With Stylish, you can create a new style for the domain reddit.com with the contents:
.redesign-beta-optin { display: none }
You will notice a small period of time as the site is loading with the button there if you use Tampermonkey, since it takes some time to initialize. This does not happen with Stylish.

How to add a "pin it" button dynamically?

I'm trying to optimize my Wordpress install - and one of the culprits I'm seeing, is the "Pin It" button widget for Pinterest. I'm now trying to find a way to dynamically load the JS code (when they initially hover over the button), and then apply it to the page. So far I've only managed to get this far:
jQuery(document).on("mouseenter click",'.pinItSidebar', function() {
jQuery.getScript("http://assets.pinterest.com/js/pinit_main.js", function() {
// do something here?
});
});
I can't seem to find a function that I can call (as a callback, after the JS is loaded). Obviously I will only do this once per page load (the above is just a very basic version at the moment)
Does anyone have any suggestions on how I can achieve this? The end game of how I want it to function, is with:
Working solution:
Here is a working solution I've now got, which will allow you to load the pinterest stuff ONLY when they click the button (and then trigger the opener as well). The idea behind this, is that it saves a ton of Pinterest JS/CSS / onload calls, which were slowing the page down.
jQuery(document).on("click",'.pinItSidebar', function() {
if (typeof PinUtils == "undefined") {
jQuery.getScript("http://assets.pinterest.com/js/pinit_main.js", function() {
PinUtils.build();
PinUtils.pinAny();
});
} else {
PinUtils.pinAny();
}
});
...and just call with:
foo
Hopefully this helps save someone else some time :)
Extra tweak: I'm just playing around, to see if I can make this even more awesome :) Basically, I want to be able to decide which images are pinnable. Below this will do that for you:
jQuery("img").each(function() {
if (jQuery(this).data('pin-do')) {
// its ok, lets pin
} else {
jQuery(this).attr('nopin',"1");
}
});
All you need to do to make an image pinnable, is have the data-pin-do="1" param set the images you want to allow them to share :)

Jquery-Hot key responds to every key

I have downloaded jquery.hotkeys-0.7.9.js plugin and was trying to provide hot key. on pressing ctr+t it should open new url address . i have made this something like this
jQuery(document).bind('keypress', 'Ctrl+t',function (evt){
alert('ctrl+t is pressed');
window.location.href = ("${createLink(controller:'trip',action:'create')}");
return false
});
But this is not working, it resonds to any key in my keyboard,(even if i press a,b,c etc). What changes i should make so that it should respond to only ctr+t ??
even if i delete the downloaded plugin from js folder the result is same\
jquery version i am using is jquery-1.1.3.1.pack.js
According to the example the project gave, you should do this:
$.hotkeys.add('Ctrl+t', function(){
alert("haha");
});
But in Chrome(and maybe some other browsers too), Ctrl+t is the default hot key to open a new tab, I don't know how to overwrite it. So when I test, I replace Ctrl+t to Ctrl+v, and it worked.
fiddle: http://jsfiddle.net/QFT8f/
UPDATE:
This is copied from the source file of hotkey.js:
USAGE:
$.hotkeys.add('Ctrl+c', function(){ alert('copy anyone?');});
$.hotkeys.add('Ctrl+c', {target:'div#editor', type:'keyup', propagate: true},function(){ alert('copy anyone?');});>
$.hotkeys.remove('Ctrl+c');
$.hotkeys.remove('Ctrl+c', {target:'div#editor', type:'keypress'});
Your code is correct based on the documentation, but the plugin does not work as expected (at least in Firefox). I would ditch the plugin and just handle it based on event attributes.
Here's a fiddle with the plugin installed where you can see the event firing when any key is pressed, and how you would limit to only run certain code when 'Ctrl+t' is pressed. Note: you have to click on the output panel to give it focus for the key events to fire.
JavaScript code:
$(document).bind('keypress', 'Ctrl+t',function (e){
if(e.which==116 && e.ctrlKey){
alert('Ctrl+t was pressed');
return false;
} else {
alert('Any other key. Bad code...BAD!');
}
return true;//Pass the event on
});
UPDATE
I had previously added the plugin when I was testing, but it appears like I lost it somewhere when I was fiddling, so the example above works in plain JQuery (I'd make the second parameter the function though). Here's the fiddle with the jquery.hotkeys-0.7.9.min.js resource added with the same code, and for me it throws an "elem.getAttribute is not a function" JavaScript error when run with JQuery 1.6. Another reason to ditch the plugin!

Categories

Resources