Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(esl-random-text): create auxiliary esl-random-text component to generate dummy text #2055

Merged
merged 11 commits into from
Nov 24, 2023
Merged
5 changes: 5 additions & 0 deletions pages/src/localdev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import {
ESLRelatedTarget
} from '@exadel/esl/modules/all';

import {ESLRandomText} from '@exadel/esl/modules/esl-random-text/core';

import '@exadel/esl/modules/esl-media/providers/iframe-provider';
import '@exadel/esl/modules/esl-media/providers/html5/audio-provider';
import '@exadel/esl/modules/esl-media/providers/html5/video-provider';
Expand Down Expand Up @@ -73,6 +75,9 @@ ESLDemoBackLink.register();
ESLDemoBanner.register();
ESLDemoSwipeArea.register();

// Test Content
ESLRandomText.register('lorem-ipsum');

// Register ESL Components
ESLImage.register();
ESLMedia.register();
Expand Down
32 changes: 15 additions & 17 deletions pages/views/draft/accordion-regression.njk
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ name: Accordion (Regression)
tags: [draft]
icon: examples/accordion.svg
---
{% import 'lorem.njk' as lorem %}

<section class="row">
<div class="col-12">
<h2>Simple multiple accordion with at least 3 and simultaneously maximum open panels</h2>
Expand All @@ -21,7 +19,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -31,7 +29,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -41,7 +39,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -51,7 +49,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -61,7 +59,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -71,7 +69,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -93,7 +91,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -103,7 +101,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -113,7 +111,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand Down Expand Up @@ -141,7 +139,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -151,7 +149,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -161,7 +159,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand Down Expand Up @@ -189,7 +187,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -199,7 +197,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand All @@ -209,7 +207,7 @@ icon: examples/accordion.svg
</esl-trigger>
<esl-panel open class="esl-d-accordion-panel">
<div class="esl-d-accordion-body">
{{ lorem.paragraphs(1) }}
<lorem-ipsum paragraphs="1"></lorem-ipsum>
</div>
</esl-panel>
</div>
Expand Down
59 changes: 59 additions & 0 deletions src/modules/esl-random-text/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# [ESL](../../../) Random Text

Version: *1.0.0-beta*.

Authors: *Alexey Stsefanovich*.

<a name="intro"></a>

**ESLRandomText** is a custom tag and utility that allows to generate random text from a given set of words `DICTIONARY`.

### Getting Started:

1. Register ESLRandomText component
```js
import {ESLRandomText} from '@exadel/esl';
ESLRandomText.register();
```

2. (Optionally) provide a custom dictionary using `ESLRandomText.DICTIONARY` static property:
```js
ESLRandomText.DICTIONARY = ['word1', 'word2', 'word3'];
```

3. Add the `<esl-random-text>` custom tag and provide text limitations (with `paragraphs` and `wordsPerParagraph` attributes):
```html
<esl-random-text paragraphs="3"></esl-random-text>
```
```html
<esl-random-text paragraphs="1.5"></esl-random-text>
```
```html
<esl-random-text paragraphs="10" words-per-paragraph ="5"></esl-random-text>
```

### Attributes:

- `paragraphs` \[number] - number of paragraphs to generate (can be float)
- `wordsPerParagraphs` \[number] - number of words to generate per paragraph
- `shuffle` \[boolean] - choose words randomly from the dictionary (use words in `DICTIONARY` order otherwise)


### Static API:

- `ESLRandomText.DICTIONARY` - static property that contains a dictionary of words to generate random text from.
"Lorem ipsum" is used by default.

- `ESLRandomText.WORDS_PER_PARAGRAPH` - static property that contains a default number of words per paragraph.
100 is used by default.

- `ESLRandomText.WORDS_PER_SENTENCE` - static property that contains a default number of words per single sentence.
10 is used by default.

- `ESLRandomText.generateText(words, shuffle)` - static method that generates random text from the dictionary.
Returns a string with `words` number of words. If `shuffle` is `true` words are chosen randomly from the dictionary.
Otherwise, words are chosen in the dictionary order.

- `ESLRandomText.generateTextHTML(words, wordsPerParagraph, shuffle)` - static method that generates random text from the dictionary.
Returns an HTML string with `words` number of words and `wordsPerParagraph` number of words per paragraph.
If `shuffle` is `true` words are chosen randomly from the dictionary. Otherwise, words are chosen in the dictionary order.
2 changes: 2 additions & 0 deletions src/modules/esl-random-text/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './core/esl-random-text';
export type * from './core/esl-random-text.shape';
34 changes: 34 additions & 0 deletions src/modules/esl-random-text/core/esl-random-text.shape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type {ESLBaseElementShape} from '../../esl-base-element/core/esl-base-element.shape';
import type {ESLRandomText} from './esl-random-text';

export interface ESLRandomTextShape extends ESLBaseElementShape<ESLRandomText> {
/**
* Choose words randomly from {@link DICTIONARY} rather than sequentially
* @see ESLRandomText#shuffle
*/
shuffle: boolean;

/**
* Maximum number of paragraphs in generated text
* @see ESLRandomText#paragraphs
*/
paragraphs: number;

/**
* Maximum number words in paragraph
ala-n marked this conversation as resolved.
Show resolved Hide resolved
* @see ESLRandomText#wordsPerParagraph
*/
wordsPerParagraph: number;

/** No children allowed */
children: never | [];
}

