Autosave Status in CKEditor 5 - ckeditor

I have gotten stuck on a rather simple aspect of the autosave feature and that is the current status of the action like found on the overview page: https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/saving-data.html#demo. But it doesn't look like they actually reference it anywhere (example below).
My html is just:
<textarea class="form-control" name="notes" id="notes">{!! $shipmentShortage->notes !!}</textarea>
My create script is below, the autosave feature works just fine, but the status just isn't there:
<script>
ClassicEditor
.create( document.querySelector( '#notes' ), {
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
image: {
toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ],
},
autosave: {
save( editor ) {
console.log(editor.getData());
// The saveData() function must return a promise
// which should be resolved when the data is successfully saved.
return saveData( editor.getData() );
}
}
} );
// Save the data to a fake HTTP server (emulated here with a setTimeout()).
function saveData( data ) {
return new Promise( resolve => {
setTimeout( () => {
console.log( 'Saved', data );
$.ajax({
url: '/osd/shortages/update',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: {
'shortage_id':'{{$shipmentShortage->id}}',
'notes': data,
},
dataType: 'json',
success: function (response) {
console.log('saved');
}
});
resolve();
}, 5000 );
} );
}
// Update the "Status: Saving..." info.
function displayStatus( editor ) {
const pendingActions = editor.plugins.get( 'PendingActions' );
const statusIndicator = document.querySelector( '#editor-status' );
pendingActions.on( 'change:hasAny', ( evt, propertyName, newValue ) => {
if ( newValue ) {
statusIndicator.classList.add( 'busy' );
} else {
statusIndicator.classList.remove( 'busy' );
}
} );
}
</script>

You are absolutely correct. They show us a sexy status updater but don't give us the code for it. Here is what I extracted from the demo page by looking at the page source. This should give you the Status updates as you asked. Let me know if you have any questions.
HTML:
<div id="snippet-autosave">
<textarea name="content" id="CKeditor_Notes">
Sample text
</textarea>
</div>
<!-- This will show the save status -->
<div id="snippet-autosave-header">
<div id="snippet-autosave-status" class="">
<div id="snippet-autosave-status_label">Status:</div>
<div id="snippet-autosave-status_spinner">
<span id="snippet-autosave-status_spinner-label"></span>
<span id="snippet-autosave-status_spinner-loader"></span>
</div>
</div>
</div>
CSS:
<style>
#snippet-autosave-header{
display: flex;
justify-content: space-between;
align-items: center;
background: var(--ck-color-toolbar-background);
border: 1px solid var(--ck-color-toolbar-border);
padding: 10px;
border-radius: var(--ck-border-radius);
/*margin-top: -1.5em;*/
margin-bottom: 1.5em;
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
#snippet-autosave-status_spinner {
display: flex;
align-items: center;
position: relative;
}
#snippet-autosave-status_spinner-label {
position: relative;
}
#snippet-autosave-status_spinner-label::after {
content: 'Saved!';
color: green;
display: inline-block;
margin-right: var(--ck-spacing-medium);
}
/* During "Saving" display spinner and change content of label. */
#snippet-autosave-status.busy #snippet-autosave-status_spinner-label::after {
content: 'Saving...';
color: red;
}
#snippet-autosave-status.busy #snippet-autosave-status_spinner-loader {
display: block;
width: 16px;
height: 16px;
border-radius: 50%;
border-top: 3px solid hsl(0, 0%, 70%);
border-right: 2px solid transparent;
animation: autosave-status-spinner 1s linear infinite;
}
#snippet-autosave-status,
#snippet-autosave-server {
display: flex;
align-items: center;
}
#snippet-autosave-server_label,
#snippet-autosave-status_label {
font-weight: bold;
margin-right: var(--ck-spacing-medium);
}
#snippet-autosave + .ck.ck-editor .ck-editor__editable {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
#snippet-autosave-lag {
padding: 4px;
}
#snippet-autosave-console {
max-height: 300px;
overflow: auto;
white-space: normal;
background: #2b2c26;
transition: background-color 500ms;
}
#snippet-autosave-console.updated {
background: green;
}
#keyframes autosave-status-spinner {
to {
transform: rotate( 360deg );
}
}
</style>
The rest is just initializing the Editor just like on the demo page here.
ClassicEditor
.create(document.querySelector('#CKeditor_Notes'), {
autosave: {
save(editor) {
return saveData(editor.getData());
}
}
})
.then(editor => {
window.editor = editor;
displayStatus(editor);
})
.catch(err => {
console.error(err.stack);
});
// Save the data to Server Side DB.
function saveData(data) {
return new Promise(resolve => {
setTimeout(() => {
console.log('Saved', data);
SaveDataToDB(data)
resolve();
});
});
}
// Update the "Status: Saving..." info.
function displayStatus(editor) {
const pendingActions = editor.plugins.get('PendingActions');
const statusIndicator = document.querySelector('#snippet-autosave-status');
pendingActions.on('change:hasAny', (evt, propertyName, newValue) => {
if (newValue) {
statusIndicator.classList.add('busy');
} else {
statusIndicator.classList.remove('busy');
}
});
}

