Toggle button with panel in Firefox extension with Mozilla SDK - javascript

I am developing a firefox extension with the Mozilla SDK. The situation is:
I want a toggle/action button to show/hide the extension's panel.
My code:
// the panel
let panel = require("sdk/panel").Panel({
// ...
onHide: handleHide
});
// the button
let button = ToggleButton({
// ...
// will be executed, when user clicks the button
onChange: handleChange
});
// event handlers
function handleChange(state) {
// state.checked is always true
if (???) {
panel.show();
}
}
function handleHide() {
// un-check the button
button.state('window', {checked: false});
}
The problem is, that inside of handleChange, where the toggling logic should be, i can't tell if the panel is supposed to show or hide. In the docs theres an example which uses state.checked, but since this code is run while i am clicking on the button, the state.checked is always true. In the end, the toggling does not work this way, because the panel never gets hidden when clicking the "toggle"-button.
help much appreaciated, i already tried so many things.. mothings works.
thanks in advance!

simply use console.log to see what's inside the state:
{
"disabled": false,
"checked": false,
"label": "the default label",
"icon": "./icon.png",
"id": "show-panel"
}
so we can go on like this:
if(state.checked)
{
myExt.show();
return false;
} else {
myExt.hide();
return false;
}
in older versions you need to return false.

Related

Shopify ThemeEditor doesnt execute Javascript after edit caused Section reload

I wrote a custom Shopify section. The section contains a slider, and each block added to the section results in a new slide added to the slider.
When editing slides (blocks), the slider should automatically slide to the selected block for proper preview experience. I wrote a js function for that, that works perfectly fine:
if (Shopify.designMode) {
document.addEventListener('shopify:block:select', function(event) {
const sectionSelectedIsHero = event.target.classList.contains('hero-slide');
if(!sectionSelectedIsHero) return;
var selectedSlideId = $(event.target).attr("data-slide-id");
heroCarousel.to(selectedSlideId);
});
}
However, when a user edits a slide (block), for example the background color in a color picker, Shopify automatically reloads the section in the ThemeEditor to update the preview for the user.
While the shopify:block:select event is being fired again (I can track "event" variable in console.log()), the slider doesnt work at all after that. The first slide is in preview and the controls also stop working. When selecting different slides (blocks), nothing happens.
Appreciate any help. Thanks!
EDIT: I now have a working solution. However, this is not optimal at all as im repeating code just to make it execute again. How can I avoid that? Does anyone have a suggestion?
$( document ).ready(function() {
var heroCarouselElement = document.querySelector('#heroCarousel');
var heroCarousel = new bootstrap.Carousel(heroCarouselElement, {
interval: false,
keyboard: false,
wrap: true,
touch: true
});
$("#heroControlPrev").click(function() { heroCarousel.prev(); });
$("#heroControlNext").click(function() { heroCarousel.next(); });
if (Shopify.designMode) {
document.addEventListener('shopify:block:select', function(event) {
const sectionSelectedIsHero = event.target.classList.contains('hero-slide');
if(!sectionSelectedIsHero) return;
var selectedSlideId = $(event.target).attr("data-slide-id");
var heroCarouselElement = document.querySelector('#heroCarousel');
var heroCarousel = new bootstrap.Carousel(heroCarouselElement, {
interval: false,
keyboard: false,
wrap: true,
touch: true
});
$("#heroControlPrev").click(function() { heroCarousel.prev(); });
$("#heroControlNext").click(function() { heroCarousel.next(); });
heroCarousel.to(selectedSlideId);
});
}
});
On my mind, the issue is about the event.
You might try this:
if (Shopify.designMode) {
document.addEventListener('shopify:section:load', function(event) {
/* Do something */
});
}
As explained in doc the load event is fired when "A section has been added or re-rendered." Which is the case each time user add a slide (re-rendering).
Please not that you might have to reset/clear the function initializing the slider before, using the unload event (depending the way the slider works).

jQuery always prevents the action of the first click

