I added an image to the Trix editor, generating the following code:
<figure
data-trix-attachment="{lots of data}"
data-trix-content-type="image/jpeg"
data-trix-attributes="{'presentation':'gallery'}"
class="attachment attachment--preview attachment--jpg">
<img src="http://myhost/myimage.jpg" width="5731" height="3821">
<figcaption class="attachment__caption">
<span class="attachment__name">cool.jpg</span> <span class="attachment__size">4.1 MB</span>
</figcaption>
</figure>
When I display the generated HTML from the editor on my Bootstrap-based page, the image obviously extends the screen (see the width and height) and I'd like to remove these props and also assign the img-fluid class to it.
So basically I thought to use the config:
Trix.config.css.attachment = 'img-fluid'
But that does a) not change the attachment class to img-fluid and it also would not apply the changes to the image but the figure.
I would like to avoid using jQuery each time I display the content and traverse all figures and then manipulate the image's properties at runtime.
Isn't there a solution to define these styles when adding the attachment?
Trix does not have any kind of support to change the image element inside the attachment. One way to do it is by using MutationObserver to check for mutations inside Trix editor that apply to attributes, childList and subtree.
If we have a width or height attributes mutation to an img target node with a figure parent node, then we remove those attributes and we can apply the class img-fluid to the first attribute mutation, for example width.
Run code snippet and try to add some image attachments to see or inspect the HTML
Please read inline comments
// Listen to trix-attachment-add event so we'll get rid of the progress bar just for this demo
// Here we should upload the attachment and handle progress properly
document.addEventListener("trix-attachment-add", event => {
const { attachment } = event.attachment;
// Get rid of the progress bar
attachment.setUploadProgress(100)
});
// Get the Trix editor
const editor = document.querySelector('trix-editor');
// Instantiating an observer
const observer = new MutationObserver(function (mutations) {
mutations.forEach(({ type, target, attributeName }) => {
// If the parent is a figure with an img target
if (target.parentNode.tagName === 'FIGURE' &&
target.nodeName === 'IMG')
{
if (type === 'attributes') {
switch(attributeName) {
// If we have attribute width
case 'width':
// Remove attribute width
target.removeAttribute('width');
// Add img-fluid only once
target.classList.add('img-fluid');
break;
// If we have attribute height
case 'height':
// Remove attribute height
target.removeAttribute('height');
break;
}
}
// Render images HTML code
renderHtmlOutput();
}
});
});
// Observing Trix Editor
observer.observe(editor, {
attributes: true,
childList: true,
subtree: true
});
// Function to render every figure > img HTML code
function renderHtmlOutput() {
const images = editor.querySelectorAll('figure > img');
let output = '';
for(const image of images) {
output += image.outerHTML.replace(/ /g, "\n ") + "\n";
}
document.getElementById('output-html').textContent = output;
}
body {
height: 100vh;
margin: 0;
flex-direction: column;
display: flex;
}
#main {
display: flex;
flex-direction: row;
flex: 1;
margin: 10px;
}
#editor-container {
flex: 3;
}
#output-container {
flex: 2;
margin-left: 20px;
border-left: 1px solid lightgray;
overflow: auto;
}
#output-html {
margin: 0;
padding: 10px;
font-size: small;
color: blue;
}
/* Hide some Trix buttons to free horizontal space */
.trix-button--icon-increase-nesting-level,
.trix-button--icon-decrease-nesting-level,
.trix-button--icon-bullet-list,
.trix-button--icon-number-list { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/trix/1.2.1/trix.js" integrity="sha256-2D+ZJyeHHlEMmtuQTVtXt1gl0zRLKr51OCxyFfmFIBM=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/trix/1.2.1/trix.css" integrity="sha256-yebzx8LjuetQ3l4hhQ5eNaOxVLgqaY1y8JcrXuJrAOg=" crossorigin="anonymous"/>
<section id="main">
<div id="editor-container">
<form>
<input id="editor" value="Editor content goes here" type="hidden" name="content">
<trix-editor input="editor"></trix-editor>
</form>
</div>
<div id="output-container">
<pre id="output-html"></pre>
</div>
</section>
Related
I have a container div that holds a react handsontable component, and I want to use the autosizing of the component but at the same time have it centered in the screen (or an outer div).
So in this example:
https://jsfiddle.net/opike99/b1ux0rLy/5/
I'm trying to get the width of div #example1 to match the contents of the table (so by changing the number of columns, the div width will adjust accordingly).
HTML:
<script src="https://cdn.jsdelivr.net/npm/handsontable#11.1/dist/handsontable.full.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable#11.1/dist/handsontable.full.min.css" />
<script src="https://handsontable.com/docs/8.3.2/components/numbro/dist/languages.min.js"></script>
<div class="outer2">
<div class="outer1">
<div id="example1">
</div>
</div>
</div>
JS:
const container = document.querySelector('#example1');
const numberOfColumns = 7;
const hot = new Handsontable(container, {
data: Handsontable.helper.createSpreadsheetData(5, numberOfColumns),
colHeaders: true,
rowHeaders: true,
hiddenColumns: true,
width: 'auto',
height: 'auto',
licenseKey: 'non-commercial-and-evaluation',
});
// re-render your Handsontable instance
hot.render()
CSS:
.outer2 {
}
.outer1 {
}
#example1 {
border-style: solid;
/* width: fit-content; */
}
So I've been playing around with your example, and got the following results:
There's actually three tings you need to do:
The generated $('.wtHolder') has a width: 680px defined on a style attribute, so the only way to remove it is programatically.
$('.ht_master.handsontable, #example1') need width: fit-content
Using a flexbox, I was able to centre the table. I set display: flex; justify-content: center; on $('.outer1').
And for some reason, the order in which these are applied is important too. I got it working with a setTimeout, although you'd probably want something more sophisticated.
setTimeout(function() {
document.querySelector('.wtHolder').style.width = 'initial';
document.querySelector('#example1').style.width = 'fit-content';
const outer = document.querySelector('.outer1');
outer.style.display = 'flex';
outer.style.justifyContent = 'center';
}, 2000);
Let me know how you go.
I have a div container with several images. I want the user to select an image (avatar) from the provided list. Then the avatar image will be uploaded and also accessible. Once the user selects the avatar, I want to save the location of the selected avatar to my database. What is the best way to select the image? Is there any easy way to do this?
HTML
<div class="image-container">
<img src="images/gorillaAvatars/brownGorilla.png" id="brownGorilla">
<img src="images/gorillaAvatars/gorilla.png" id="Gorilla">
<img src="images/gorillaAvatars/greenGorilla.png" id="greenGorilla">
<img src="images/gorillaAvatars/kidGorilla.png" id="kidGorilla">
<img src="images/gorillaAvatars/surpriseGorilla.png" id="surpriseGorilla">
</div>
CSS
<style>
.image-container{
width:60%;
border: solid magenta 1px;
padding: 5px;
margin: 30px;
display: flex;
justify-content: space-evenly;
}
img{
width:80px;
}
img:hover,
img:focus,
img:active{
background-color: blue;
border-radius: 20px;
}
<style>
Javascript
const brownGorillaAvatar = "https://brownGorilla.png";
const mainGorillaAvatar ="https://gorilla.png"
const greenGorillaAvatar ="https://greenGorilla.png"
const kidGorillaAvatar ="https://kidGorilla.png"
const surpriseGorillaAvatar ="https://surpriseGorilla.png"
const avatar = [brownGorillaAvatar,mainGorillaAvatar,greenGorillaAvatar,kidGorillaAvatar, surpriseGorillaAvatar]
brownG.addEventListener('click', avatarSelect);
bigG.addEventListener('click', avatarSelect1);
greenG.addEventListener('click', avatarSelect2);
kidG.addEventListener('click', avatarSelect3);
surpG.addEventListener('click', avatarSelect4);
function avatarSelect (){
console.log(avatar[0])
}
function avatarSelect1 (){
console.log(avatar[1])
}
function avatarSelect2 (){
console.log(avatar[2])
}
function avatarSelect3 (){
console.log(avatar[3])
}
function avatarSelect4 (){
console.log(avatar[4])
}
Rather than attaching an event to each image object, it would be better to attach an event to the container surrounding it.
You can avoid overlapping codes and respond flexibly even if image objects increase.
for example
const imageContainer = document.getElementById("image-container");
imageContainer.onclick = function(e) {
console.log(e.target.id); // you can get img tag's id
}
Have a look at how Event Bubbling and delegation work in javascript to get a better understanding but you want to add the event to the parent container not to each element. So by adding new elements to your array they will be clickable.
const avatars = [
'brownGorillaAvatar',
'mainGorillaAvatar',
'greenGorillaAvatar',
'kidGorillaAvatar',
'surpriseGorillaAvatar'
]
const avatarContainer = document.querySelector('#avatarContainer');
avatars.forEach((avatar) => {
const span = document.createElement('span');
span.innerHTML = avatar;
avatarContainer.appendChild(span);
})
avatarContainer.addEventListener('click', (evt) => {
console.log(evt.target);
})
<html>
<head></head>
<body>
<section id="avatarContainer">
</section>
</body>
</html>
in my react application I have an iframe which is loaded with HTML document and content of it exceeds 1 page. on pressing Ctrl+p I want to print it in several pages but the print preview only shows one page.
how it should be handled to recognize that the content of iframe is more than one A4 page?
the DOM in chrome devtool looks like
<div class="article-container">
<iframe style="">#document
/* hundreds of <p> tags */
</iframe>
</div>
the structure in react app is like
<div className="article-container">
<FrameText content={content} status={!this.state.editStatus} />
</div>
and the FrameText
class FrameText extends React.Component<Props> {
iframe: HTMLIFrameElement;
compinentDidMount(){
window.addEventListener('beforeprint',(e)=>{console.log(e);})
}
/* other stuff*/
render() {
const { status } = this.props;
return <iframe ref={(ref) => (this.iframe = ref!)} style={!status ? { display: 'none' } : {}} />;
}
so here when the ctrl+p is pressed I get the event and the iframe document is in the event. Also, I have the content of iframe in the local state too.
I could not find anywhere that when this event is triggered what can I do with it to manipulate or somehow tell the print preview that the content is long.
Also, the css is
#media print {
.article-container {
background-color: white;
height: 100%;
width: 100%;
position: fixed;
top: 0;
left: 0;
margin: 0;
padding: 15px;
font-size: 14px;
line-height: 18px;
}
}
Your print media query will not work on iframe inner content that is the reason iframe size is ignored while printing If you want to apply specific print styles to iframe then you have to reference from outside via appropriate method(whether js or html) I am writing a sample to reference styles to iframe there may exist other implementations for it to
let cssLink = document.createElement("link");
cssLink.href = "style.css";
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
frames['iframe1'].document.head.appendChild(cssLink);
I was able to print multiple pages in an iframe by capturing the CTRL P event, giving focus to the iframe then initiating printing on the iframe.
<iframe id="iframe" name="iframe" src="2.html"></iframe>
<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
$(document).bind("keyup keydown", function (e) {
if (e.ctrlKey && e.keyCode === 80) {
window.frames["iframe"].focus();
window.frames["iframe"].print();
return false;
}
return true;
});
</script>
I have been tasked to take some pre-existing code which has a float event on an org chart. When you hover over an individual on the org chart a picture pops up and displays all the employees under them.
They don't like that and would like it changed to a click event. I've listed the code for the float event but what would be an example of taking the contentFloating and making it a click event? Looking for the proper syntax please.
}
.orgContainer .contentStable .contentFloating img {
height: 720px;
width: 960px;
}
/* Float content */
.orgContainer .contentFloating {
border: 2px solid black;
display: none;
position: fixed;
}
.orgContainer .contentStable:hover .contentFloating {
display: block;
top: 7%;
left: 15%;
}
<div class="contentStable">
<img title="Scott Plemmons Director Supplier Quality Compliance" src="/sites/scm/utas_supp_qual/Home_Pictures/scott_plemmons.jpg" />
<p>
Scott Plemmons<br/> Director
<br/> Supplier Quality
</p>
<div class="contentFloating">
<img src="/sites/scm/utas_supp_qual/Home_Pictures/Org_Charts/Scott_Plemmons_Chart.jpg" />
</div>
</div>
This is an example of how to add a click event handler to a dom element, and then make another div appear when you click on it.
html
<div class="orgchart">click for details</div>
<div id="details">details</div>
css
#details {
position:absolute;
}
javascript
let elements = document.getElementsByClassName("orgchart");
for(var i = 0; i < elements.length; i++)
{
elements[i].addEventListener("click", function(e){
// get the position of the element that was clicked
let clickedItem = e.target;
var rect = clickedItem.getBoundingClientRect();
// set the details div to that position and fill it with content
let details = document.getElementById("details");
details.innerHTML = "Joe Average";
details.style.left = (rect.left + 10) + "px";
details.style.top = (rect.top + 20) + "px";
});
}
Check a jsfiddle example here
I want to hide all images which have no data-web-src attribute on 767px. I tried the following but I failed; how can I do that?
$('#homepage-carousel .lazy_res').each(function(index, value) {
var ws = $(window).width();
var large = 1024;
var medium = 767;
var small = 0;
if (ws <= medium) {
$(this).not('[data-web-src]').hide();
} else {
$(this).not('[data-web-src]').show();
}
});
img {
width: 500px;
float: left;
margin-right: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="homepage-carousel">
<img class="lazy_res" src="http://pre07.deviantart.net/338a/th/pre/i/2012/007/f/7/mapa_mundi_com_bandeiras___preto_by_plamber-d4leocd.jpg" alt="" />
<img class="lazy_res" src="http://img05.deviantart.net/a6be/i/2013/099/8/9/helena_harper_by_plamber-d6125tx.jpg">
</div>
Codepen Demo
This should be done with CSS Media Queries. No JavaScript required.
/* Set page default styles and styles that should only
be in effect for viewports under 767px wide here. */
img {
width: 500px;
float: left;
margin-right: 10px;
}
/* Apply the following CSS only to viewports wider than 767px */
#media (min-width: 767px) {
/* Select all images except those with an attribute of: dat-web-src */
img:not([data-web-src]) {
display: none; /* Hide the matching elements */
}
/* Make any other CSS changes you like here */
/* This class will only be applied to images when the media query
is in effect. */
img.someNewClass {
/* Whatever you need here */
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="homepage-carousel">
<img class="lazy_res" src="http://localhost:82/works/anitur/img/slider/1.jpg" alt="" />
<img class="lazy_res" src="http://localhost:82/works/anitur/img/assets/mice-1.jpg">
</div>
You need to set your code within a function and then it can be called onload and also onresize to test it:
see https://api.jquery.com/on/
Description: Attach an event handler function for one or more events to the selected elements.
function testit() {
$("#homepage-carousel .lazy_res").each(function(index, value) {
var ws = $(window).width();
var large = 1024;
var medium = 767;
var small = 0;
if (ws <= medium) {
$(this).not('[data-web-src]').hide();
} else {
$(this).not('[data-web-src]').show();
}
});
}
$(window).on('resize load', testit );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
below 767px wide, you'll see nothing else here :), use the full page mode to test the snippet. then resize the window
<div id="homepage-carousel">
<img class="lazy_res" src="http://pre07.deviantart.net/338a/th/pre/i/2012/007/f/7/mapa_mundi_com_bandeiras___preto_by_plamber-d4leocd.jpg" alt="" />
<img class="lazy_res" src="http://img05.deviantart.net/a6be/i/2013/099/8/9/helena_harper_by_plamber-d6125tx.jpg">
</div>
https://codepen.io/gc-nomade/pen/EXLZEN