Related

Toggle Button doesn't work inside datatable in laravel

The InActive button in the top of the picture, gets displayed properly when it is outside the datatable but doesn't work inside the datatable.
I have added the same code for status column inside the datatable but it displays only a checkbox. How do I get the InActive button inside datatable?
<script type="text/javascript">
$(document).ready(function() {
$.noConflict();
fill_datatable();
function fill_datatable(collegeID = '') {
var table = $('.user_datatable1').DataTable({
order: [
[0, 'desc']
],
processing: true,
serverSide: true,
ajax: {
url: "{{ route('alumni.datatable1') }}",
data: {
collegeID: collegeID
}
},
columns: [{
data: 'id',
name: 'id'
},
{
data: 'name',
name: 'name'
},
{
data: 'status',
name: 'status',
mRender: function(data) {
return ' <input data-id="{{$colleges->id}}" class="toggle-class" type="checkbox" data-onstyle="success" data-offstyle="danger" data-toggle="toggle" data-on="Active" data-off="InActive" {{ $colleges->status ? "checked" : "" }}>'
}
}
},
{
data: 'action',
name: 'action',
orderable: false,
searchable: false
},
]
});
}
});
$(function() {
$('.toggle-class').change(function() {
var status = $(this).prop('checked') == true ? 1 : 0;
var user_id = $(this).data('id');
$.ajax({
type: "GET",
dataType: "json",
url: '/changeStatus',
data: {'status': status, 'id': id},
success: function(data){
console.log(data.success)
}
});
})
})
</script>
Please Add css.....
CSS
<style>
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
</style>
You can simple put after status....
Toggle switch
{
"data": "id",
render: function(data, type, row, meta) {
$html = '<label class="switch"> <input type="checkbox">
<span class="slider round"></span></label>';
return $html;
}
},

How to fade one react component out, then fade another in?

