浏览代码

Docs: Polished the autosave guide. [skip ci]

Piotrek Koszuliński 7 年之前
父节点
当前提交
3617c8dceb

+ 22 - 30
docs/_snippets/builds/saving-data/autosave.html

@@ -2,29 +2,27 @@
 	<p>Type some text to test the <a href="#autosave-feature">autosave</a> feature.</p>
 </div>
 
-<div class="snippet-autosave-header">
-	<div class="snippet-autosave-status">
-		<div class="snippet-autosave-status_label">Status:</div>
-		<div class="snippet-autosave-status_spinner">
-			<span class="snippet-autosave-status_spinner-label"></span>
-			<span class="snippet-autosave-status_spinner-loader"></span>
+<div id="snippet-autosave-header">
+	<div id="snippet-autosave-status">
+		<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 class="snippet-autosave-server">
-		<div class="snippet-autosave-server_label">HTTP server lag (ms):</div>
+	<div id="snippet-autosave-server">
+		<div id="snippet-autosave-server_label">HTTP server lag (ms):</div>
 		<input id="snippet-autosave-lag" type="number" value="500" step="100" min="0" max="9000">
 	</div>
 </div>
 
 <p>Server data:</p>
 
-<pre>
-	<code id="snippet-autosave-console">Type some text to test the &#x3C;a href=&#x22;#autosave-feature&#x22;&#x3E;autosave&#x3C;/a&#x3E; feature.</code>
-</pre>
+<pre><code id="snippet-autosave-console">Type some text to test the &#x3C;a href=&#x22;#autosave-feature&#x22;&#x3E;autosave&#x3C;/a&#x3E; feature.</code></pre>
 
 <style>
-	.snippet-autosave-header {
+	#snippet-autosave-header {
 		display: flex;
 		justify-content: space-between;
 		align-items: center;
@@ -39,16 +37,16 @@
 		border-top-right-radius: 0;
 	}
 
-	.snippet-autosave-status_spinner{
+	#snippet-autosave-status_spinner{
 		display: flex;
 		align-items: center;
 		position: relative;
 	}
-	.snippet-autosave-status_spinner-label {
+	#snippet-autosave-status_spinner-label {
 		position: relative;
 	}
 
-	.snippet-autosave-status_spinner-label::after {
+	#snippet-autosave-status_spinner-label::after {
 		content: 'Saved!';
 		color: green;
 		display: inline-block;
@@ -56,12 +54,12 @@
 	}
 
 	/* During "Saving" display spinner and change content of label. */
-	.snippet-autosave-status.busy .snippet-autosave-status_spinner-label::after  {
+	#snippet-autosave-status.busy #snippet-autosave-status_spinner-label::after  {
 		content: 'Saving...';
 		color: red;
 	}
 
-	.snippet-autosave-status.busy .snippet-autosave-status_spinner-loader {
+	#snippet-autosave-status.busy #snippet-autosave-status_spinner-loader {
 		display: block;
 		width: 16px;
 		height: 16px;
@@ -71,14 +69,14 @@
 		animation: autosave-status-spinner 1s linear infinite;
 	}
 
-	.snippet-autosave-status,
-	.snippet-autosave-server {
+	#snippet-autosave-status,
+	#snippet-autosave-server {
 		display: flex;
 		align-items: center;
 	}
 
-	.snippet-autosave-server_label,
-	.snippet-autosave-status_label {
+	#snippet-autosave-server_label,
+	#snippet-autosave-status_label {
 		font-weight: bold;
 		margin-right: var(--ck-spacing-medium);
 	}
@@ -93,24 +91,18 @@
 	}
 
 	#snippet-autosave-console {
-		/* Lets wrap content. */
 		max-height: 300px;
 		overflow: auto;
 		white-space: normal;
 		background: #2b2c26;
-		transition: 300ms;
+		transition: background-color 500ms;
 	}
 
-	#snippet-autosave-console.received {
-		animation: autosave-received 1s ease 1;
+	#snippet-autosave-console.updated {
+		background: green;
 	}
 
 	@keyframes autosave-status-spinner {
 		to { transform: rotate( 360deg ); }
 	}