I have several "Purchase Now" buttons of different articles. When the button has the class "sold-out" it shouldn't do anything otherwise it should open a jQuery Magnific Popup. So far that works. My problem is, that when I click for the first time I visit the homepage the purchaseable "Purchase Now" button, it isn't doing anything. When I click for the second time on it, it opens the jQuery window. But why it doesn't work for the first time already ??
My HTML:
Purchase Now
My JQuery:
$('.open-popup-link').magnificPopup({
type:'inline',
midClick: true,
mainClass: 'mfp-fade'
});
$('.ajax-popup').click(function(e){
e.preventDefault();
if($(this).hasClass("sold-out")) {
return false;
}
var region = $(this).data('region');
var quantity = $(this).data('quantity');
if(typeof quantity == 'undefined') quantity = $(this).parent().find('select').val();
var packageid = $(this).data('packageid');
$(this).magnificPopup({
type: 'ajax',
ajax: {
settings: {
data : {
region : region,
quantity : quantity,
packageid : packageid,
}
}
},
closeOnContentClick: false,
closeOnBgClick: false
});
});
It might be because you are declaring the popup definition within the click function. Can you try declaring the function outside the click function?
It doesn't open on first click cause this is the time you BIND it to the element.
Hovewer, we see in documentation that we can instantly open MagnificPopup.
// Open popup immediately. If popup is already opened - it'll just overwite the content (but old options will be kept).
// - first parameter: options object
// - second parameter (optional): index of item to open
$.magnificPopup.open({
items: {
src: 'someimage.jpg'
},
type: 'image'
// You may add options here, they're exactly the same as for $.fn.magnificPopup call
// Note that some settings that rely on click event (like disableOn or midClick) will not work here
}, 0);
http://dimsemenov.com/plugins/magnific-popup/documentation.html#options

ACE change key binding conditionally

If the user presses the down key while a custom popup is displayed, I would like this down event to be cancelled from the editor and handled manually.
However, if the popup is disactivated, the 'down' key should perform as usual.
For that, I wrote this:
editor.commands.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return false;
} else {
// just leave the key.
return true;
}
readOnly: true
});
Unfortunately, I can return false or true, the result is the same, it always capture the down event, which is annoying. How can I prevent that?
I already tried the following:
Add a key binding to the DOM. But after that, the interaction always happen (i.e. I cannot capture it).
Return false or true as suggested for common events but this does not work here.
EDIT
The solution from #a user works very well.
Instead of the above command, I wrote:
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return true; // CHANGE HERE ! true is when it capture it.
} else {
// just leave the key.
return false; // CHANGE HERE ! false is when I don't capture it.
}
readOnly: true
});
editor.keyBinding.addKeyboardHandler(keyboardHandler);
In the current version ace only keeps one command for each key so your addCommand call removes default binding for down.
You can add new keyboard handler similar to what autocompletion does https://github.com/ajaxorg/ace/blob/v1.1.3/lib/ace/autocomplete.js#L221
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand(/*add your command with return false*/)
editor.keyBinding.addKeyboardHandler(keyboardHandler);

JavaScript multipage form onbeforeunload issue

I am putting together a quiz system using the multipage form jQuery script and I would like to be able to warn the user if tries to close the page. I managed to do this just fine using the code below:
$(document).ready(function($) {
window.onbeforeunload = function(){
return 'Sure you want to close the page?';
};
});
My problem is that when I try to submit the form and post the results I get the warning asking me if I want to navigate away from this page. This is the code:
$('#quizForm').formwizard({
validationEnabled: true,
focusFirstInput : true,
formOptions: {
beforeSubmit: window.onbeforeunload = null,
resetForm: true
}
});
What am I doing wrong?
LE: I created this fiddle maybe someone can help me out, I am running out of ideas.
http://jsfiddle.net/awLYY/5/
first, you don't need to wait for the DOM to be ready in order to attach an onbeforeunload handler.
second, since the onbeforeunload is a function, you can choose wither to return a string or return nothing in case you're submitting some data to the server
var isFormBeingSubmitted = false;
window.onbeforeunload = function() {
if( isFormBeingSubmitted ) {
return;
}
return 'Sure you want to close the page?';
};
// now before you submit your form, just enable the isFormBeingSubmitted
$('#quizForm').formwizard({
validationEnabled: true,
focusFirstInput : true,
formOptions: {
beforeSubmit: function() {
isFormBeingSubmitted = true;
return true;
},
resetForm: true
}
});
To answer my own question, all I had to do was to add to the formwizard options:
formPluginEnabled: true
Now everything is working fine. Thanks

Backbone.js model.get not retrieving value

This is a really strange problem I'm having with an app in Backbone.js. I have different search results which are displayed in an accordion, only one result can be selected at a time.
The model for each result has an attribute, "selected" which represents whether the result is selected or not.
For some reason I'm not able to deselect the match. This is the code that's run on clicks on the result.
I've been looking through it, selected always returns false, and somehow, never gets set to true in this function.
click_header: function (e) {
e.stopPropagation();
var s = this.model.get("selected");
if (s == true) {
this.model.set({ selected: false, expanded:false});
} else {
this.model.set("selected", true, { silent: true });
this.model.set("expanded", true, { silent: true });
}
}
EDIT:
I fixed the problem. A function elsewhere in the program triggered by changes to select was setting select to false on all models.
I fixed the problem. A function elsewhere in the program triggered by changes to select was setting select to false on all models.
Updated Here is a more streamlined approach:
click_header: function (e) {
e.stopPropagation();
var s = this.model.get("selected");
this.model.set({ selected: !s, expanded: !s}, { silent: !s });
}

Categories

Resources