I've got 2 components that are conditionally shown or hidden based on a string value stored in useState as showModal
{showModal === 'SIGNIN' && <SignIn />}
{showModal === 'JOIN' && <Join />}
I want to fade in one component, then when the state changes, fade it out and fade in the other component.
Can this be done with react transition group?
I tried
<TransitionGroup>
<CSSTransition in={showModal === 'SIGNIN' ? true : false} classNames='fade' timeout={220} key={showModal}>
<div>
<SignIn />
</div>
</CSSTransition>
<CSSTransition in={showModal === 'JOIN' ? true : false} classNames='fade' timeout={220} key={showModal}>
<div>
<Join />
</div>
</CSSTransition>
</TransitionGroup>
I don't get any error, one component is shown, changing showModal from 'SIGNIN' to 'JOIN' does nothing. Inspecting the divs with the timeout set to 22000 shows that no new classes have been added.
SwitchTransition from react transition group might help.
Example
const { useState, useEffect } = React;
const { SwitchTransition, CSSTransition } = ReactTransitionGroup;
const SignIn = () => <div className="block sign-in">Sign In</div>;
const Join = () => <div className="block join">Join</div>;
const App = () => {
const [showModal, setModal] = useState("SIGNIN");
useEffect(() => {
let handle;
const loop = () => {
setModal(state => state === "JOIN" ? "SIGNIN" : "JOIN");
handle = setTimeout(loop, 2500);
};
handle = setTimeout(loop, 1000);
return () => {
clearTimeout(handle);
}
}, []);
const addEndListener = (node, done) => {
node.addEventListener("transitionend", done, false);
}
return <div>
<SwitchTransition mode="out-in">
<CSSTransition
key={showModal === "SIGNIN"}
addEndListener={addEndListener}
classNames="fade">
{showModal === "SIGNIN" ? <SignIn/> : <Join/>}
</CSSTransition>
</SwitchTransition>
</div>;
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
body {
margin: 0;
overflow: hidden;
font-family: Georgia, serif;
}
.block {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 10px;
color: white;
width: 200px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
}
.sign-in {
background: #0984e3;
}
.join {
background: #6c5ce7;
}
.fade-enter {
opacity: 0;
transform: translate(-100%, -50%);
}
.fade-exit {
opacity: 1;
transform: translate(-50%, -50%);
}
.fade-enter-active {
opacity: 1;
transform: translate(-50%, -50%);
}
.fade-exit-active {
opacity: 0;
transform: translate(100%, -50%);
}
.fade-enter-active,
.fade-exit-active {
transition: opacity 500ms, transform 500ms;
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-transition-group#4.4.2
/dist/react-transition-group.min.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>

How to style dropdown with styled-components

I am using React JS + Typescript for my app. For styling I am using styled-components. I am really new in styled components. I have created one dropdown. The logic works fine but the UI looks horrible. I uploaded my code in Code sand box. I want design my Dropdown like Tailwind. But since I am new styled-components, I just don't know how to do that.
This is my dropdown component
import React, { useState } from "react";
import styled from "styled-components";
import Arrow from './Arrow.svg'
const Wrapper = styled.div<
{
active: boolean;
}
>`
text-align: left;
width: 100%;
color: #bfc5cd;
font-size: 16px;
font-weight: 300;
position: relative;
margin: 2em 0;
#media (min-width: 400px) {
max-width: 300px;
}
svg {
fill: #798697;
transition: all 0.2s ease;
}
${props =>
props.active
? `
svg {
transform: rotate(180deg);
}
`
: ``}
`;
const MenuLabel = styled.span`
display:inline-block;
color: grey;
border: 1px solid green;
background: white;
box-shadow: 0 0 5px -1px rgba(0,0,0,0.2);
cursor:pointer;
vertical-align:middle;
max-width: 100px;
padding: 40px 40px;
font-size: 12px;
text-align: center;
border: 1px solid ${({ theme }) => theme.inputBorderColor};
&:focus {
outline: none;
box-shadow: 0px 0px 0px 1px ${({ theme }) => theme.inputBorderColorActive};
border: 1px solid ${({ theme }) => theme.inputBorderColorActive};
}
`;
const ItemList = styled.div`
color: #798697;
background: white;
line-height: 30px;
padding: .25em 2em .25em 2em;
cursor: defaul;
user-select: none;
transition: all .25s ease;
&:hover,
&.selected {
background: #F7F7F7;
color: #4A4A4A;
}
`;
export interface IOptions {
label: string;
value: number;
}
export interface IDropdown {
labelDefault: string;
options: IOptions[];
}
const Dropdown = ({ labelDefault, options }: IDropdown) => {
const [isOpened, setIsOpened] = useState(false);
const [selectedOption, setSelectedOption] = useState("");
const [label, setLabel] = useState("");
const handleSelectedItem = (obj: any) => {
setSelectedOption(obj.value);
setLabel(obj.label);
setIsOpened(!isOpened);
};
return (
<Wrapper active={isOpened}>
<MenuLabel onClick={() => setIsOpened(!isOpened)}>
{selectedOption ? label : labelDefault}
</MenuLabel>
<ul
style={
isOpened
? {
display: "block",
listStyleType: "none"
}
: { display: "none" }
}
>
{options.map(el => (
<ItemList
key={el.value.toString()}
onClick={() => handleSelectedItem(el)}
>
{el.label}
</ItemList>
))}
</ul>
</Wrapper>
);
}
export default Dropdown;
This is the parent component
import * as React from "react";
import Dropdown from "./dropdown";
const MockData = [
{ label: "one", value: 1 },
{ label: "two", value: 2 },
{ label: "three", value: 3 }
];
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Dropdown labelDefault="Select a label" options={MockData} />
</div>
);
}

zooming out of SVG using CSS