-
-	@keyframes autosave-received {
-		from { background: green; }
-		to { background: #2b2c26; }
-	}
 </style>

+ 13 - 6
docs/_snippets/builds/saving-data/autosave.js

@@ -38,7 +38,7 @@ function saveData( data ) {
 	return new Promise( resolve => {
 		// Fake HTTP server's lag.
 		setTimeout( () => {
-			log( data );
+			updateServerDataConsole( data );
 
 			resolve();
 		}, HTTP_SERVER_LAG );
@@ -47,22 +47,29 @@ function saveData( data ) {
 
 function displayStatus( editor ) {
 	const pendingActions = editor.plugins.get( 'PendingActions' );
-	const statusIndicator = document.querySelector( '.snippet-autosave-status' );
-	const console = document.querySelector( '#snippet-autosave-console' );
+	const statusIndicator = document.querySelector( '#snippet-autosave-status' );
 
 	pendingActions.on( 'change:hasAny', ( evt, propertyName, newValue ) => {
 		if ( newValue ) {
 			statusIndicator.classList.add( 'busy' );
-			console.classList.remove( 'received' );
 		} else {
 			statusIndicator.classList.remove( 'busy' );
-			console.classList.add( 'received' );
 		}
 	} );
 }
 
-function log( msg ) {
+let consoleUpdates = 0;
+
+function updateServerDataConsole( msg ) {
 	const console = document.querySelector( '#snippet-autosave-console' );
 
+	consoleUpdates++;
+	console.classList.add( 'updated' );
 	console.textContent = msg;
+
+	setTimeout( () => {
+		if ( --consoleUpdates == 0 ) {
+			console.classList.remove( 'updated' );
+		}
+	}, 500 );
 }

+ 28 - 36
docs/_snippets/builds/saving-data/manualsave.html

@@ -1,26 +1,24 @@
-<div id="snippet-manual">
+<div id="snippet-manualsave">
 	<p>Change the content of this editor, then save it on the server.</p>
 </div>
 
-<div class="snippet-manual-save-header">
-	<div class="snippet-manual-save-server">
-		<div class="snippet-manual-save-server_label">HTTP server lag (ms):</div>
-		<input id="snippet-manual-lag" type="number" value="500" step="100" min="0" max="9000">
+<div id="snippet-manualsave-header">
+	<div id="snippet-manualsave-server">
+		<div id="snippet-manualsave-server_label">HTTP server lag (ms):</div>
+		<input id="snippet-manualsave-lag" type="number" value="500" step="100" min="0" max="9000">
 	</div>
-	<div class="snippet-manual-save-container">
-		<input id="snippet-manual-save" type="submit" value="Save">
-		<span class="snippet-manual-save-spinner"></span>
+	<div id="snippet-manualsave-container">
+		<span id="snippet-manualsave-spinner"></span>
+		<input id="snippet-manualsave-save" type="submit" value="Save">
 	</div>
 </div>
 
 <p>Server data:</p>
 
-<pre>
-	<code id="snippet-manual-save-console">&#x3C;p&#x3E;Change the content of this editor, then save it on the server.&#x3C;/p&#x3E;</code>
-</pre>
+<pre><code id="snippet-manualsave-console">&#x3C;p&#x3E;Change the content of this editor, then save it on the server.&#x3C;/p&#x3E;</code></pre>
 
 <style>
-	.snippet-manual-save-header {
+	#snippet-manualsave-header {
 		display: flex;
 		justify-content: space-between;
 		align-items: center;
@@ -35,14 +33,14 @@
 		border-top-right-radius: 0;
 	}
 
-	.snippet-manual-save-server,
-	.snippet-manual-save-submit {
+	#snippet-manualsave-server,
+	#snippet-manualsave-submit {
 		display: flex;
 		align-items: center;
 	}
 
-	.snippet-manual-save-server_label,
-	.snippet-manual-save-status_label {
+	#snippet-manualsave-server_label,
+	#snippet-manualsave-status_label {
 		font-weight: bold;
 		margin-right: var(--ck-spacing-medium);
 	}
@@ -52,11 +50,11 @@
 		border-bottom-left-radius: 0;
 	}
 
-	#snippet-manual-save-lag {
+	#snippet-manualsave-lag {
 		padding: 4px;
 	}
 
-	#snippet-manual-save {
+	#snippet-manualsave-save {
 		color: #fff;
 		background: hsl( 88, 73%, 39% );
 		opacity: 0.5;
@@ -70,45 +68,44 @@
 		box-shadow: 0 2px 0 rgb(68, 117, 10);
 	}
 
-	#snippet-manual-save:hover {
+	#snippet-manualsave-save:hover {
 		background: hsl( 88, 73%, 42% );
 	}
 
-	#snippet-manual-save:active,
-	#snippet-manual-save:focus {
+	#snippet-manualsave-save:active,
+	#snippet-manualsave-save:focus {
 		box-shadow: 0 1px 0 rgb(68, 117, 10);
 	}
 
-	.snippet-manual-save-container.active #snippet-manual-save {
+	#snippet-manualsave-container.active #snippet-manualsave-save {
 		cursor: pointer;
 		opacity: 1;
 	}
 
