say I have many divs and each div trigger an event when clicked - dojo

Dojo 1.7
say I have many divs and each div trigger an event when clicked. So when I cilck a div, dojo adds a class, say "clicked" to the div. But how can I set it so when I click another div, it removes the previous div class "clicked" and gives it to the div that I just clicked?
This is because if I clicked on one div it supposed to change its background and remove the background from the previously clicked div
Thanks!!!

You can put all these div in one container, for example
<div class='RadioDivContainer'>
<div> </div>
....
<div> </div>
<div>
Then do this in onclick event handler of divs:
dojo.query(".RadioDivContainer .clicked").forEach(function(node){
dojo.removeClass(node, "clicked");
});
dojo.addClass(evt.target, "clicked");
This is just show the idea how to implement it. You can change it to suit your case.

You can remove the clicked class from all the elements in the group before applying the clicked class to the newly-clicked element.
Using Dojo 1.7:
require([
'dojo/query',
'dojo/dom-class',
'dojo/on',
'dojo/dom',
'dojo/domReady!'
], function(query, dom_class, on, dom) {
var boxes = query('.box', dom.byId('#container')); // get elements inside #container
boxes.forEach(function(box) {
on(box, 'click', function() {
boxes.forEach(function(b) {
dom_class.remove(b, 'clicked');
});
dom_class.add(box, 'clicked');
});
});
});
Here's a fiddle.
You could also keep track of the last clicked element and remove the clicked class from that. You can see both examples in the fiddle.

You should enable hooks to your desired DOM elements with dojo.query, handle click events using dojo.on and assign/unassign classes with dojo/dom-class. Give the div elements a shared class to denote that they are part of this clickable unit, then listen for click events on all of them and assign classes as necessary. See this JSfiddle, using Dojo 1.7.4:
HTML
<div class="mutable"></div>
<div class="mutable"></div>
<div class="mutable"></div>
Javascript/Dojo
require(["dojo/query", "dojo/dom-class", "dojo/on", "dojo/domReady!"], function(query, domClass, on) {
on(query(".mutable"), "click", function(e) {
query(".mutable").forEach(function(node) {
domClass.remove(node, "clicked");
});
domClass.add(this, "clicked")
});
});
CSS
.mutable {
background-color:red;
}
.clicked {
background-color:green;
}
div {
border:2px solid black;
margin:5px;
}
This will also work with Dojo 1.8.x and 1.9.x.

Related

How can I listen to the scroll event in a sidebar [Bootstrap Vue]