declare global {
namespace JSX {
export interface IntrinsicElements {
/** {@link ESLRandomTextShape} custom tag */
'esl-random-text': ESLRandomTextShape;
}
}
}
130 changes: 130 additions & 0 deletions src/modules/esl-random-text/core/esl-random-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import {ESLBaseElement} from '../../esl-base-element/core';
import {attr, boolAttr} from '../../esl-utils/decorators';
import {capitalize} from '../../esl-utils/misc/format';

export class ESLRandomText extends ESLBaseElement {
public static override readonly is = 'esl-random-text';
public static readonly observedAttributes = [
'paragraphs',
'words-per-paragraph',
'shuffle'
];

/** Last used word index in dictionary */
protected static pointer: number = -1;
/** Words dictionary to use in random text generation. */
public static DICTIONARY: string[] = [
'lorem', 'ipsum', 'dolor', 'sit', 'amet',
'consectetur', 'adipiscing', 'elit', 'curabitur',
'ultrices', 'et', 'mi', 'suscipit', 'eget', 'vulputate', 'ante',
'proin', 'vel', 'pretium', 'enim', 'vivamus', 'venenatis', 'eu',
'urna', 'tempor', 'blandit', 'nullam', 'pellentesque', 'metus',
'rhoncus', 'mauris', 'mollis', 'neque', 'sed', 'tincidunt', 'tellus',
'nunc', 'ac', 'nulla', 'ut', 'purus', 'etiam', 'id', 'dui', 'justo',
'sapien', 'scelerisque', 'viverra', 'ligula', 'aenean', 'porta',
'condimentum', 'nibh', 'dictum', 'congue', 'odio', 'facilisis',
'finibus', 'mattis', 'vehicula', 'lacinia', 'risus', 'placerat',
'augue', 'fringilla', 'at', 'facilisi', 'arcu', 'diam', 'laoreet'
];

/** Number of words in sentence */
public static readonly WORDS_PER_SENTENCE = 10;
/** Number of words in paragraph */
public static readonly WORDS_PER_PARAGRAPH = 100;

/** Choose words randomly from {@link DICTIONARY} rather than sequentially */
@boolAttr() public shuffle: boolean;
/** Maximum number of paragraphs in generated text */
@attr({parser: parseFloat, defaultValue: 1}) public paragraphs: number;
/** Maximum number words in paragraph */
ala-n marked this conversation as resolved.
Show resolved Hide resolved
@attr({parser: parseInt, defaultValue: 100}) public wordsPerParagraph: number;

/** Redraws random text content */
public refresh(): void {
// Normalize values
if (isNaN(this.paragraphs)) this.paragraphs = 1;
if (isNaN(this.wordsPerParagraph)) this.wordsPerParagraph = 100;

const {paragraphs, wordsPerParagraph, shuffle} = this;
const words = Math.ceil(paragraphs * wordsPerParagraph);
this.style.display = 'contents';
this.innerHTML = ESLRandomText.generateTextHTML(words, wordsPerParagraph, shuffle);
}

protected override connectedCallback(): void {
super.connectedCallback();
this.refresh();
}
protected override disconnectedCallback(): void {
this.innerHTML = '';
this.style.display = '';
super.disconnectedCallback();
}
protected override attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
this.refresh();
}

/**
* Generates a dummy word.
* @param random - choose word randomly from {@link DICTIONARY} rather than sequentially
*/
protected static generateWord(random = false): string {
if (random) return this.DICTIONARY[Math.floor(Math.random() * this.DICTIONARY.length)];
this.pointer = (this.pointer + 1) % this.DICTIONARY.length;
return this.DICTIONARY[this.pointer];
}

/**
* Builds a dummy text
* @param words - number of words in text
* @param shuffle - shuffle words randomly
*/
protected static buildText(words: number, shuffle: boolean = false): string {
const sentences = [];
while (words > 0) {
const count = Math.min(this.WORDS_PER_SENTENCE, words);
const buffer = Array.apply(0, new Array(count));
const sentence = buffer.map(() => this.generateWord(shuffle)).join(' ');
sentences.push(capitalize(sentence) + '.');
words -= this.WORDS_PER_SENTENCE;
}
return sentences.join(' ');
}

/**
* Generates a dummy text.
* @param words - number of words in text
* @param shuffle - shuffle words randomly
*/
public static generateText(words: number, shuffle: boolean = false): string {
this.pointer = -1;
return this.buildText(words, shuffle);
}

/**
* Generates a dummy text.
* @param words - number of words in text
* @param wordsPerParagraph - number of words in paragraph
* @param shuffle - shuffle words randomly
*/
public static generateTextHTML(
words: number = this.WORDS_PER_PARAGRAPH,
wordsPerParagraph = Math.min(this.WORDS_PER_PARAGRAPH, words),
shuffle = false
): string {
this.pointer = -1;
const result = [];
while (words > 0) {
const text = this.buildText(Math.min(wordsPerParagraph, words), shuffle);
result.push(`<p>${text}</p>`);
words -= wordsPerParagraph;
}
return result.join('');
}
}

declare global {
export interface HTMLElementTagNameMap {
'esl-random-text': ESLRandomText;
}
}