-	.snippet-manual-save-container.saving #snippet-manual-save {
+	#snippet-manualsave-container.saving #snippet-manualsave-save {
 		background: hsl( 88, 73%, 34% );
 	}
 
-	#snippet-manual-save-console {
-		/* Lets wrap content. */
+	#snippet-manualsave-console {
 		max-height: 300px;
 		overflow: auto;
 		white-space: normal;
 		background: #2b2c26;
-		transition: 300ms;
+		transition: background-color 500ms;
 	}
 
-	#snippet-manual-save-console.received {
-		animation: manualsave-received 1s ease 1;
+	#snippet-manualsave-console.updated {
+		background: green;
 	}
 
-	.snippet-manual-save-spinner {
+	#snippet-manualsave-spinner {
 		display: none;
 	}
 
-	.snippet-manual-save-container.saving .snippet-manual-save-spinner {
+	#snippet-manualsave-container.saving #snippet-manualsave-spinner {
 		display: inline-block;
 		vertical-align: middle;
-		margin-left: var(--ck-spacing-medium);
+		margin-right: var(--ck-spacing-medium);
 		width: 16px;
 		height: 16px;
 		border-radius: 50%;
@@ -117,11 +114,6 @@
 		animation: manualsave-spinner 1s linear infinite;
 	}
 