I am using the Sidebar component from BootstrapVue to render a navigation for my application.
As an example, I have 30 menu items in my navigation, so the content within the sidebar scrolls vertically. I would like to bind to that scroll event to dynamiclly add/remove some classes.
I have tried to create a custom scroll directive:
Vue.directive('scroll', {
inserted: function(el, binding) {
console.log('el', el);
let f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
});
...then register that to the component within my vue file:
<b-sidebar
v-scroll="handleScroll"
title="Menu"
shadow="lg"
backdrop
#change="$emit('sidebar-change')"
...
handleScroll() {
console.log('handleScroll');
},
The directive is being picked up properly, but my handleScroll method is firing when the main body is scrolling, not the sidebar.
In my directive, I am logging to see what element it thinks it's working with:
<div tabindex="-1" class="b-sidebar-outer">...</div>
Since Bootstrap is dynamiclly creating the markup for the overlay, that's the parent element -- looking closer, I believe I need to attach my directive to this:
<div class="b-sidebar-body">...</div>
That is the <div> that looks to be scrolling. However, since it is generated at runtime, I don't know how to hook into that.
I have also tried using #native.scroll="myMethod" on the component...no luck there either.
How can I listen for the scroll event within my sidebar component? Thank you for any suggestions!
Your scroll listener fires on the main window because the directive attached the event listener to window, and not the element.
To listen to scroll events on the contents of b-sidebar, the listener should be on an element inside the default slot of b-sidebar (not the b-sidebar itself).
Put a wrapper div inside b-sidebar's default slot, and style it to enable scrolling:
<template>
<b-sidebar>
<div class="wrapper">
<!-- your actual contents here -->
</div>
</b-sidebar>
</template>
<style>
.wrapper {
overflow: auto;
height: 100%;
}
</style>
Add the custom v-scroll directive on the wrapper div:
<div class="wrapper" v-scroll="handleScroll">
Update the custom directive to add the binding value as the event listener on the given element's scroll event:
Vue.directive('scroll', (el, binding) => {
let f = (evt) => {
if (binding.value(evt, el)) {
el.removeEventListener('scroll', f)
}
}
el.addEventListener('scroll', f)
})
demo
You need to check whether the event's target is the sidebar and only execute your function if it is.

Quill.js doesn't work properly in a Vuetify v-dialog

I'm trying to use a Quill.js editor inside a Vuetify v-dialog, but the toolbar dropdowns are not closed when the user clicks outside the current opened dropdown.
I made a js Fiddle:
https://jsfiddle.net/6d7bef5n/
<div id="app">
<v-app>
<quill-editor v-model="content"></quill-editor>
<v-dialog v-model="dialog">
<quill-editor v-model="contentKo"></quill-editor>
</v-dialog>
<v-btn #click.stop="dialog = !dialog">Open Quill in a Modal</v-btn>
</v-app>
</div>
Vue.use(VueQuillEditor)
Vue.use(VueQuillEditor)
new Vue({
el: "#app",
data() {
return {
content: "I'm OK",
contentKo: "I'm Wrong, Toolbar dropdowns are not closing on blur",
dialog: false
}
}
});
It seems that the v-dialog component does something wrong on the events inside his content slot, probably for the open/close behavior, but didn't found what.
Thanks
As #MarlburroW pointed out Vuetify's VDialog components stops the propagation of the click event when the user clicks inside of the dialog.
https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VDialog/VDialog.js#L284
In my case I had a custom directive which detects clicks outside of the target element, for example for a dropdown component. This worked, but if you used such a component inside of Vuetify's dialog the custom directive would not work, because the VDialog stopped propagation of the click event.
Vuetify has its own outside click directive which they use for menus, selects...etc. It does not suffer from this issue.
https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/directives/click-outside.ts
I had a look at the differences between Vuetify's directive and my own and the reason it works is that they use capturing instead of bubbling for the event listener.
The following codepen demonstrates it:
https://codepen.io/geersch/pen/LoLgYK
onClick = function (e) { console.log('The click event bubbled up.'); };
document.body.addEventListener('click', onClick, { capture: true });
// document.body.addEventListener('click', onClick, { capture: false });
dialog = document.querySelector('#dialog');
dialog.addEventListener('click', function (e) {
e.stopPropagation();
});
So I just changed my directive to use capturing too.
.quill-editor {
user-select: auto !important;
-moz-user-select: auto !important;
-webkit-user-select: auto !important;
-ms-user-select: auto !important;
}
Try it. It works for me.

Modifying Bootstrap 3's Collapse Animation with Animate.css

I managed to override the default "collapse in" animation for Bootstrap 3's collapse plugin but unable override the toggle back animation.
Basically I want it to fade in (which is doing now) and fade out on close which at the moment its defaulting to the default BS animation for that event.
Example jsfiddle
<div class="collapse animated fadeIn" id="collapseExample">
<div class="well">
...
</div>
</div>
After taking a look at the Bootstrap 3 documentation for "collapse" and This other question, I took over the events and managed to get it working.
I removed all animate.css classes from element.
jQuery to override the show and hide events generated by BS.
Create a class that would delay the transition on "hide".
Result jsfiddle
JS
$(function() {
var animateIn = 'animated fadeIn';
var animateOut = 'animated fadeOut collapsing-delay';
$('#collapseExample').on('show.bs.collapse', function () {
// do something…
$(this).addClass(animateIn).on('shown.bs.collapse',
function() {
$(this).removeClass(animateIn);
});
})
$('#collapseExample').on('hide.bs.collapse', function () {
// do something…
$(this).addClass(animateOut).on('hidden.bs.collapse',
function() {
$(this).removeClass(animateOut);
});
})
})
CSS
.collapsing-delay {
/* delay BS transition for animated fadeOut to show */
-webkit-transition-delay: 2s !important;
transition-delay: 2s !important;
}

Add/Remove individual widgets from gridster

I'm trying to add and or remove a a widget based on a button click function. It works but once the function is called once it does something odd where the code is called on any mouse click instead of just the button click on the html page. So if I click the remove button on the html page it will remove that widget but then if I click any other widget (not on a button) it still removes that widget. I only want the function called on the html button click, not any mouse click. It's like the button is initializing something on the page to make any mouse click call the remove function. Can anyone explain why this is happening and how I can fix it? My code below:
function deleteWidget() {
var gridster = $('.gridster ul').gridster().data('gridster');
$(document).on( "click", ".gridster ul li", function() {
$(this).addClass("activ");
gridster.remove_widget($('.activ'));
});
}
function addWidget() {
var gridster = $(".gridster ul").gridster().data('gridster');
$(document).on("click", ".gridster ul li", function() {
gridster.add_widget('<li class="gs_w">The HTML of the widget...</li>', 2, 1);
});
}
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1" class="gs_w"><button onclick="addWidget()" style="float: right;">+</button><h3>4</h3><span class="gs-resize-handle gs-resize-handle-both"></span></li>
<li data-row="1" data-col="6" data-sizex="1" data-sizey="1" class="gs_w"><button onclick="deleteWidget()"style="float: right;">-</button><h3>6</h3></li>
Thank you for any help!
When you click on your delete button, your code is creating a bind that makes any click on any widget, run the code to remove it.
$(document).on( "click", ".gridster ul li", function() {
$(this).addClass("activ");
gridster.remove_widget($('.activ'));
});
You can try change your html to:
<li data-row="1" data-col="4" data-sizex="1" data-sizey="1" class="gs_w"><button class="delete-button" style="float: right;">+</button><h3>4</h3><span class="gs-resize-handle gs-resize-handle-both"></span></li>
<li data-row="1" data-col="6" data-sizex="1" data-sizey="1" class="gs_w"><button class="add-button" style="float: right;">-</button><h3>6</h3></li>
and, in your javascript code, after initializing your gridster add:
$(document).on( "click", ".gridster .delete-button", function() {
var gridster = $(".gridster ul").gridster().data('gridster');
gridster.remove_widget($(this).parent());
});
$(document).on("click", ".gridster .add-button", function() {
var gridster = $(".gridster ul").gridster().data('gridster');
gridster.add_widget('<li class="gs_w">The HTML of the widget...</li>', 2, 1);
});
Hope it helps.
Below is the jQuery and HTML required for adding a widget to a gridster grid.
jQuery:
$(document).on( "click", "#addWidgetButton", function(e) {
e.preventDefault();
gridster.add_widget.apply(gridster, ['<li>new</li>', 1, 2]);
});
HTML:
<button id="addWidgetButton" style="float: right;">+</button>

How to make a dojo dijit tab blink or flash when an event occurs and it is not the active tab?

I have a dojo dijit tab container and I want the tabs to flash a few times when an event occurs and it is not the selected tab. For example, when I receive a chat message I want the "Chat tab" to flash a few times as a visual notification that a chat has been received. I'm having a hard time finding the right control (the tab) to modify. Here is the code:
The HTML:
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region:'center',splitter: true">
<div id="tabChat" title="Chat" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="iconClass:'i-chat', design: 'sidebar'">
<div id="pnlChatLog" style="background-color:#FFF; padding:0px;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center', splitter:true">
<div id="divChatLog" style="width:100%; height:100%; overflow-y:scroll; overflow-x:hidden;">
</div>
</div>
<div id="pnlChatMessage" style="background-color:#FFF; padding:0px; overflow:hidden;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom', splitter:false">
<input id="txtChatMessage" style="width:100%; margin:0px; border:0px;" data-dojo-type="dijit.form.ValidationTextBox" data-dojo-props="intermediateChanges:false,placeholder:'Enter Message'" />
</div>
</div>
<div id="tabQuestions" title="Questions" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="iconClass:'i-help', design: 'sidebar'">
<div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="region:'center', splitter:false, gutters:false">
<div style="background-color:#FFF; padding:0px; border-top:0px;" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center', splitter:true">
<div id="gridQuestions"></div>
</div>
</div>
</div>
The javaScript:
//Chat message Event
chat.on("message", function(e) {
//Message code is here...
//TODO: Make the tab flash if it is not the current tab
});
Note: The messaging code (not shown here) works. I just need to know what javaScript will replace the TODO section so the tab blinks/flashes for a few seconds at this point.
To get to the tab button you have to use the tab element's "controlButton" then modify the domNode. Here is an example:
//A method for the blinking using setInterval. The top line shows
//how to get the actual tab that you want to modify. Then add and remove the
//Hover classes for a nice flashing/blinking effect.
function blinkTab(tabId, count, interval) {
var tabbutton = dijit.byId(tabId).controlButton.domNode;
var interval = setInterval(function(){
if(count % 2 == 0) {
tabbutton .className += " dijitTabHover";
tabbutton .className += " dijitHover";
}
else {
//Not sure this is the best way to remove a class but I couldn't find
//a "clean" way to do it with dojo.
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitTabHover(?!\S)/ , '');
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitHover(?!\S)/ , '');
}
if(count == 0) {
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitTabHover(?!\S)/ , '');
tabbutton .className = tabbutton .className.replace( /(?:^|\s)dijitHover(?!\S)/ , '');
clearInterval(interval);
}
count--;
}, interval);
}
//Now make the calls where desired
//Chat message Event
chat.on("message", function(e) {
//Message code is here...
blinkTab("tabChat", 10, 500);
});
//Question Event
questions.on("message", function(e) {
//Question code is here...
blinkTab("tabQuestions", 10, 500);
});
You might just want to change the "class" of the tab title span (or is it a div? don't remember). The easy way is to use firebug, check the element used for the tab title, identify it in the node hierarchy, then put an id on your tab like tabMsg or something, then you justy ned to dijit.byId to get the right tab, and then go to the title node and addClass/removeClass every seconds or 0.5s to make it "blink".
You might want to add a "blinking" property to your tab, so that while this is true you switch classes, and when you click on the tab you set it to false and disable the blinking.