I have this SVG of a paperplane, which I want to have inside of a circle.
However, when I do the following the SVG is cropped at the edges. The nature of SVG is being scaleable, I have tried fiddling with the properties of the SVG however the problem remains. What should I do to keep this SVG
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 18.7 14.3" style="enable-background:new 0 0 18.7 14.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#000;}
</style>
<path class="st0" d="M18.7,0L0.3,4.1l3,3.6L0,9.4l0.5,4.9l5.6-4.1l2.3,1.5L18.7,0z M1.3,4.4L16,1.2L3.8,7.4L1.3,4.4z M10.3,4.7
l-9.3,5.5l-0.2,1.7L0.6,9.7L10.3,4.7z M1.2,13.2l0.4-2.7l2.6-1.6l1.5,1L1.2,13.2z M4.7,8.6l12-7.1l-8.3,9.5L4.7,8.6z"/>
</svg>
This is my HTML and CSS
.choice {
background-color: #E0D6AF;
border-radius: 50%;
height: 200px;
width: 200px;
margin: 10px auto;
transition: transform 0.2s;
transform: scale(1);
z-index: 10;
}
<img id="paper" class="choice" value="paper" src="http://www.jerrylow.com/demo/rps/paper.svg" alt="a piece of paper"> </img>
Full CSS file
.container {
display: inline-grid;
padding-top:30px;
grid-gap: 2px;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}
#submit {
border-radius: 50%;
height: 150px;
width: 150px;
margin: auto;
grid-column: 2;
grid-row: 2;
background-color:#E0D6AF;
}
#submit:hover {
transform: scale(1.3);
}
.choice {
background-color: #E0D6AF;
border-radius: 50%;
height: 200px;
width: 200px;
margin: 10px auto;
transition: transform 0.2s;
transform: scale(1);
z-index: 10;
}
.choice > img:hover {
transform: scale(1.1);
}
#rock{
grid-column: 1;
grid-row:1;
}
#paper{
grid-column: 1;
grid-row:2;
}
#scissor{
grid-column: 1;
grid-row:3;
}
#humanScore > p {
padding-top: 80px;
text-align: center !important;
}
#humanScore {
grid-column: 2;
grid-row: 3;
}
#computerScore > p {
padding-top: 80px;
text-align: center !important;
}
#computerScore {
grid-column: 2;
grid-row: 1;
}
#result {
margin: auto;
width: 150px;
height: 150px;
border-radius: 50%;
grid-column: 3;
grid-row: 2;
}
#keyframes pulse{
0%{
transform: scale(0);
}
100%{
transform: scale(1);
}
}
.resultWin{
background-color:lightgreen;
transition: transform 0.2s;
transform: scale(1.3);
animation-name: pulse;
animation-duration: 1s;
animation-iteration-count: 1;
animation-fill-mode: both;
}
.resultLoss{
background-color: crimson;
transition: transform 0.2s;
transform: scale(1.3);
animation-name: pulse;
animation-duration: 1s;
animation-iteration-count: 1;
animation-fill-mode: both;
}
.resultTie{
background-color:goldenrod;
transition: transform 0.2s;
transform: scale(1.3);
animation-name: pulse;
animation-duration: 1s;
animation-iteration-count: 1;
animation-fill-mode: both;
}
.chosen { filter: brightness(70%) }
Full react file - needs a ton of refactoring so difficult to read.
import React from 'react';
import './Game.css'
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
picked: '',
score: {
player: 0,
computer: 0
},
previousPicks: {
rock: 0,
scissor: 0,
paper: 0
},
result: { result: "", player: "", computer: "" }
};
}
unmarkImage = () => {
if (this.state.picked !== "") {
document.querySelector(`#${this.state.picked}`).classList.remove("chosen")
}
}
onClickHandler = (event) => {
this.unmarkImage();
document.querySelector(`#${event.target.attributes.value.value}`).classList.add("chosen");
this.setState({ picked: event.target.attributes.value.value });
}
onSubmit = () => {
if (this.state.picked === "") {
alert("pick your weapon, before fighting")
return
}
const self = this;
fetch(`/api/play/${this.state.picked}`)
.then(function (res) {
res.text().then((function (text) {
self.setState({ result: JSON.parse('{' + text.replace(/(\w+):(\w+)/g, `"$1":"$2"`) + '}') })
self.updateScore(self.state.result.result);
self.updateResult();
self.unmarkImage();
self.updateComputerChoice();
self.updatePreviousPicks(self.state.picked)
self.setState({ picked: "" })
}))
})
}
updateScore = (result) => {
let scoreClone = { ...this.state.score }
if (result === "win") {
scoreClone.player++
this.setState({
score: scoreClone
})
} else if (result === "loss") {
scoreClone.computer++
this.setState({
score: scoreClone
})
}
}
updatePreviousPicks = (pick) => {
let previousPicksClone = { ...this.state.previousPicks }
if (pick === "rock") {
previousPicksClone.rock++;
this.setState({
previousPicks: previousPicksClone
})
} else if (pick === "scissor") {
previousPicksClone.scissor++;
this.setState({
previousPicks: previousPicksClone
})
} else {
previousPicksClone.paper++;
this.setState({
previousPicks: previousPicksClone
})
}
}
onReset = () => { //looks clumsy, but good performance
let computerDiv = document.querySelector("#computer")
while (computerDiv.firstChild) {
computerDiv.removeChild(computerDiv.firstChild);
}
}
updateResult = () => {
let result = document.querySelector("#result")
if (this.state.result.result === "win") {
result.classList.add("resultWin");
}
else if (this.state.result.result === "loss") {
result.classList.add("resultLoss");
} else {
result.classList.add("resultTie");
}
}
updateComputerChoice = () => {
let computerChoice = this.state.result.computer;
let result = document.querySelector("#result");
while (result.firstChild) {
result.removeChild(result.firstChild);
}
let answer = document.createElement("img");
let img;
if (computerChoice === "rock") {
img = document.getElementById("rock").src;
} else if (computerChoice === "scissor") {
img = document.getElementById("scissor").src;
} else {
img = document.getElementById("paper").src;
}
answer.src = img;
result.appendChild(answer);
}
render() {
return (
<div className="container">
<img id="rock" className="choice" value="rock" src="resources/rock.svg" alt="a rock" onClick={this.onClickHandler}></img>
<img id="paper" className="choice" value="paper" src="resources/paper.svg" alt="a piece of paper" onClick={this.onClickHandler}></img>
<img id="scissor" className="choice" value="scissor" src="resources/scissor.svg" alt="a scissor" onClick={this.onClickHandler}></img>
<button id="submit" className="waves-effect waves-light btn" onClick={this.onSubmit}>Fight the AI!</button>
<div id="humanScore">
<p>You: {this.state.score.player}</p>
</div>
<div id="computerScore">
<p>Computer: {this.state.score.computer}</p>
</div>
<div id="result" className="">
</div>
</div>
)
}
}
export default Game
To demonstrate #exaneta 's original suggestion, which I can't imagine would have any effect on a grid system, run the snippet below. If that's not what you are trying to accomplish, I'll delete this answer.
.choice {
background-color: #E0D6AF;
border-radius: 50%;
height: 200px;
width: 200px;
margin: 10px auto;
transition: transform 0.2s;
transform: scale(1);
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
}
.choice > img#paper{
width: 60%;
}
<div class="choice">
<img
id="paper"
value="paper"
src="http://www.jerrylow.com/demo/rps/paper.svg"
alt="a piece of paper"
/>
</div>

