Validate saved data (#591)

* Specify submodule branch for test

* Change branch for testing convenience

Just run: git submodule update --remote

* Added checklist submodule for test

* Attempt to validate data on save

* Rewrite promise.then to async/await

* Move validate logic to saver

* Remove extra space

* Fix tabs

* Don't need async/await here

* Remove submodule

* Improve logging, remove empty blocks from data array

* Remove warning

* Loop over blocks only once

* Make validate non-async

* Get rid of await Promise.all

* Make validate async

* Call plugin's validate method with await

* Add docs

* Update docs

* Make separate function for tools validation

* Rename method

* Add data types interfaces

* Improve logging

* Desctructure extraction object

* Remove useless argument

* Update README and changelog

* Make separate changelog for version

* Increase version

* Bump version

* Keep logs at their places

* Fix logs order

* Pull submodules

* Improve logs grouping

* log styles improved

* Describe allExtractedData type

* Improve JSDoc
This commit is contained in:
Polina Shneider 2019-01-12 19:39:43 +03:00 committed by GitHub
parent 208f8e15ab
commit fc3e146764
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 29 deletions

12
dist/codex-editor.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,9 @@
# Changelog
### 2.7.28
- `New` [Tools Validation](https://github.com/codex-team/codex.editor/blob/master/docs/tools.md#validate-optional) is added.
### 2.2.27
- `New` *Mobile view* — Editor now adopted for mobile devices

View file

@ -39,7 +39,9 @@ Method that returns Tool's element {HTMLElement} that will be placed into Editor
Process Tool's element created by `render()` function in DOM and return Block's data.
### validate() _optional_
### validate(data: BlockToolData): boolean|Promise\<boolean\> _optional_
Allows to check correctness of Tool's data. If data didn't pass the validation it won't be saved. Receives Tool's `data` as input param and returns `boolean` result of validation.
### merge() _optional_

View file

@ -1,6 +1,6 @@
{
"name": "codex.editor",
"version": "2.7.27",
"version": "2.7.28",
"description": "CodeX Editor. Native JS, based on API and Open Source",
"main": "dist/codex-editor.js",
"types": "./types/index.d.ts",

View file

@ -9,6 +9,7 @@ import {
ToolConfig,
} from '../../types';
import {SavedData} from '../types-internal/block-data';
import $ from './dom';
import _ from './utils';
@ -369,7 +370,7 @@ export default class Block {
* Groups Tool's save processing time
* @return {Object}
*/
public async save(): Promise<void|{tool: string, data: BlockToolData, time: number}> {
public async save(): Promise<void|SavedData> {
const extractedBlock = await this.tool.save(this.pluginsContent as HTMLElement);
/**
@ -398,23 +399,19 @@ export default class Block {
* Uses Tool's validation method to check the correctness of output data
* Tool's validation method is optional
*
* @description Method also can return data if it passed the validation
* @description Method returns true|false whether data passed the validation or not
*
* @param {Object} data
* @returns {Boolean|Object} valid
* @param {BlockToolData} data
* @returns {Promise<boolean>} valid
*/
public validateData(data: BlockToolData): BlockToolData|false {
public async validate(data: BlockToolData): Promise<boolean> {
let isValid = true;
if (this.tool.validate instanceof Function) {
isValid = this.tool.validate(data);
isValid = await this.tool.validate(data);
}
if (!isValid) {
return false;
}
return data;
return isValid;
}
/**

View file

@ -7,7 +7,9 @@
*/
import Module from '../__module';
import {OutputData} from '../../../types';
import {ValidatedData} from '../../types-internal/block-data';
import Block from '../block';
import _ from '../utils';
declare const VERSION: string;
@ -34,7 +36,7 @@ export default class Saver extends Module {
ModificationsObserver.disable();
blocks.forEach((block: Block) => {
chainData.push(block.save());
chainData.push(this.getSavedData(block));
});
const extractedData = await Promise.all(chainData);
@ -45,9 +47,21 @@ export default class Saver extends Module {
return this.makeOutput(sanitizedData);
}
/**
* Saves and validates
* @param {Block} block - Editor's Tool
* @return {ValidatedData} - Tool's validated data
*/
private async getSavedData(block: Block): Promise<ValidatedData> {
const blockData = await block.save();
const isValid = blockData && await block.validate(blockData.data);
return {...blockData, isValid};
}
/**
* Creates output object with saved data, time and version of editor
* @param {Object} allExtractedData
* @param {ValidatedData} allExtractedData
* @return {OutputData}
*/
private makeOutput(allExtractedData): OutputData {
@ -56,20 +70,33 @@ export default class Saver extends Module {
console.groupCollapsed('[CodexEditor saving]:');
allExtractedData.forEach((extraction) => {
/** Group process info */
console.log(`«${extraction.tool}» saving info`, extraction);
totalTime += extraction.time;
allExtractedData.forEach(({tool, data, time, isValid}) => {
totalTime += time;
/**
* Capitalize Tool name
*/
console.group(`${tool.charAt(0).toUpperCase() + tool.slice(1)}`);
if (isValid) {
/** Group process info */
console.log(data);
console.groupEnd();
} else {
console.log(`Block «${tool}» skipped because saved data is invalid`);
console.groupEnd();
return;
}
/** If it was stub Block, get original data */
if (extraction.tool === this.Editor.Tools.stubTool) {
blocks.push(extraction.data);
if (tool === this.Editor.Tools.stubTool) {
blocks.push(data);
return;
}
blocks.push({
type: extraction.tool,
data: extraction.data,
type: tool,
data,
});
});

20
src/types-internal/block-data.d.ts vendored Normal file
View file

@ -0,0 +1,20 @@
import {BlockToolData} from '../../types/tools';
/**
* Tool's saved data
*/
export interface SavedData {
tool: string;
data: BlockToolData;
time: number;
}
/**
* Tool's data after validation
*/
export interface ValidatedData {
tool?: string;
data?: BlockToolData;
time?: number;
isValid: boolean;
}