-	@keyframes manualsave-received {
-		from { background: green; }
-		to { background: #2b2c26; }
-	}
-
 	@keyframes manualsave-spinner {
 		to { transform: rotate( 360deg ); }
 	}

+ 17 - 10
docs/_snippets/builds/saving-data/manualsave.js

@@ -10,12 +10,12 @@ import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud
 let HTTP_SERVER_LAG = 500;
 let isDirty = false;
 
-document.querySelector( '#snippet-manual-lag' ).addEventListener( 'change', evt => {
+document.querySelector( '#snippet-manualsave-lag' ).addEventListener( 'change', evt => {
 	HTTP_SERVER_LAG = evt.target.value;
 } );
 
 ClassicEditor
-	.create( document.querySelector( '#snippet-manual' ), {
+	.create( document.querySelector( '#snippet-manualsave' ), {
 		cloudServices: CS_CONFIG,
 		toolbar: {
 			viewportTopOffset: 60
@@ -34,7 +34,7 @@ ClassicEditor
 
 // Handle clicking the "Save" button.
 function handleSaveButton( editor ) {
-	const saveButton = document.querySelector( '#snippet-manual-save' );
+	const saveButton = document.querySelector( '#snippet-manualsave-save' );
 	const pendingActions = editor.plugins.get( 'PendingActions' );
 
 	saveButton.addEventListener( 'click', evt => {
@@ -45,7 +45,7 @@ function handleSaveButton( editor ) {
 
 		// Fake HTTP server's lag.
 		setTimeout( () => {
-			log( data );
+			updateServerDataConsole( data );
 
 			pendingActions.remove( action );
 
@@ -80,8 +80,7 @@ function handleBeforeunload( editor ) {
 }
 
 function updateStatus( editor ) {
-	const buttonContainer = document.querySelector( '.snippet-manual-save-container' );
-	const console = document.querySelector( '#snippet-manual-save-console' );
+	const buttonContainer = document.querySelector( '#snippet-manualsave-container' );
 
 	if ( isDirty ) {
 		buttonContainer.classList.add( 'active' );
@@ -91,15 +90,23 @@ function updateStatus( editor ) {
 
 	if ( editor.plugins.get( 'PendingActions' ).hasAny ) {
 		buttonContainer.classList.add( 'saving' );
-		console.classList.remove( 'received' );
 	} else {
 		buttonContainer.classList.remove( 'saving' );
 	}
 }
 
-function log( msg ) {
-	const console = document.querySelector( '#snippet-manual-save-console' );
+let consoleUpdates = 0;
 
-	console.classList.add( 'received' );
+function updateServerDataConsole( msg ) {
+	const console = document.querySelector( '#snippet-manualsave-console' );
+
+	consoleUpdates++;
+	console.classList.add( 'updated' );
 	console.textContent = msg;
+
+	setTimeout( () => {
+		if ( --consoleUpdates == 0 ) {
+			console.classList.remove( 'updated' );
+		}
+	}, 500 );
 }

+ 34 - 12
docs/builds/guides/integration/saving-data.md

@@ -163,6 +163,12 @@ This demo shows a simple integration of the editor with a fake HTTP server (whic
 ```js
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
+		plugins: [
+			Autosave,
+
+			// ... other plugins
+		],
+
 		autosave: {
 			save( editor ) {
 				return saveData( editor.getData() );
@@ -178,18 +184,18 @@ ClassicEditor
 		console.error( err.stack );
 	} );
 
-// Save the data to a fake HTTP server.
+// Save the data to a fake HTTP server (emulated here with a setTimeout()).
 function saveData( data ) {
 	return new Promise( resolve => {
-
 		setTimeout( () => {
-			console.log( data );
+			console.log( 'Saved', data );
 
 			resolve();
 		}, HTTP_SERVER_LAG );
 	} );
 }
 
+// Update the "Status: Saving..." info.
 function displayStatus( editor ) {
 	const pendingActions = editor.plugins.get( 'PendingActions' );
 	const statusIndicator = document.querySelector( '#editor-status' );
@@ -229,10 +235,18 @@ To handle the former situation you can listen to the native [`window#beforeunloa
 The example below shows how all these mechanisms can be used together to enable or disable a "Save" button and block the user from leaving the page without saving the data.
 
 ```js
+import PendingActions from '@ckeditor/ckeditor5-core/src/pendingactions';
+
 let isDirty = false;
 
 ClassicEditor
-	.create( document.querySelector( '#editor' ) )
+	.create( document.querySelector( '#editor' ), {
+		plugins: [
+			PendingActions,
+
+			// ... other plugins
+		]
+	} )
 	.then( editor => {
 		window.editor = editor;
 
@@ -244,21 +258,25 @@ ClassicEditor
 		console.error( err.stack );
 	} );
 
-// Handle clicking the "Save" button.
+// Handle clicking the "Save" button by sending the data to a
+// fake HTTP server (emulated here with setTimeout()).
 function handleSaveButton( editor ) {
 	const saveButton = document.querySelector( '#save' );
 	const pendingActions = editor.plugins.get( 'PendingActions' );
 
 	saveButton.addEventListener( 'click', evt => {
 		const data = editor.getData();
+
+		// Register the action of saving the data as a "pending action".
+		// All asynchronous actions related to the editor are tracked like this,
+		// so later on you only need to check `pendingActions.hasAny` to check
+		// whether editor is busy or not.
 		const action = pendingActions.add( 'Saving changes' );
 
 		evt.preventDefault();
 
-		// Fake HTTP server's lag.
+		// Save the data to a fake HTTP server.
 		setTimeout( () => {
-			log( data );
-
 			pendingActions.remove( action );
 
 			// Reset isDirty only if data didn't change in the meantime.
@@ -271,10 +289,10 @@ function handleSaveButton( editor ) {
 	} );
 }
 
+// Listen to new changes (to enable the "Save" button) and to
+// pending actions (to show the spinner animation when the editor is busy).
 function handleStatusChanges( editor ) {
-	const pendingActions = editor.plugins.get( 'PendingActions' );
-
-	pendingActions.on( 'change:hasAny', () => updateStatus( editor ) );
+	editor.plugins.get( 'PendingActions' ).on( 'change:hasAny', () => updateStatus( editor ) );
 
 	editor.model.document.on( 'change:data', () => {
 		isDirty = true;
@@ -283,12 +301,14 @@ function handleStatusChanges( editor ) {
 	} );
 }
 
+// If the user tries to leave the page before the data is saved, ask
+// they whether they are sure.
 function handleBeforeunload( editor ) {
 	const pendingActions = editor.plugins.get( 'PendingActions' );
 
 	window.addEventListener( 'beforeunload', evt => {
 		if ( pendingActions.hasAny ) {
-			evt.returnValue = pendingActions.first.message;
+			evt.preventDefault();
 		}
 	} );
 }
@@ -296,12 +316,14 @@ function handleBeforeunload( editor ) {
 function updateStatus( editor ) {
 	const saveButton = document.querySelector( '#save' );
 
+	// Disables the "Save" button when the data on the server is up to date.
 	if ( isDirty ) {
 		saveButton.classList.add( 'active' );
 	} else {
 		saveButton.classList.remove( 'active' );
 	}
 
+	// Shows the spinner animation.
 	if ( editor.plugins.get( 'PendingActions' ).hasAny ) {
 		saveButton.classList.add( 'saving' );
 	} else {

+ 1 - 1
docs/builds/guides/quick-start.md

@@ -33,7 +33,7 @@ Load the classic editor build (here [CDN](https://cdn.ckeditor.com/) location is
 
 Call the {@link module:editor-classic/classiceditor~ClassicEditor#create `ClassicEditor.create()`} method.
 
-```js
+```html
 <script>
 	ClassicEditor
 		.create( document.querySelector( '#editor' ) )