Skip to content

Instantly share code, notes, and snippets.

@ZER0
Last active December 17, 2015 04:09
Show Gist options
  • Save ZER0/5548355 to your computer and use it in GitHub Desktop.
Save ZER0/5548355 to your computer and use it in GitHub Desktop.
let { Button } = require("sdk/ui");
let button = Button({
id: "my-button",
// assuming automatically `data` folder for "./"
image: "./beer.png",
// required as tooltip and overflow
label: "My Button",
type: "checked"
});
button.on("change", function (state) {
// state is an immutable object that represent a snapshot
// of the button's properties at the time the event was
// fired.
// It's the state of the button clicked by the user, in case
// of base button we have 1 state per window.
// returns the new state to merge with the current one
return { image: state.checked ? "./coffee.png" : "./beer.png "};
});
// Let's say instead they want have a shared button:
let { Button } = require("sdk/ui");
let sharedButton = Button({
id: "my-shared-button",
image: "./beer.png",
label: "My Shared Button",
type: "checked"
});
sharedButton.on("change", function (state) {
// this will be propagated to all `sharedButton` states
this.checked = state.checked;
this.image = state.checked ? "./coffee.png" : "./beer.png ";
});
// We could also provide low level utility function to get and set button state
// outside our events, for instance:
const tabs = require("sdk/tabs");
// The reason because I thought to functions instead of method, is mainly because
// in most of use case add-on devs shouldn't have the needs to get this state, if we
// provide the right set of events; so having them as low level API function makes
// a clear separation between them and our high level API.
const { getStateFor, setStateFor } = require("sdk/ui/utils");
// Note: this is something Location / Page Button would partially done internally
// Here we handle the thing manually to show the concept
tabs.on("activate", function (tab) {
// get the state of mybutton in the "thing" given (can be both `tab` or `window`)
let state = getStateFor(mybutton, tab);
let isImageType = tab.contentType.indexOf("image/") === 0;
let image = isImageType && state.checked ? "./on.png" : "./off.png";
// However, I don't really like this kind of function's signature,
// I think could be improved
setStateFor(mybutton, tab, {image: image});
});
// We can definitely improve that; but that's the basic idea
// We don't have to think in term of "views" anymore, but in term of "state":
// There are some conditions where we have 1 view and 1 state, but others
// where we have 1 view and multiple states (e.g. Location Button)
/**
* Alternative approach #1
*/
const { statesFor } = require("sdk/ui/utils");
tabs.on("activate", function (tab) {
let states = statesFor(mybutton); // returns a 'list' of all states of this button
// get the state of mybutton in the "thing" given (can be both `tab` or `window`)
let state = states.get(tab); // maybe `get` is not the proper name
let isImageType = tab.contentType.indexOf("image/") === 0;
let image = isImageType && state.checked ? "./on.png" : "./off.png";
// maybe `set` is not the proper name
states.set(tab, {image: image});
});
// The issue I see in these approaches is that `set` seems to intend to replace
// entirely the previous status object, where is actually is `applied` on top of
// it. That is done to avoid that the dev has to merge manually every time
// the state object. Maybe another name could be better.
/**
* Alternative approach #2
*/
tabs.on("activate", function (tab) {
// get the state of mybutton in the "thing" given (can be both `tab` or `window`)
let state = mybutton.stateFor(tab);
let isImageType = tab.contentType.indexOf("image/") === 0;
let image = isImageType && state.checked ? "./on.png" : "./off.png";
mybutton.stateFor(tab, {image: image});
});
/**
* Alternative approach #3
*/
tabs.on("activate", function (tab) {
// get the 'button' of mybutton for given 'thing' (can be both `tab` or `window`)
let button = mybutton.getButtonFor(tab);
let isImageType = tab.contentType.indexOf("image/") === 0;
let image = isImageType && button.checked ? "./on.png" : "./off.png";
button.image = image;
});
/**
* Alternative approach #4
* Basically instead properties it has method accessors.
*/
tabs.on("activate", function (tab) {
let isImageType = tab.contentType.indexOf("image/") === 0;
let image = isImageType && button.getChecked(tab) ? "./on.png" : "./off.png";
button.setImage(image, tab);
});
@erikvold
Copy link

+1 for alt #2 not sure why "states" is plural though, how about X.getState(aThing?) ?

@ZER0
Copy link
Author

ZER0 commented May 24, 2013

My bad, thanks to spot it out! So, good to hear we're all mostly on the same page; I was started already to implement a kind of approach #1 as low level API, in order to build the approach #2 on top of it.

Thanks to all you guys, I will update the Buttons JEP during the day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment