Enabling CSS for HTML targets with Stimulus - ruby-on-rails

The following importmap had to have the entry for stimulus commented out
pin "application", preload: true
pin "#hotwired/turbo-rails", to: "turbo.min.js", preload: true
# pin "#hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "#hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "trix"
pin "#rails/actiontext", to: "actiontext.js"
in order to run the following HTML behaviour with CSS using a link target
<div class="thumb-wrapper">
<a href="#img1">
<img src="https://unsplash.it/800/400?image=17" class="thumbnail_lb">
</a>
<a href="#img2">
<img src="https://unsplash.it/800/400?image=13" class="thumbnail_lb">
</a>
<a href="#img3">
<img src="https://unsplash.it/800/400?image=3" class="thumbnail_lb">
</a>
</div>
<!-- lightbox container hidden with CSS -->
<a href="#" class="lightbox" id="img1">
<img src="https://unsplash.it/800/400?image=17">
</a>
<a href="#" class="lightbox" id="img2">
<img src="https://unsplash.it/800/400?image=13">
</a>
<a href="#" class="lightbox" id="img3">
<img src="https://unsplash.it/800/400?image=2">
</a>
stylesheet
.thumbnail_lb {
max-width: 80px;
margin: 1em;
float: left;
}
.lightbox {
display: none;
position: fixed;
z-index: 999;
width: 100%;
height: 100%;
text-align: center;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
.lightbox img {
max-width: 90%;
max-height: 80%;
margin-top: 2%;
}
.lightbox:target {
outline: none;
display: block;
}
.thumb-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
with stimulus enabled, the browser inspector shows the hidden container being highlighted as its source wrapper is clicked upon, but nothing happens in the browser. Reloading the browser with say #img3 generates the overlay,but clicking on it does not return to the page overlay-less.
stimulus is entirely geared around targetting. I have not found documentation indicating that CSS-targetting HTML would be impeded by the presence of this library, although I may have missed it.
How can CSS-driveng taargetting co-exist with stimulus?

I don't know about stimulus, but turbo intercepts click events and does it's own url fetching, and it looks like it doesn't play well with # urls.
You can disable turbo around the lightbox links:
<div data-turbo="false">
<!-- lightbox code -->
</div>
https://turbo.hotwired.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms
or you can bypass turbo navigation by catching click events first:
// for any clicks
document.addEventListener("click", e => {
const target = e.target.closest("a[href^='#']")
if (target) {
// this is what Turbo does, normally, which doesn't work.
// Turbo.visit(target.href)
window.location = target.href // bypass Turbo navigation
e.preventDefault();
}
})
// for link clicks
document.addEventListener("turbo:click", e => {
if (e.target.matches("a[href^='#']")) {
e.preventDefault();
}
})
https://turbo.hotwired.dev/reference/events

Related

Nav Tabs positioned at the bottom of the page with Angular Material

I'm trying to build a tab navigation bar like the example below (copied from Ionic docs) with Angular Material. Each of these tabs will lazy load different pages.
To lazy load pages on each tab, the doc suggests using nav mat-tab-nav-bar component. However, this component presents the tabs bar at the top of the page and I need this bar at the bottom of it.
As in the docs, the mat-tab-group has this attribute called headerPosition that can be used to position the tab bar at the bottom of the page, but it doesn't work on the nav mat-tab-nav-bar component.
Can anyone help me either create a tab that can open pages/components in lazy mode with mat-tab-group or position the nav mat-tab-nav-bar component at the bottom of the page?
Currently my component is:
tabs.page.html
<nav mat-tab-nav-bar headerPosition="below" >
<a mat-tab-link *ngFor="let page of pages" (click)="activePage = page.path" [active]="activePage == page.path"> {{ page.label }} </a>
</nav>
<router-outlet></router-outlet>
tabs.page.ts
// ...
export class TabsPage implements OnInit {
readonly pages = [
{
path: 'page1',
label: 'Page 1',
},
{
path: 'page2',
label: 'Page 2',
},
];
activePage = this.pages[0].path;
constructor() { }
// ...
}
Heres the sample.
.page-container {
background-color: #f8f9fa;
padding: 10px;
width: 90%;
min-width: 378px;
}
.parent-container,
.d-flex {
display: flex;
}
.child-centered,
.m-auto {
/* Magic! */
margin: auto;
max-width: 430px;
min-width: 220px;
}
div#topdiv, div#bottomdiv{
position:fixed;
left: 0px;
width: 100%;
color: #CCC;
}
div#topdiv{top:0px;}
div#bottomdiv {bottom:0px;}
<div class="parent-container">
<div class="child-centered">
<router-outlet>
</router-outlet>
<div style="height: 150px;"> </div>
<footer id="bottomdiv" class="parent-container">
<nav mat-tab-nav-bar class="child-centered mat-tab-group-inverted-header main-nav" >
<a mat-tab-link style="height: 80px; width: 40px;" *ngFor="let link of navLinks"
routerLink="{{ link.location }}" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">
<div style="padding: 10px;">
<mat-icon class="example-tab-icon">{{ link.icon }}</mat-icon>
<div>{{ link.label }}</div>
</div>
</a>
</nav>
</footer>
</div>
</div>

