I have an iron-list in which I have a settings icon which, when clicked causes a panel to slide out with settings options in. However when I have one open, I am wanting it to close upon opening the panel for another row. Currently I have it where they can all be open at the same time which is not optimal.
Please see the gif for the problem I am facing.
GIF OF THE PROBLEM
HTML/Polymer
<div class="container horizontal layout">
<div class="settingsIconContainer">
<paper-icon-button class="settingIcon" icon="settings" on-click="toggleSettings"></paper-icon-button>
</div>
<div id="edit" class="settings">
<paper-icon-button icon="delete"></paper-icon-button>
<paper-icon-button icon="create"></paper-icon-button>
<paper-icon-button icon="clear" on-click="toggleSettings"></paper-icon-button>
</div>
</div>
Polymer JS
toggleSettings : function(e) {
this.$.edit.classList.toggle('settingsMove');
},
You should not access the parent element from the child element. There are two ways of doing this.
1) In the toggle class, fire an event as below
toggleSettings : function(e) {
this.fire('settings-icon-toggle');
}
In the parent element add a listener and listen to the fired event.
listeners:{
'settings-icon-toggle': '_onSettingsIconToggle'
},
_onSettingsIconToggle: function(e){
//Using e.target.id, loop through all the settings and close them except the current one.
}
2) Add a boolean property in the object that you're passing to the iron-list, pass it to the settins component and set the property to true in the tolggleSetings method.
toggleSettings : function(e) {
this._isOpen = false;
}
In the Parent component, add an observer to this property and set all the rest of them to false.
observers:['_listChanged(arrayToIronList.*)'],
_listChanged:function(){
var isOpenSubPath = e.path.indexOf('._isOpen')
if( isOpenSubPath >=0){
var index = parseInt(e.path.match(/\d+/g)[0]);
//loop through the array and set all the _isOpen properties to false except the current one.
//You can find the current one using the index.
}
}
Did i misunderstood your question or is this question that simple?
You are trying to have only 1 opened settings at a time, right? so when user presses one settings, all others needs to be closed.
Just find all elements with settingsMove class and then remove that class.
toggleSettings : function(e) {
var elems = Polymer.dom(this.root).querySelectorAll(".settingsMove");
for(var i = 0; i < elems.length; i++){
this.toggleClass("settingsMove", false, elems[i]);
}
this.toggleClass("settingsMove", true, e.target.parentNode.parentNode.querySelector(".settings"))
}
i don't know what element you need to set class settingsMove on. So edit e.target.parentNode.parentNode.querySelector(".settings")) to suit your code
I used Polymer native function toggleClass. More info you can find here https://www.polymer-project.org/1.0/docs/api/Polymer.Base#method-toggleClass
Related
I am building a custom WordPress plugin that requires me to build into it a custom media library button that lets a user associate an image with a certain option for a post. The user needs to be able to add the elements dynamically, so there are multiple options, i.e. multiple medial library buttons.
The issue that I am running into is that if I have 5 options with five buttons, setting the first image works fine. But if I click buttons 2-5 to set the images for the additional options, they are not getting set but the first option is changing.
It's almost like once the initial element is set on click, then it never changes.
Here is a sample of the HTML (the generic.jpg is the default image before the image is set from the library):
<div class="image-preview-wrapper">
<img class="image-preview" src="https://WEBSITE/wp-content/plugins/atas_spec_writer/admin/assets/generic.jpg" style="max-height: 100px; width: 100px;" width="100" height="100">
<input type="button" class="button upload_image_button" value="Add Image">
<input type="hidden" name="options[section_4][3][img_id]" class="image_attachment_id" value="">
</div>
Here is the JS code:
// Uploading files
var j = jQuery;
var file_frame;
j(document).on('click', '.upload_image_button', function(event) {
var el = j(this);
event.preventDefault();
// If the media frame already exists, reopen it.
if (file_frame) {
// Open frame
file_frame.open();
return;
}
// Create the media frame.
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Select a image to upload',
button: {
text: 'Use this image',
},
multiple: false // Set to true to allow multiple files to be selected
});
// When an image is selected, run a callback.
file_frame.on('select', function() {
// We set multiple to false so only get one image from the uploader
attachment = file_frame.state().get('selection').first().toJSON();
el.siblings('.image-preview').attr('src', attachment.url);
el.siblings('.image_attachment_id').val(attachment.id);
});
// Finally, open the modal
file_frame.open();
// Restore the main ID when the add media button is pressed
j('a.add_media').on('click', function() {
wp.media.model.settings.post.id = wp_media_post_id;
});
I've switched up using j(this), event.target, and they both seem to stick with the first element clicked.
I originally thought that it might just go to the first element in the DOM that matches what is clicked, but if I add 2 options with images and then come back two days later and add two more, the click event sticks with the first element that was set that day, not the first element in the DOM.
So I am completely at a loss......
Any help is much appreciated!!
Looks like once you open a frame file_frame variable will never be nullified or resetted.
I guess problem lies in the following return statement:
if (file_frame) {
// Open frame
file_frame.open();
return;
}
Vanilla Picker is an absolutely fantastic color picker (example one, example two). However the documentation is a bit lacking. I know how to initialize though I don't know how to identify whatever global object (besides Picker) so I do not know how to access the show(), hide() and/or movePopup(options, open) methods.
The code I've come up with below at least prevents additional popups beyond one-per-element. However it would make more sense (and waste less memory) to simply use the movePopup() method though again I do not know what parent object to refer to. If I console.log(Picker); and looking through the events in the inspector tools of Waterfox and Chrome has me a bit lost. I also have to click twice initially for the popup to be displayed.
How do I identify the global / primary object which I can then use movePopup to only initialize a single Picker with Vanilla Picker?
No frameworks or libraries, except of course of Vanilla Picker itself.
JavaScript
// See URL for Vanilla Picker code:
// https://unpkg.com/vanilla-picker#2.8.0/dist/vanilla-picker.min.js
window.onclick = function(event)
{
if (event.target.hasAttribute('data-color') && event.target.getAttribute('data-color')[0] == '#')
{
console.log(event.target.getAttribute('data-color'));
var picker = new Picker({alpha : true,
color: event.target.getAttribute('data-color'),
editor : true,
editorFormat : 'rgb',
onChange: function(color)
{
event.target.setAttribute('data-color',color.rgbaString);
event.target.style.backgroundColor = color.rgbaString; console.log(color);
},
//onDone: function(color) {console.log(color);},
parent : event.target,
//popup : 'bottom'
});
}
}
HTML
<div data-color="#f00" id="color1">Color 1</div>
<div data-color="#0f0" id="color2">Color 2</div>
<div data-color="#00f" id="color3">Color 3</div>
As you instantiate an instance of Picker you assign it to a variable you can reference it through. If this variable is defined in the global scope, you can access this instance and thus all of its methods from anywhere in your code.
Here's a simple example, where we re-use the same Picker for two different DIVs:
var picker = new Picker();
function changePicker(e) {
picker.movePopup({
parent: e.currentTarget
}, true);
}
document.getElementById("divA").addEventListener("click", changePicker);
document.getElementById("divB").addEventListener("click", changePicker);
picker.onDone = function(color) {
this.settings.parent.style.backgroundColor = color.rgbaString;
};
<script src="https://unpkg.com/vanilla-picker#2.8.0/dist/vanilla-picker.min.js"></script>
<div id="divA">TestA</div>
<div id="divB">TestB</div>
This will set backgroundColor of a DIV as soon as the done button of the picker is pressed. If you take a look at the onDone callback function, you'll notice this.settings. This is an object returned by the picker itself. Among other things it returns the HTML element which is currently associated with the picker - this.settings.parent.
I'm trying to create an accordion able to expand multiple panels at once. I have tried to find it in the jQuery UI API, but I haven't yet found the proper way.
Please let me know if there is a way of doing this using jQuery UI accordion.
As others have noted, the Accordion widget does not have an API option to do this directly. However, if you must use the widget, it is possible to achieve this by using the beforeActivate event handler option to subvert and emulate the default behavior of the widget.
For example:
$('#accordion').accordion({
collapsible:true,
beforeActivate: function(event, ui) {
// The accordion believes a panel is being opened
if (ui.newHeader[0]) {
var currHeader = ui.newHeader;
var currContent = currHeader.next('.ui-accordion-content');
// The accordion believes a panel is being closed
} else {
var currHeader = ui.oldHeader;
var currContent = currHeader.next('.ui-accordion-content');
}
// Since we've changed the default behavior, this detects the actual status
var isPanelSelected = currHeader.attr('aria-selected') == 'true';
// Toggle the panel's header
currHeader.toggleClass('ui-corner-all',isPanelSelected).toggleClass('accordion-header-active ui-state-active ui-corner-top',!isPanelSelected).attr('aria-selected',((!isPanelSelected).toString()));
// Toggle the panel's icon
currHeader.children('.ui-icon').toggleClass('ui-icon-triangle-1-e',isPanelSelected).toggleClass('ui-icon-triangle-1-s',!isPanelSelected);
// Toggle the panel's content
currContent.toggleClass('accordion-content-active',!isPanelSelected)
if (isPanelSelected) { currContent.slideUp(); } else { currContent.slideDown(); }
return false; // Cancel the default action
}
});
See a jsFiddle demo
You could write multiple accordions that are stacked and each accordion have only one panel. This way the panels could be individually toggled.
An accordion is, by definition, a set of expanding elements that toggle in a certain way. You don't want that. You just want a set of expanding elements. It's extremely easy to build that with jQuery. It often needs nothing more than this:
$('.my-heading-class').on('click', function() {
$(this).next('.my-content-class').slideToggle();
});
<div class="my-heading-class">My Heading</div>
<div class="my-content-class">My Content</div>
I have an element $('#anElement') with a potential popover attached, like
<div id="anElement" data-original-title="my title" data-trigger="manual" data-content="my content" rel="popover"></div>
I just would like to know how to check whether the popover is visible or not: how this can be accomplished with jQuery?
If this functionality is not built into the framework you are using (it's no longer twitter bootstrap, just bootstrap), then you'll have to inspect the HTML that is generated/modified to create this feature of bootstrap.
Take a look at the popupver documentation. There is a button there that you can use to see it in action. This is a great place to inspect the HTML elements that are at work behind the scene.
Crack open your chrome developers tools or firebug (of firefox) and take a look at what it happening. It looks like there is simply a <div> being inserted after the button -
<div class="popover fade right in" style="... />
All you would have to do is check for the existence of that element. Depending on how your markup is written, you could use something like this -
if ($("#popoverTrigger").next('div.popover:visible').length){
// popover is visible
}
#popoverTrigger is the element that triggered that popover to appear in the first place and as we noticed above, bootstrap simply appends the popover div after the element.
There is no method implemented explicitly in the boostrap popover plugin so you need to find a way around that. Here's a hack that will return true or false wheter the plugin is visible or not.
var isVisible = $('#anElement').data('bs.popover').tip().hasClass('in');
console.log(isVisible); // true or false
It accesses the data stored by the popover plugin which is in fact a Popover object, calls the object's tip() method which is responsible for fetching the tip element, and then checks if the element returned has the class in, which is indicative that the popover attached to that element is visible.
You should also check if there is a popover attached to make sure you can call the tip() method:
if ($('#anElement').data('bs.popover') instanceof Popover) {
// do your popover visibility check here
}
In the current version of Bootstrap, you can check whether your element has aria-describedby set. The value of the attribute is the id of the actual popover.
So for instance, if you want to change the content of the visible popover, you can do:
var popoverId = $('#myElement').attr('aria-describedby');
$('#myElement').next(popoverid, '.popover-content').html('my new content');
This checks if the given div is visible.
if ($('#div:visible').length > 0)
or
if ($('#div').is(':visible'))
Perhaps the most reliable option would be listening to shown/hidden events, as demonstrated below. This would eliminate the necessity of digging deep into the DOM that could be error prone.
var isMyPopoverVisible = false;//assuming popovers are hidden by default
$("#myPopoverElement").on('shown.bs.popover',function(){
isMyPopoverVisible = true;
});
$("#myPopoverElement").on('hidden.bs.popover',function(){
isMyPopoverVisible = false;
});
These events seem to be triggered even if you hide/show/toggle the popover programmatically, without user interaction.
P. S. tested with BS3.
Here is simple jQuery plugin to manage this. I've added few commented options to present different approaches of accessing objects and left uncommented that of my favor.
For current Bootstrap 4.0.0 you can take bundle with Popover.js: https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.bundle.min.js
// jQuery plugins
(function($)
{
// Fired immiedately
$.fn.isPopover = function (options)
{
// Is popover?
// jQuery
//var result = $(this).hasAttr("data-toggle");
// Popover API
var result = !!$(this).data('bs.popover');
if (!options) return result;
var $tip = this.popoverTip();
if (result) switch (options)
{
case 'shown' :
result = $tip.is(':visible');
break;
default:
result = false;
}
return result;
};
$.fn.popoverTip = function ()
{
// jQuery
var tipId = '#' + this.attr('aria-describedby');
return $(tipId);
// Popover API by id
//var tipId = this.data('bs.popover').tip.id;
//return $(tipId);
// Popover API by object
//var tip = this.data('bs.popover').tip; // DOM element
//return $(tip);
};
// Load indicator
$.fn.loadIndicator = function (action)
{
var indicatorClass = 'loading';
// Take parent if no container has been defined
var $container = this.closest('.loading-container') || this.parent();
switch (action)
{
case 'show' :
$container.append($('<div>').addClass(indicatorClass));
break;
case 'hide' :
$container.find('.' + indicatorClass).remove();
break;
}
};
})(jQuery);
// Usage
// Assuming 'this' points to popover object (e.g. an anchor or a button)
// Check if popover tip is visible
var isVisible = $(this).isPopover('shown');
// Hide all popovers except this
if (!isVisible) $('[data-toggle="popover"]').not(this).popover('hide');
// Show load indicator inside tip on 'shown' event while loading an iframe content
$(this).on('shown.bs.popover', function ()
{
$(this).popoverTip().find('iframe').loadIndicator('show');
});
Here a way to check the state with Vanilla JS.
document.getElementById("popover-dashboard").nextElementSibling.classList.contains('popover');
This works with BS4:
$(document).on('show.bs.tooltip','#anElement', function() {
$('#anElement').data('isvisible', true);
});
$(document).on('hidden.bs.tooltip','#anElement', function() {
$('#anElement').data('isvisible', false);
});
if ($('#anElement').data('isvisible'))
{
// popover is visible
$('#tipUTAbiertas').tooltip('hide');
$('#tipUTAbiertas').tooltip('show');
}
Bootstrap 5:
const toggler = document.getElementById(togglerId);
const popover = bootstrap.Popover.getInstance(toggler);
const isShowing = popover && popover.tip && popover.tip.classList.contains('show');
Using a popover with boostrap 4, tip() doesn't seem to be a function anymore. This is one way to check if a popover is enabled, basically if it has been clicked and is active:
if ($('#element').data('bs.popover')._activeTrigger.click == true){
...do something
}
I have a html with one div and two scripts with Ext Js 3.4.0
<script type="text/javascript" src="js/listaBancos.js"></script>
The file listaBancos.js show a Grid with toolbar button in the divListaBancos, the first time i click the button "Agregar" and i see the Window declared in altaBanco.js.
==============Part of the grid in listaBancos.js============
tbar:[{
text:'Agregar',
tooltip:'Agrega un banco',
iconCls:'add',
handler: agregaBanco
}]
function agregaBanco(){
var win =Ext.getCmp('myWin');
win.show();
}
==============Window declared in altaBanco.js================
var winAltaBanco = new Ext.Window({
id : 'myWin',
height : 250,
width : 400,
});
When i close the window then click the button again the windows doesn't showed.
Can you help me ???
The default close action of a windows is close, i.e., it destroys the component, hence it cannot be accessed using Ext.geCmp() again since it doesn't exist on the DOM anymore. To achieve what you want either set closeAction : hide or
var cmp = Ext.getCmp('myId');
if(!cmp)
{
cmp = new Ext.Window({
id : 'myId'
});
}
cmp.show();
Prefer hiding to recreating.
Make sure in window config close action is set to hide.
closeAction:'hide'
check this
There is no need to make any trick, simply remove your window id. In ExtJS component ids must be unique.