CSS Modules <style module> doesnt work

I have Laravel 5.4 project with Vue.js. I wont to use CSS Modules feature that provides by vue-loader. I have vue.js file with code:
<template lang="pug">
.LAYOUT
.SIDE-NAVBAR
.MAIN
</template>
<style module>
.LAYOUT{
height: 100%;
width: 100%;
border: 1px solid red;
}
</style>
<script>
export default {
methods:{
test(){
console.log(this.$style.LAYOUT)
}
},
mounted(){
this.test();
}
}
</script>
When I'm trying to see some information about "this.$style.LAYOUT" in console, it shows that the variable is undefined. May be I should do some settings? How to fix it?
When I'm trying to get value of "this.$style", it returns object:
It may be undefined because you not using that class.
Below is a working example.It also includes how to set dynamic css module class:
<template>
<div>
<button :class="[className1, className2, dynamicClass]" #click="showStyleObject">Click Me</button>
</div>
</template>
<script>
export default {
name: 'example',
props: {
'type-of-button': {
validator: function (value) {
return ['primary', 'secondary', 'default'].indexOf(value) !== -1
}
}
},
data() {
return {
className1: this.$style.button,
className2: this.$style.button2,
}
},
created() {
console.log(this.$style.button)
console.log(this.$style.button2)
},
computed: {
dynamicClass() {
return this.$style[this.typeOfButton]
}
},
methods: {
showStyleObject() {
console.log(this.$style)
}
},
}
</script>
<style module>
.button {
background: red;
}
.button2 {
padding: 8px 10px;
}
.primary {
padding: 8px 10px;
background: blue;
color: white;
border-radius: 10px;
}
.secondary {
padding: 8px 15px;
background: darkslategrey;
color: aliceblue;
border: none;
}
.default {
background: aliceblue;
}
</style>

Resources