is it possible to customize the vue components?

Is it possible to customize the vue components that quasar has?
I want to use the color picker vue component from the quasar framework (this one https://quasar.dev/vue-components/color-picker), but i wanted to remove the header and keep the hexadecimal color input.
I know there is a "no header" version of the component, but that version also removes the color input.
Here an image to exemplify
I want to keep the green part and remove the red part
You can hide the header completely and add a custom header which shows value of the current color.
<link href="https://cdn.jsdelivr.net/npm/quasar#1.8.3/dist/quasar.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.8.3/dist/quasar.umd.min.js"></script>
<div id="q-app">
<div class="q-pa-md">
<div class="container">
<div class="custom-header">{{hex}}</div>
<q-color no-header v-model="hex" dark class="my-picker" ></q-color>
</div>
</div>
</div>
<script>
new Vue({
el: '#q-app',
data () {
return {
hex: '#FF00FF'
}
}
})
</script>
<style>
.my-picker{
width: 150px
}
.container {
width: 180px;
position: relative;
}
.custom-header {
text-align: center;
background: transparent;
position: absolute;
width: 100%;
top: 0;
left: 0;
z-index: 10000
}
</style>
codepen

Bootstrap 3 column class interfering with jquery-ui droppable div

I'm using jQuery-UI v1.11.2 in order to create some draggable and droppable divs, and Boostrap 3.1.1 as well.
I'd like to know why a Boostrap column class is interfering with the draggable "hint".
In other words, as I drag an image from my Gallery div to my Dashboard div, the Dashboard div comes in FRONT of the image hint. Then once I DROP my image on the Dashboard div, the image re-appears.
If I remove the col-md-8 class from the Dashboard div, this problem goes away.
Here are two screen shots to demonstrate:
1) WITHOUT the Bootstrap column class on the right div (image hint looks good)
2) With the Bootstrap column class on the right div (image hint disappears)
Here's the HTML code :
<section id="gadgets-view" class="mainbar" data-ng-controller="gadgets">
<div class="container-fluid">
<div class="row-fluid">
<!-- based on http://jqueryui.com/droppable/#photo-manager -->
<div class="ui-widget ui-helper-clearfix col-md-4"> <-- GALLERY OF WIDGETS -->
<ul id="gallery" class="gallery ui-helper-reset ui-helper-clearfix">
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Tree Grid</h5>
<img src="images/treegrid.jpg" alt="Hierarchy Grid" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Area Chart</h5>
<img src="images/chart_area.jpg" alt="Area Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Bar Chart</h5>
<img src="images/chart_bar.png" alt="Bar Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Column Chart</h5>
<img src="images/chart_column.png" alt="Column Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Line Chart</h5>
<img src="images/chart_line.png" alt="Line Chart" width="96" height="72">
</li>
</ul>
</div>
<div class="col-md-8">
<div id="dashboard" class="ui-widget-content ui-state-default "> <-- DROPPABLE DASHBOARD -->
<h4 class=""><span class="ui-icon ui-icon-image"></span>Dashboard</h4>
</div>
<div>
</div>
</div>
</section>
The CSS :
<style>
.ui-widget-header{
font-size: 65%;
font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif";
}
.ui-state-highlight {
border: 2px dashed #d3d3d3; /* override to show dashed border when dragging */
}
#gallery {
float: left;
width: 75%;
min-height: 12em;
}
.gallery.custom-state-active {
background: #eee;
}
.gallery li {
list-style: none;
float: left;
width: 96px;
padding: 0.4em;
margin: 0 0.4em 0.4em 0;
text-align: center;
}
.gallery li h5 {
margin: 0 0 0.4em;
cursor: move;
}
.gallery li a {
float: right;
}
.gallery li a.ui-icon-zoomin {
float: left;
}
.gallery li img {
width: 100%;
cursor: move;
}
#dashboard {
float: left;
width: 45%;
height:500px;
padding: 1%;
}
#dashboard h4 {
line-height: 25px;
margin: 0 0 0.4em;
}
#dashboard h4 .ui-icon {
float: left;
}
#dashboard .gallery h5 {
display: none;
}
The JavaScript to create drag/drop areas :
<script>
$(function () {
// there's the gallery and the dashboard
var $gallery = $("#gallery"),
$dashboard = $("#dashboard");
// let the gallery items be draggable
$("li", $gallery).draggable({
cancel: "a.ui-icon", // clicking an icon won't initiate dragging
revert: "invalid", // when not dropped, the item will revert back to its initial position
containment: "document",
helper: "clone",
cursor: "move"
});
// let the dashboard be droppable, accepting the gallery items
$dashboard.droppable({
accept: "#gallery > li",
activeClass: "ui-state-highlight",
drop: function (event, ui) {
debugger;
deleteImage(ui.draggable);
}
});
// let the gallery be droppable as well, accepting items from the dashboard
$gallery.droppable({
accept: "#dashboard li",
activeClass: "custom-state-active",
drop: function (event, ui) {
recycleImage(ui.draggable);
}
});
// image deletion function
var recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off' title='Remove gadget' class='ui-icon ui-icon-minus'></a>";
function deleteImage($item) {
$item.fadeOut(function () {
var $list = $("ul", $dashboard).length ?
$("ul", $dashboard) :
$("<ul class='gallery ui-helper-reset'/>").appendTo($dashboard);
//$item.find("a.ui-icon-dashboard").remove(); // DO NOT REMOVE ORIGINAL WIDGET ICON - 11/19/2014 BM:
$item.append(recycle_icon).appendTo($list).fadeIn(function () {
//$item.animate({ width: "48px" }).find("img").animate({ height: "36px" });
$item.animate().find("img").animate();
});
});
}
// image recycle function
var dashboard_icon = "<a href='link/to/dashboard/script/when/we/have/js/off' title='Add this gadget' class='ui-icon ui-icon-plus'</a>";
function recycleImage($item) {
$item.fadeOut(function () {
$item
.find("a.ui-icon-refresh")
.remove()
.end()
.css("width", "96px")
.append(dashboard_icon)
.find("img")
.css("height", "72px")
.end()
.appendTo($gallery)
.fadeIn();
});
}
// image preview function, demonstrating the ui.dialog used as a modal window
function viewLargerImage($link) {
var src = $link.attr("href"),
title = $link.siblings("img").attr("alt"),
$modal = $("img[src$='" + src + "']");
if ($modal.length) {
$modal.dialog("open");
} else {
var img = $("<img alt='" + title + "' width='384' height='288' style='display: none; padding: 8px;' />")
.attr("src", src).appendTo("body");
setTimeout(function () {
img.dialog({
title: title,
width: 400,
modal: true
});
}, 1);
}
}
// resolve the icons behavior with event delegation
$("ul.gallery > li").click(function (event) {
var $item = $(this),
$target = $(event.target);
if ($target.is("a.ui-icon-dashboard")) {
deleteImage($item);
} else if ($target.is("a.ui-icon-zoomin")) {
viewLargerImage($target);
} else if ($target.is("a.ui-icon-refresh")) {
recycleImage($item);
}
return false;
});
});
I found the problem you describe (but i did not found a relation with the Bootstrap Grid Classes).
For my the problem seems to be related to the z-index and can be solved by adding the following style rules at the end of your CSS code:
.ui-draggable-handle {
z-index: 1;
}

