I have a "collapsible" definition list.
For each item of the list, I have added a Click-To-Copy button to the definition term for it to copy the paragraph text of each term .
The problem is that everytime I click on the Click-To-Copy button, it automatically expands (or collapses) the paragraph, and I do not want it to do that.
I want the paragraph to be expanded (or collapsed) only when I click on the text of the definition term, but not when I click on the button within the definition term element.
/* Collapsible Definition List usando jQuery */
(function( $ ){
$.fn.collapsible_definition_list = function() {
return this.each(function(){
$(this).find('dd').hide().end().find('dt').addClass("more").bind({
click: function(){
$(this).toggleClass("more less");
$(this).nextAll().each(function(){
if($(this).is('dt')){
return false;
}
$(this).slideToggle();
});
}
});
});
};
})( jQuery );
$(document).ready(function(){
$('.collapsible').collapsible_definition_list();
});
/* Here is the code for the click to copy: */
function copyToClipboard(element) {
var $temp = $("<textarea>");
var brRegex = /<br\s*[\/]?>/gi;
$("body").append($temp);
$temp.val($(element).html().replace(brRegex, "\r\n")).select();
document.execCommand("copy");
$temp.remove();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<dl class="collapsible">
<dt><button onclick="copyToClipboard('#p1')">Click to Copy</button> Item 1</dt>
<dd id="p1">Test text 1.<br>This is paragraph #1</dd>
<dt><button onclick="copyToClipboard('#p2')">Click to Copy</button> Item 2</dt>
<dd id="p2">Test text 2.<br>This is paragraph #2</dd>
<dt><button onclick="copyToClipboard('#p3')">Click to Copy</button> Item 3</dt>
<dd id="p3">Test text 3.<br>This is paragraph #3</dd>
</dl>
What can I do so that clicking on the click-to-copy button does not activate the collapse/expand feature of the definition term element?
(just in case, be nice with me if I am doing something incorrectly... I've done this empirically)
Related
I would like to display the contents of the first menu item, without clicking on it, making it the default contents displayed when the app is opened. I have tried everything I can think of. Console.log shows the value of the "selectedView" observable to be something like "View {title: "Event List", templateName: "EventList"}" so I've tried setting it to this value but it still does work.
<div class="inServMenu" data-bind="foreach: views">
</div>
<div data-bind="with: selectedView">
<div data-bind="template: { name: templateName }"></div>
</div>
<script id="EventList" type="text/html">
<span>"Here's the Event List..."</span>
</script>
<script id="RosterList" type="text/html">
<span>"Here's the Roster List..."</span>
</script> var View = function (title, templateName) {
this.title = title;
this.templateName = templateName;
};
// VIEWMODEL
var viewModel = {
selectedView: ko.observable(),
views: ko.observableArray([
new View('Event List', 'EventList'),
new View('Roster List', 'RosterList')
]),
}
ko.applyBindings(viewModel);```
[Here's a jsfiddle][1]
[1]: http://jsfiddle.net/jjfrick/hmfubkcr/18/
You'd need to slightly change your viewmodel constructor so that you can have a reference to it:
function ViewModel () {
var vm = this;
vm.views = ko.observableArray([
new View('Event List', 'EventList'),
new View('Roster List', 'RosterList')
]);
vm.selectedView = ko.observable(vm.views()[0])
}
ko.applyBindings(new ViewModel());
I want scroll down to the last div
<div v-for="(message, message_index) in messageArray" :key="message_index">
<div class="chatList">
</div>
</div>
I'm assuming you have a chat component where you want to scroll down to the last message on page load.
Although there are many ways to achieve this, I found this is the simplest one.
scrollIntoView() inside this.$nextTick(function () {}) gets the job done.
Bind your every div inside the loop with unique id. :id="`m-(some_unique_id)`">
<div v-for="(message, message_index) in messageArray" :key="message_index">
<div :id="`m-${message.id}`">
</div>
</div>
and get the element of the last index of messageArray. And tell the scrollIntoView to scroll down to that div.
script
<script>
mounted: {
this.getChatBoxUsersChats();
},
methods: {
getChatBoxUsersChats() {
this.$nextTick(function () {
let length = this.messageArray.length;
if (length > 0) {
let id = this.messageArray0[length - 1].id;
let element = document.getElementById("m-" + id);
element.scrollIntoView({ behavior: "smooth", block: "end" });
});
},
},
}
</script>
I'm using Ember v1.2.0 along with Handlebars v1.0.0 and jQuery v2.0.2 and I started to use Ember.Component and replace some views I created through components (for example a custom dropdown element) and it felt like the right thing to do, but unfortunately it does not work as I expected.
this is my Handlebars file, placed under `templates/components/my-dropdown:
<div class="dropdown__header" {{action 'toggle'}}>
<i {{bind-attr class=view.iconClass}}></i>{{view.displayText}}
</div>
<div class="dropdown__caret"></div>
<ul class="dropdown__body">
{{yield}}
</ul>
this is the corresponding Ember.Component class:
App.MyDropdownComponent = Ember.Component.extend({
classNames: 'dropdown'.w(),
toggleList: function () {
//var $this = this.$(); // returns null (!!!)
var $this = this.$('.' + this.get('classNames').join(' .')); // returns the expected object
if($this.hasClass('open')) {
$this.removeClass('open');
} else {
$this.addClass('open');
}
// Note: I can't work with classNameBindings and toggleProperty() because the classes
// could also be accessed through other code...
},
click: function (event) {
alert('heureka!'); // never fired!
},
actions: {
toggle: function () {
this.toggleList(); // fired as expected
}
}
});
is this expected behaviour of an Ember.Component?
I'm somewhat new to Angular. I am trying to display a Bootstap 3 modal dialog when an invalid user role is detected. I cannot get my modal template to display. The behavior seems to work i.e. I can dismiss the faded overlay..I just don't see the actual modal template.
Bootstrap 3
AngularJS 1.0.7
AngularJS UI Bootstrap 0.6.0
Controller
gsApp.controller('MainController', ['$rootScope', '$scope', '$q', '$window', '$location', '$modal', 'ApplicationCache', 'UserService',
function MainController($rootScope, $scope, $q, $window, $location, $modal, ApplicationCache, UserService) {
$scope.userRole = "BadRole";
$scope.showBadRoleModel = function () {
var showBadRoleModelInstance = $modal.open({
templateUrl: "badRoleModal.html",
backdrop: true,
windowClass: 'modal',
controller: badRoleModalInstance,
resolve: {
items: function () {
return $scope.userRole;
}
}
});
}
var badRoleModalInstance = function($scope, $modalInstance, items){
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
}]);
HTML
<div class="row" ng-controller="MainController">
<script type="text/ng-template" id="badRoleModal.html">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<h2>body</h2>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn" ng-click="showBadRoleModel()">Show bad role modal</button>
</div>
AngularJs UI Bootstrap doesn't work with Bootstrap 3 yet.
See more details here: https://github.com/angular-ui/bootstrap/issues/331
Here's a reusable Angular directive that will hide and show a Bootstrap 3 (or 2.x) modal.
app.directive("modalShow", function () {
return {
restrict: "A",
scope: {
modalVisible: "="
},
link: function (scope, element, attrs) {
//Hide or show the modal
scope.showModal = function (visible) {
if (visible)
{
element.modal("show");
}
else
{
element.modal("hide");
}
}
//Check to see if the modal-visible attribute exists
if (!attrs.modalVisible)
{
//The attribute isn't defined, show the modal by default
scope.showModal(true);
}
else
{
//Watch for changes to the modal-visible attribute
scope.$watch("modalVisible", function (newValue, oldValue) {
scope.showModal(newValue);
});
//Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
element.bind("hide.bs.modal", function () {
scope.modalVisible = false;
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
}
}
};
});
Usage Example #1 - this assumes you want to show the modal - you could add ng-if as a condition
<div modal-show class="modal fade"> ...bootstrap modal... </div>
Usage Example #2 - this uses an Angular expression in the modal-visible attribute
<div modal-show modal-visible="showDialog" class="modal fade"> ...bootstrap modal... </div>
Another Example - to demo the controller interaction, you could add something like this to your controller and it will show the modal after 2 seconds and then hide it after 5 seconds.
$scope.showDialog = false;
$timeout(function () { $scope.showDialog = true; }, 2000)
$timeout(function () { $scope.showDialog = false; }, 5000)
I'm late to contribute to this question - created this directive for another question. Here are some related links: Simple Angular Directive for Bootstrap Modal and https://stackoverflow.com/a/19668616/1009125
Hope this helps.
I quite like the filter feature of django admin views (list_filter).
But, on views with a lot of fields, I would really like the ability to minimize/expand it with a click, to save screen real-estate and also because it sometimes actually hides stuff.
Is there an easy way to add a collapse button (some already existing plugin I haven't found or something similar)?
Given that you now have jQuery in django admin, it's easy to bind a slideToggle() to the titles in the List Filter.
This seems enough Javascript for it to work:
// Fancier version https://gist.github.com/985283
;(function($){ $(document).ready(function(){
$('#changelist-filter').children('h3').each(function(){
var $title = $(this);
$title.click(function(){
$title.next().slideToggle();
});
});
});
})(django.jQuery);
Then in the ModelAdmin subclass you want to activate that set the Media inner class:
class MyModelAdmin(admin.ModelAdmin):
list_filter = ['bla', 'bleh']
class Media:
js = ['js/list_filter_collapse.js']
Make sure to drop the list_filter_collapse.js file in a 'js' folder inside your STATIC_DIRS or STATIC_ROOT (Depending on your Django version)
I changed Jj's answer to collapse the whole filter when clicking on the 'filter' title, adding it here for completeness, a gist is available here:
(function($){
ListFilterCollapsePrototype = {
bindToggle: function(){
var that = this;
this.$filterTitle.click(function(){
that.$filterContent.slideToggle();
that.$list.toggleClass('filtered');
});
},
init: function(filterEl) {
this.$filterTitle = $(filterEl).children('h2');
this.$filterContent = $(filterEl).children('h3, ul');
$(this.$filterTitle).css('cursor', 'pointer');
this.$list = $('#changelist');
this.bindToggle();
}
}
function ListFilterCollapse(filterEl) {
this.init(filterEl);
}
ListFilterCollapse.prototype = ListFilterCollapsePrototype;
$(document).ready(function(){
$('#changelist-filter').each(function(){
var collapser = new ListFilterCollapse(this);
});
});
})(django.jQuery);
I have written a small snippets downloadable on bitbucket for the purpose.
The state of the filters are stored in a cookie and the selected filters stay visible.
Thanks to #JJ's idea.
I added toggles for the whole window, simpler than #abyx's implement.
Toggle the whole filter by clicking "Filter" title
Toggle each list by clicking list title
This is the js file content:
;(function($){ $(document).ready(function(){
$('#changelist-filter > h3').each(function(){
var $title = $(this);
$title.click(function(){
$title.next().slideToggle();
});
});
var toggle_flag = true;
$('#changelist-filter > h2').click(function () {
toggle_flag = ! toggle_flag;
$('#changelist-filter > ul').each(function(){
$(this).toggle(toggle_flag);
});
});
});
})(django.jQuery);
Made another change to this so that the H3's are hidden, as well as the filter lists, when you click on the top H2. This will get the entire list of filters out of the way if you click on the top "Filters".
This is the js file content
;(function($){ $(document).ready(function(){
$('#changelist-filter > h3').each(function(){
var $title = $(this);
$title.click(function(){
$title.next().slideToggle();
});
});
var toggle_flag = true;
$('#changelist-filter > h2').click(function () {
toggle_flag = ! toggle_flag;
$('#changelist-filter').find('> ul, > h3').each(function(){
$(this).toggle(toggle_flag);
});
});
});
})(django.jQuery);
Modified fanlix solution to:
Show cursor as pointer on hover
Be folded by default
Code
(function($){ $(document).ready(function(){
$('#changelist-filter > h3').each(function(){
var $title = $(this);
$title.next().toggle();
$title.css("cursor","pointer");
$title.click(function(){
$title.next().slideToggle();
});
});
var toggle_flag = false;
$('#changelist-filter > h2').css("cursor","pointer");
$('#changelist-filter > h2').click(function () {
toggle_flag = ! toggle_flag;
$('#changelist-filter > ul').each(function(){
$(this).slideToggle(toggle_flag);
});
});
});
})(django.jQuery);
Combined Tim's and maGo's approaches, with some tweaks:
Pros:
Allows user to hide the entire list (added "click to hide/unhide" to the filter list title so user knows what to do).
Maintains folded filter categories by default
Cons:
The page refresh after a filter is selected causes the filter categories to fold once again; ideally the ones you're working with would stay open.
The code:
(function($){ $(document).ready(function(){
// Start with a filter list showing only its h3 subtitles; clicking on any
// displays that filter's content; clicking again collapses the list:
$('#changelist-filter > h3').each(function(){
var $title = $(this);
$title.next().toggle();
$title.css("cursor","pointer");
$title.click(function(){
$title.next().slideToggle();
});
});
// Add help after title:
$('#changelist-filter > h2').append("<span style='font-size: 80%; color: grey;'> (click to hide/unhide)</span>");
// Make title clickable to hide entire filter:
var toggle_flag = true;
$('#changelist-filter > h2').click(function () {
toggle_flag = ! toggle_flag;
$('#changelist-filter').find('> h3').each(function(){
$(this).toggle(toggle_flag);
});
});
});
})(django.jQuery);
I wrote a snippets for menu collapse and single element menu collapse.
It's a fork from abyx code, I've just extended it.
If a filter was previously activated the element menu related to this will start as opened.
The filter menu starts closed as default.
Hope this helps
https://github.com/peppelinux/Django-snippets/tree/master/django-admin.js-snippets
Giuseppe De Marco's snippet works best. So i am adding his code snippet here for easy access. It even solves the problem (Cons) discussed above by joelg:
// Copied from
// https://github.com/peppelinux/Django-snippets/tree/master/django-admin.js-snippets
(function($){
var element_2_collapse = '#changelist-filter';
var element_head = 'h2'
var filter_title = 'h3'
// this is needed for full table resize after filter menu collapse
var change_list = '#changelist'
ListFilterCollapsePrototype = {
bindToggle: function(){
var that = this;
this.$filterTitle.click(function(){
// check if some ul is collapsed
// open it before slidetoggle all together
$(element_2_collapse).children('ul').each(function(){
if($(this).is(":hidden"))
{
$(this).slideToggle();
}
})
// and now slidetoggle all
that.$filterContentTitle.slideToggle();
that.$filterContentElements.slideToggle();
that.$list.toggleClass('filtered');
});
},
init: function(filterEl) {
this.$filterTitle = $(filterEl).children(element_head);
this.$filterContentTitle = $(filterEl).children(filter_title);
this.$filterContentElements = $(filterEl).children('ul');
$(this.$filterTitle).css('cursor', 'pointer');
this.$list = $(change_list );
// header collapse
this.bindToggle();
// collapsable childrens
$(element_2_collapse).children(filter_title).each(function(){
var $title = $(this);
$title.click(function(){
$title.next().slideToggle();
});
$title.css('border-bottom', '1px solid grey');
$title.css('padding-bottom', '5px');
$title.css('cursor', 'pointer');
});
}
}
function ListFilterCollapse(filterEl) {
this.init(filterEl);
}
ListFilterCollapse.prototype = ListFilterCollapsePrototype;
$(document).ready(function(){
$(element_2_collapse).each(function(){
var collapser = new ListFilterCollapse(this);
});
// close them by default
$(element_2_collapse+' '+element_head).click()
// if some filter was clicked it will be visible for first run only
// selezione diverse da Default
$(element_2_collapse).children(filter_title).each(function(){
lis = $(this).next().children('li')
lis.each(function(cnt) {
if (cnt > 0)
{
if ($(this).hasClass('selected')) {
$(this).parent().slideDown();
$(this).parent().prev().slideDown();
// if some filters is active every filters title (h3)
// should be visible
$(element_2_collapse).children(filter_title).each(function(){
$(this).slideDown();
})
$(change_list).toggleClass('filtered');
}
}
})
});
});
})(django.jQuery);
Django 4.x, here is how I do.
create admin template as below
{% extends "admin/change_list.html" %} {% block extrastyle %}
{{ block.super }}
function toggle_filter() {
$("#changelist-filter").toggle("slow");
};
$(document).ready(function(){
// close them by default
$("#changelist-filter").toggle("fast");
}); {% endblock %}
enhance admin/base_site.html to add button
<button onclick="toggle_filter()" class="btn btn-warning btn-sm" type="submit">Toggle Filter</button>