i'm using next JS 13 and created a rich-text editor using react-quilljs package. so far i've created a quill text-area and custom toolbar. when i console log the deltas it returns it with Array. but how can i post and display the delta into readable only? i want to store the delta to server and display it to a page with no editor?
const { quill, quillRef } = useQuill({ theme, modules: modules });
useEffect(() => {
if (quill == null) return;
const handler = (delta, oldDelta, source) => {webkitURL
// if (source !== "user") return;
console.log(delta);
console.log("first");
console.log(oldDelta);
};
quill.on("text-change", handler);
// return quill.off("text-change", handler);
}, [quill]);
return (
<div className="w-full h-[45vh] font-serif font-thin tracking-wide pb-20">
<div ref={quillRef} />
</div>
);
Related
This is my function to download zip file
autoDownload.current.click() - automatically click on HTML element which download my zip file.
But Problem is page used to reload while this process.
How i can prevent my page to reload.
const downloadZipFile = () => {
console.log('download');
autoDownload.current.click();
}
I need something like this.
const downloadZipFile = () => {
console.log('download');
autoDownload.current.click((e) => {
e.preventDefalut();
});
}
Have you tried adding an 'onClick' property to the link/button with a function that includes the e.preventDefault() ? Not sure exactly how you're setting this up, but below has some ideas (using reactjs).
const downloadZipFile = (e) => {
e.preventDefault()
// Add your download zip functionality here
}
// Example of function that will execute on page load
React.useEffect(() => {
downloadZipFile()
}, [])
return (
<Button id='someid' onClick={downloadZipFile} />
)
I'm trying to create a sort of dropdown menu that a user can insert tokens into a CKEditor with. I've found that I can insert text in an editor with this code:
editorInstance.model.change( writer => {
let pos = editorInstance.model.document.selection.getFirstPosition();
writer.insertText( "TEST", pos,0);
});
It works when I put it in the ClassicEditor.create.then for testing but it does nothing when I place this in a $().click event. I can log something from inside the callback so I know the code is executed but nothing is inserted.
I've been trying to get this working for hours now but all the examples I can find is in angular or any other frameworks.
I Solved the issue you faced as follows
first defined new editor that is null and Then instatiate Ckeditor 5
let neditor = null;
ClassicEditor.create(document.querySelector('#editor'))
.then(editor => {
neditor = editor;
})
.catch(error => {
console.error(error);
});
using pure js
document.addEventListener("click", (event) => {
var button = event.target;
if (event.target.type === 'button' && event.target.className.includes('testtokenbutton')) {
neditor.model.change(writer => {
const insertPosition = neditor.model.document.selection.getFirstPosition();
writer.insertText(button.id, insertPosition);
});
}
});
I would like to show the popup only one time with React Hooks.
Access for the first time to example.com/campaign/1234
Show popup
Close or refresh the page.
Access again to example.com/campaign/1234 and don't show popup
Access for the first time to example.com/campaign/0000 (is a different URL)
Show popup
Close or refresh the page
Access again to example.com/campaign/0000 or example.com/campaign/1234 and the popup is not being displayed
Any idea of how to do it? I know that I need to use local storage but how can I trigger the event when the user closes or refreshes the page?
Here is a sandbox.
I also read this thread but it doesn't mention how to do it with Hooks
If you never use the setStickyState callback from the custom hook, the state will just remain at its initial value.
It seems like setStickyState also has a bug in it, where it won't update if the key has changed. Here's an enhanced version that I've called useLocalStorage, which should work more reliably:
export function useLocalStorage(key, initialDefault) {
const [val, setVal] = useState(() => {
const localStorageVal = localStorage.getItem(key);
return localStorageVal !== null
? JSON.parse(localStorageVal)
: initialDefault;
});
useEffect(() => {
if (localStorage.getItem(key) === null) {
setVal(initialDefault);
}
}, [key, initialDefault]);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(val));
}, [val, key]);
return [val, setVal];
}
You can then use it like this:
const [visited, setVisited] = useLocalStorage(pageId, false);
const navigateAway = useCallback(() => {
setVisited(true)
}, [setVisited])
useEffect(() => {
// if user navigates away to a completely different site
// or refreshes the page etc
window.addEventListener("beforeunload", navigateAway);
// if user navigates to another page on the same site
return () => {
navigateAway();
window.removeEventListener("beforeunload", navigateAway);
};
}, [pageId, navigateAway]);
// ...
<dialog open={!visited}>
<p>Welcome to page {pageId}!</p>
<button onClick={() => setVisited(true)}>
Don't show again on this page
</button>
</dialog>
Here's a demo (with TypeScript):
useLocalStorage demo
<script
id="ze-snippet"
src="https://static.zdassets.com/ekr/snippet.js?key=some_zendesk_key"
/>
I'm trying to optimize my web site performance. I've faced a big impact of third-party code to my performance, I think all my bundle has a lower size than zendesk code. How can I load it without impacting on the main thread? Should I use the async or defer tags? Or which approach is better for this case?
This seems to be an issue that tortures so many people without a clear solution.
What I managed to do it to reduce the block time by adding this configuration.
window.zESettings = {
webWidget: {
chat: {
connectOnPageLoad: false
}
}
};
ref https://developer.zendesk.com/embeddables/docs/widget/settings#connectonpageload
ps
I did a performance test to my zendesk helpdesk "domain.zendesk.com" and the results there were even worse
I came across this issue recently and made this hack using a function for loading the zendesk script only when you reached certain point of the doc. I know is kind of dirty but it works:
<script defer type="text/javascript">
(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el){
function visPx(){
var H = $(this).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? H-t : (b<H?b:H)));
} visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
$('#trigger_div').inViewport(function(px){
if(px) {
//zopim code
}
});
Starting from this article https://www.newmediacampaigns.com/blog/maintaining-great-site-performanc-using-zendesk-web-widget I have implemented a solution that significantly reduces the load time by at least 3 seconds (in Google Lighthouse).
I have created a fake button in the HTML that will load the Zendesk script and open the widget when clicked. It will also load a localStorage item that will prevent this from happening on subsequent page loads.
⚠️ Warning:
The code relies heavily on how the widget is currently implemented (for example it expects a #launcher and a #webWidget element to appear on the page), so it can break as soon as the original code changes, but at least we will have an improvement in the loading times until they fix it.
Here is the most important part of the code:
HTML Button
<button class="zendesk-button">
<span class="left-icon">
<!-- here you insert the icon -->
</span>
<span class="text">Chat</span>
</button>
JavaScript code
// select the button
const zendeskButton = document.querySelector('.zendesk-button');
// add the script to the page
const loadZendeskScript = () => {
const zenDeskScript = document.createElement("script");
zenDeskScript.id = "ze-snippet";
zenDeskScript.src = "https://static.zdassets.com/ekr/snippet.js?key=HERE_YOU_INSERT_YOUR_KEY";
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.getElementsByTagName('script')[0].parentNode).insertBefore(zenDeskScript, null);
};
// a poller that waits for a condition and executes a callback
const poller = (comparison, callback, timerStep = 250, maxTime = 5000) => {
// why setTimeout instead of setInterval
// https://stackoverflow.com/questions/8682622/using-setinterval-to-do-simplistic-continuous-polling
let currTime = 0;
const checkCondition = () => {
// `comparison` is a function so the condition is always up-to-date
if (comparison() === true) {
callback();
} else if (currTime <= maxTime) {
currTime += timerStep;
setTimeout(checkCondition, timerStep);
}
};
checkCondition(); // calling the function
};
// load the script and execute a callback if provided
const loadZendeskChat = callback => {
loadZendeskScript();
if (callback) {
callback();
}
};
// this function opens the chat
const openZendeskChat = () => {
poller(
() => {
// check that zendesk-related functions are available
return typeof zE !== 'undefined';
},
() => {
// open the widget
zE('webWidget', 'open');
poller(
() => {
// check that the elements exist and that the opacity is already set to "1"
const launcher = document.querySelector('#launcher');
const webWidget = document.querySelector('#webWidget');
return launcher !== null && webWidget !== null && webWidget.style.opacity === '1';
},
() => {
// hide the fake button
zendeskButton.style.opacity = '0';
// save in localStorage
localStorage.setItem('zd_hasOpened', 'true');
}
);
}
);
};
// zendesk management
if (localStorage.getItem('zd_hasOpened')) {
// load the zendesk widget if we find that it was opened
loadZendeskChat();
} else {
// show the fake button if it's the first time it shows
zendeskButton.style.opacity = '1';
}
// This will run when the .zendesk-button element is clicked
zendeskButton.addEventListener('click', () => {
// add a 'Loading' text to the button, as the widget will take some time to load (between 1 and 2 seconds on my laptop)
zendeskButton.querySelector('.text').innerHTML = 'Loading';
// load the zendesk widget
// open the widget and hide the fake button
loadZendeskChat(openZendeskChat);
});
Regarding styles, I have pretty much copied the style in the original widget, converting ems to pixels, but one part I'd like to highlight is the focus style, because in my opinion it helps telling the user that something is happening.
.zendesk-button:focus {
outline: none;
box-shadow: inset 0 0 0 0.21429rem rgb(255 255 255 / 40%) !important;
}
I want to write a function that can add text into your clipboard and show the added text with your copied text when to paste it.
document.addEventListener('copy', function(e){
e.clipboardData.appendChild(document.createTextNode("hello,world"));
});
<p>I've included the basic site layout so we aren't wasting time creating the form </p>
<p>and making the site looks pretty.</p>
My try failed.
When you copy part of the second line ,for example looks pretty,and pasted it into a leafpad,it will show:
looks pretty hello,world
instead of
looks pretty
Read on this :
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard
This should work given that you have the permissions!
Note that permissions to navigator.clipboard are granted only for pages served over HTTPS.
document.addEventListener('copy', function(e){
appendToClip("+hello,world");
});
function updateClipboard(newClip) {
console.log('updateClipboard', newClip);
navigator.clipboard.writeText(newClip).then(function() {
/* clipboard successfully set */
}, function() {
/* clipboard write failed */
});
}
function appendToClip(text) {
console.log('appendToClip', text);
navigator.permissions.query({name: "clipboard-write"}).then(result => {
console.log(result.state);
// Listen for changes to the permission state
result.onchange = () => {
console.log(result.state);
if (result.state == "granted" || result.state == "prompt") {
navigator.clipboard.readText().then(
clipText =>
updateClipboard(clipText + text));
} else {
console.log('appendToClip: not allowed | ', result.state);
}
};
});
}
<div> test text </div>