Twitter modal positioning

so I'm using the Twitter Bootstrap plugin for Grails and I'm having trouble centering modals. When I remove the class="modal" part from the div that contains the modal, my centering function works properly, but when I put it back (which is necessary for it to have the functionality of a modal it gets stuck halfway off the page). Any help would be very nice :D
Here's my code:
<a style="position: relative; top: 2px;" data-toggle="modal" href="#myModal${instanceType.id}"
id="${instanceType.id}"> ${message} </a>
<div class="modal" style="background: black; overflow: hidden; top: 0px; left: 0px; display: none; border: 2px solid white; float: center; position: absolute"
id="myModal${instanceType.id}">
<div style="border:none" class="modal-header">
<a style="color:white;" class="close" data-dismiss="modal">X</a>
</div>
<iframe id="iFrame" style="border: none;"width=800px height=675px src="${action}/${instanceType.id}">
</iframe>
<div class="modal-body" style="background: black;"></div>
<div style="border:none; background: black;" class="modal-footer">
<a "="#" class="btn" data-dismiss="modal">Close</a>
</div>
</div>
<script>
jQuery.fn.center = function () {
this.css("position","absolute");
this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px");
this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px");
return this;
}
$(myModal${instanceType.id}).css({
'width' : $(window).width()*.75,
'height' : $(window).height()*.75
})
$(myModal${instanceType.id}).center()
$('#modal-footer').append('${saveName}')
function submitFunction(){
$("iFrame").contents().find("#submit").click()
}
function changePre(){
$("iFrame").contents().find(".buttonNew").submit()
alert('hi')
}
</script>
If you're using the default modal styling centers the modal by absolute positioning. So when you customize a modal windows, and you change the size of it, you shall adjust relevant elements also. Like the modal-body and modal header and the .modal class.
And to answer your question, and if I got your question right, that is you were trying to position your modal VERTICALLY.
Open bootstrap.css , then find and edit .modal.fade.in
The default value is 50%. Try to play with it until you achieve your desired position. Increase it to move the modal to the bottom, decrease it and it will do the opposite.
Default modal size modal window positions Horizontal centre of the screen, once the modal customizes(width changes), need to position it with script.
sample script:
$('#myModal').modal({
backdrop: true,
keyboard: true
}).css({
width: '800',// custom width
'margin-left': function () {
return -($(this).width() / 2);
}
});

jQuery UI dialog modal set to true doesn't work for radiobuttons

When the dialog is set to modal it should disable all input elements, but I tried a simple example with a textbox and a radiobutton. When the dialog is opened the text-input is disabled as expected, but i still can check the radiobutton.
I used the example from the jQuery-ui demo and a simple html with just a input-textbox and the radio.
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="dialog-message" title="Download complete" style="display:none">
<p>
<span class="ui-icon ui-icon-circle-check" style="float:left; margin:0 7px 50px 0;"></span>
Your files have downloaded successfully into the My Downloads folder.
</p>
<p>
Currently using <b>36% of your storage space</b>.
</p>
</div>
<input type="text"/>
<input type="radio" onClick="showDialog();"/>
<input type="radio"/>
</body>
</html>
And the jQuery:
function showDialog(){
jQuery(function() {
jQuery( "#dialog-message" ).dialog({
position: 'center',
zIndex: 4001,
draggable: false,
modal: true,
buttons: {
Ok: function() {
jQuery( this ).dialog( "close" );
}
}
});
});
}
Problem solved. It had to do with the css. Because I didn't use the default css or css created with theme roller I forgot to define the styling for ui-widget-overlay. After I copied the ovelay-styling from the jquery-ui css everything worked fine.
the css:
.ui-widget-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ui-widget-overlay {
background: #666666 url(ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat;
opacity: .50;
filter:Alpha(Opacity=50);
}

Resources