MMOframework
Pourquoi l'IA Playground Bibliothèques Documentation Rechercher Agence
FR EN
Index

PageEditor

MMO.editor · 1 symbole · générée le 27 Oct 2026

class

PageEditor

PageEditor.js:29

The backoffice of the pages built from sections (mmo.editor's MMO\editor\cms): the pages, and the one being edited -- its fields, its sections as forms made from their types' schemas, a live preview, its publication and its history. Everything goes through the api (admin/pages…, `MMO.editor.config). <mmo-page-editor>` is its element; it can be built on any container.

class MMO.editor.PageEditor
Espace de noms
MMO.editor
What is shown follows the display level (`MMO.modes`, mmo.client): - `simple`: the main fields of the sections (those whose schema has no `level`), the form and the preview; - `standard`: every field but the `expert` ones (SEO, alt texts, anchors...), the history; - `expert`: every field, and the preview edits the page in place -- a double click on a text edits it with `<mmo-editor inline>`, a toolbar on each section moves, copies, removes it or adds one after it. A page may be in several languages (`languages`, the default one first): the bar's language shows it in one of them, whose texts the form and the preview then change -- the rest (the sections, their order, images, links, choices) is the default language's, the same in every language. A text not translated shows the default language's. The « Languages » drawer sets them, and lists what each one has not translated yet, each a link to its field. (`MMO\editor\cms\Translations` has the same rules, `translatable`.) Its node holds everything, in the light dom: its `<mmo-editor>` fields need the page's selection. It sends `api` events (`detail: {method, url, status, reason}`), `open` (`detail: page`) and `saved`.
const editor = new MMO.editor.PageEditor(document.getElementById('backoffice'), {page: 3}); editor.node.addEventListener('api', (e) => console.log(e.detail.method, e.detail.url, e.detail.status));

Index

HISTORY_PAUSE statichow long a pause ends a group of changes: typing a sentence is one step to undo, as in <mmo-editor>
HISTORY_SIZE staticthe steps kept
LANGUAGES staticthe languages offered when one is added (any other code can be typed)
LANGUAGE_CODE statica language's tag (RFC 5646), as the server takes it: mmo.core's I18n::LANGUAGE_REGEX, which MMO\editor\cms\Translations::Code() checks with -- change both together
constructor(node, options)
Level() static
EdmsUploadUrl(labels) static
destroy()The editor is gone: what it listens to outside of its node goes with it
h(tag, attrs, children)
$(name)
t(text, context)
build()[internal] The editor's own nodes: a bar (the page, its state, its actions, the level), the work -- the sections' form and the preview; at the expert level the preview alone, over the whole window …
openDrawer(panel, id)Open the drawer on $panel: page (the page's settings), new (a new page), section (the settings of the section $id), add (a section to add, after $id), languages (the page's, and what they…
closeDrawer()
renderSectionPanel(id)[internal] The drawer shows the settings of the section $id: @return {boolean} false when there is none
renderAddPanel(after)[internal] The types of section, to add one after the section $after (at the end without it)
levelSwitch()[internal] @return {HTMLElement} the levels: the display modes', which reload the page, or the editor's own
setLevel(level)Show $level (without the display modes: the editor's own)
Rank(level) static
confirm(title, text)
notify(text)
tourId()
registerTour()Give MMO.guide (mmo.client) the guided tour of the level shown: the bar's ? offers it, and it starts by itself the first time the user meets that level.
tour()
call(method, path, body, {token = this.token, raw = false, retry = true}) async
emit(name, detail)
start() async[internal] The types of section, the pages, then the page to open
loadPages() async
pill(page)
open(id, force) asyncOpen the page $id: its unsaved changes are the user's to leave
setPage(page, history)
renderStatus()
changed(preview)The draft changed: the history records it, the preview follows, unless the change came from it (the expert level edits it in place)
snapshot()
record()[internal] A change: the state before it goes on the undo stack -- once for a group of changes made without a pause -- and what was undone can no longer be redone
flushHistory()[internal] End the group of changes running: the draft as it is now is the history's state
undo()Undo the last change of the draft (a group of changes made without a pause)
redo()Redo the last change undone
applyState(state)[internal] Put the draft back as $state says: the form, the drawer and the preview follow
updateHistory()[internal] The undo and redo buttons: enabled when there is something to undo, to redo
historyKey(event)[internal] The history's keys: Mod+Z undoes, Mod+Shift+Z and Ctrl+Y redo -- but in a field (an input, a text being edited: <mmo-editor> takes the keys it answers, defaultPrevented), which undoe…
save() async
publish() async
unpublish() async
remove() async
create(form) asyncMake a page from the form of the side
loadRevisions() async
CanCompare() static
compare(revision)Show what changed between $revision and the draft, as json, side by side, in a dialog: the application's side panel is too narrow for two versions, and under the editor's drawer.
rollback(number) async
LanguageCode(code) static
languageName(code)
translatable(field, key, parent)
filled(value)
merge(field, base, translation, kind)
extract(field, value, base, kind)
untranslated(field, base, translation, kind, path, labels, found)[internal] The texts of $base (a field's value in the default language) that $translation does not translate
translationOf(draft, language)
draft()
extractShown()[internal] @return {?Object} the translation of the language shown: what its texts say that the default language's do not
showLanguage(draft)[internal] Put $draft (draft) in the form, in the language shown: its texts translated, the default language's where they are not
setLanguage(language)Show the page in $language (one of its languages; null or the default one: the default one)
baseValue(path)
renderLanguages()[internal] The bar's language, the notice of the language shown, the drawer's languages when it shows them
renderLanguagesPanel()[internal] The drawer's languages: the default one, the others -- each with what it does not translate yet, a link to each field -- and adding one
valueAt(draft, path)
excerpt(value, length)
addLanguage(code, defaultLanguage)Add the language $code to the page ($defaultLanguage its default one, when it had none), and show it
removeLanguage(code) asyncTake $code out of the page's languages: its translation goes with it (it can be undone)
setDefaultLanguage(code)The page's texts are in $code: what its default language is called (nothing is translated)
goToField(language, path)Open the field $path (the form's data-path) in $language, to translate it
visible(field)
defaults(schema)
translateExample(value, schema)
newSection(type)
indexOf(id)
addSection(type, after)Add a section of $type, after the section $after (at the end without it)
moveSection(i, to)
copySection(i)
deleteSection(i)
fieldInput(field, obj, key, path)
imageInput(field, obj, key, path)[internal] @return {Array<HTMLElement>} an image: its address, a file sent to mmo.edms, its description
listInput(field, obj, key, path)[internal] @return {HTMLElement} a list of items: each its fields, moved, removed, added
renderPageFields()
renderSections()
sectionCard(section, i, alone)
showErrors(errors)Show what the api says is wrong: in a list, and next to each field (the closest one the form has)
preview(version, label)Render $version (the draft by default) in the preview, a moment after the last change
showPreview(html, expert)[internal] $html in the preview: its addresses resolved from this page, its sections clickable
hookPreview(scroll, expert, tries)[internal] Once the preview's document is parsed (its load may never come: a request of the page staying open): a click on a section opens its form; at the expert level, the edits in place go int…
setFromPreview(path, html, region)Write what the expert level edited in place into the draft
sectionTools(doc)[internal] The toolbar of the section under the pointer, in the preview: move, copy, remove, add one after it
select(id, scroll)Select the section $id: framed in the preview, its form opened
resize(button, width)The preview's width: a desktop's, a tablet's, a phone's

Constantes4

HISTORY_PAUSE

staticPageEditor.js:575

how long a pause ends a group of changes: typing a sentence is one step to undo, as in <mmo-editor>

static HISTORY_PAUSE = 600;

LANGUAGES

staticPageEditor.js:793

the languages offered when one is added (any other code can be typed)

static LANGUAGES = ['fr', 'en', 'de', 'es', 'it', 'pt', 'nl', 'ca', 'eu', 'br', 'oc', 'co', 'ar', 'zh', 'ja', 'ko', 'ru', 'uk', 'pl', 'cs', 'ro', 'el', 'tr', 'sv', 'da', 'no', 'fi', 'he', 'hi'];

LANGUAGE_CODE

staticPageEditor.js:798

a language's tag (RFC 5646), as the server takes it: mmo.core's I18n::LANGUAGE_REGEX, which MMO\editor\cms\Translations::Code() checks with -- change both together

static LANGUAGE_CODE = new RegExp('^([a-z]{2,3}(-[a-z]{3}(-[a-z]{3}){0,2})?|[a-z]{4}|[a-z]{5,8})(-[a-z]{4})?(-([a-z]{2}|[0-9]{3}))?' + '(-(([a-z0-9]{5,8}|[0-9][a-z0-9]{3})(-([a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*))?' + '(-([a-wy-z0-9]-[a-z0-9]{2,8}(-[a-z0-9]{2,8})*(-[a-wy-z0-9]-[a-z0-9]{2,8}(-[a-z0-9]{2,8})*)*))?(-(x(-[a-z0-9]{1,8})+))?$');

Méthodes90

constructor(node, options)

PageEditor.js:42
constructor(node, options = {})
nodeHTMLElement- where it is built
options = {}Object- pages {string} the url of admin/pages.json (MMO.editor.config.pages) - sections {string} the url of admin/sections.json (MMO.editor.config.sections) - token {string} the session's CSRF token (MMO.editor.config.token) - page {?(string|number)} the page to open; none: the first one - level {?string} simple, standard or expert; none: MMO.modes' - uploadUrl {?string} where the images go; none: mmo.edms' one-request upload, when the page has it - uploadLabels {string} the edms labels of the images ("#pages": the user's own tag) - list {boolean} false to show one page only, without the list of the pages

Level()

staticPageEditor.js:93
static Level()
retournestringthe level the display modes show: simple, standard or expert -- standard when the application offers no such level

EdmsUploadUrl(labels)

staticPageEditor.js:102
static EdmsUploadUrl(labels = '"#pages"')
labels = '"#pages"'
retourne?stringmmo.edms' one-request upload (edms/files.json), when the page has edms, for $labels

destroy()

PageEditor.js:111

The editor is gone: what it listens to outside of its node goes with it

destroy()

h(tag, attrs, children)

PageEditor.js:125
h(tag, attrs = {}, ...children)
tagstring
attrs = {}Object- on… are listeners, value is the property; null, undefined and false are left out
...children...*- strings are text, never html
retourneHTMLElement

t(text, context)

PageEditor.js:146
t(text, context = null)
textstring- in english, translated by MMO.i18n
context = null?Object- what replaces its {name}s
retournestring

build()

PageEditor.js:156

[internal] The editor's own nodes: a bar (the page, its state, its actions, the level), the work -- the sections' form and the preview; at the expert level the preview alone, over the whole window -- and a drawer, opened on demand: the page's settings, a new page, a section's settings, the history

build()

openDrawer(panel, id)

PageEditor.js:237

Open the drawer on $panel: page (the page's settings), new (a new page), section (the settings of the section $id), add (a section to add, after $id), languages (the page's, and what they do not translate), history

openDrawer(panel, id = null)
panel
id = null

renderSectionPanel(id)

PageEditor.js:257

[internal] The drawer shows the settings of the section $id: @return {boolean} false when there is none

renderSectionPanel(id)
id

renderAddPanel(after)

PageEditor.js:265

[internal] The types of section, to add one after the section $after (at the end without it)

renderAddPanel(after = null)
after = null

levelSwitch()

PageEditor.js:273

[internal] @return {HTMLElement} the levels: the display modes', which reload the page, or the editor's own

levelSwitch()

setLevel(level)

PageEditor.js:293

Show $level (without the display modes: the editor's own)

setLevel(level)
level

tourId()

PageEditor.js:319
tourId()
retournestringthe id of the guided tour of the level shown (guides/{id} in the user's config)

registerTour()

PageEditor.js:327

Give MMO.guide (mmo.client) the guided tour of the level shown: the bar's ? offers it, and it starts by itself the first time the user meets that level. The other levels' tours go: one tour, the one of what is shown.

registerTour()

tour()

PageEditor.js:335
tour()
retourneObjectthe guided tour of the level shown (MMO.guide): its targets are the editor's own nodes

call(method, path, body, {token = this.token, raw = false, retry = true})

asyncPageEditor.js:426
async call(method, path, body = undefined, {token = this.token, raw = false, retry = true} = {})
methodstring
pathstring- under admin/, or a whole url
body = undefined*- sent as json
{token = this.token, raw = false, retry = true} = {}
retournePromise<{status: number, data: *, meta: *, text: string>}

start()

asyncPageEditor.js:463

[internal] The types of section, the pages, then the page to open

async start()

loadPages()

asyncPageEditor.js:484
async loadPages()
retournePromise<Array<Object>>the pages, in the picker of the bar

open(id, force)

asyncPageEditor.js:499

Open the page $id: its unsaved changes are the user's to leave

async open(id, force = false)
id
force = false

setPage(page, history)

PageEditor.js:518
setPage(page, history = 'reset')
pageObject- as the api gives it
history = 'reset'string- reset (another page), keep (saved, published: the same draft), record (a draft replaced -- a rollback --, which can be undone)

changed(preview)

PageEditor.js:564

The draft changed: the history records it, the preview follows, unless the change came from it (the expert level edits it in place)

changed(preview = true)
preview = true

record()

PageEditor.js:588

[internal] A change: the state before it goes on the undo stack -- once for a group of changes made without a pause -- and what was undone can no longer be redone

record()

flushHistory()

PageEditor.js:603

[internal] End the group of changes running: the draft as it is now is the history's state

flushHistory()

undo()

PageEditor.js:614

Undo the last change of the draft (a group of changes made without a pause)

undo()

applyState(state)

PageEditor.js:630

[internal] Put the draft back as $state says: the form, the drawer and the preview follow

applyState(state)
state

updateHistory()

PageEditor.js:648

[internal] The undo and redo buttons: enabled when there is something to undo, to redo

updateHistory()

historyKey(event)

PageEditor.js:659

[internal] The history's keys: Mod+Z undoes, Mod+Shift+Z and Ctrl+Y redo -- but in a field (an input, a text being edited: <mmo-editor> takes the keys it answers, defaultPrevented), which undoes its own typing

historyKey(event)
eventKeyboardEvent

save()

asyncPageEditor.js:673
async save()
retournePromise<boolean>whether the draft was saved

create(form)

asyncPageEditor.js:720

Make a page from the form of the side

async create(form)
form

CanCompare()

staticPageEditor.js:755
static CanCompare()
retournebooleanwhether the page can show what changed between a revision and the draft: when it has mmo.git's <mmo-diff>, which mmo.editor does not depend on

compare(revision)

PageEditor.js:764

Show what changed between $revision and the draft, as json, side by side, in a dialog: the application's side panel is too narrow for two versions, and under the editor's drawer.

compare(revision)
revisionObject- {number, version: {title, layout, seo, sections}}, from revisions.json?full=1

LanguageCode(code)

staticPageEditor.js:803
static LanguageCode(code)
code
retourne?string$code as a page keeps it: --separated, lowercase -- null when it is no language tag

languageName(code)

PageEditor.js:809
languageName(code)
code
retournestringthe name of the language $code, in the user's language

translatable(field, key, parent)

PageEditor.js:821
translatable(field, key = null, parent = null)
fieldObject- a field's schema
key = null?string- its name
parent = null?Object- the schema of the object holding it
retourne?stringwhat a translation does with it: text (translated), object and list (their fields may be), null (the same in every language) -- the server's rules (Translations::Kind()): change both together

filled(value)

PageEditor.js:835
filled(value)
value
retournebooleanwhether $value is a text that says something: not empty, nor a markup holding nothing

merge(field, base, translation, kind)

PageEditor.js:840
merge(field, base, translation, kind = 'object')
field
base
translation
kind = 'object'
retourne*$base (a field's value in the default language) with the texts of $translation where it has them

extract(field, value, base, kind)

PageEditor.js:859
extract(field, value, base, kind = 'object')
field
value
base
kind = 'object'
retourne*what a translation keeps of $value (a field's, in a language): its texts that differ from $base's; null, none

untranslated(field, base, translation, kind, path, labels, found)

PageEditor.js:884

[internal] The texts of $base (a field's value in the default language) that $translation does not translate

untranslated(field, base, translation, kind, path, labels, found)
field
base
translation
kind
path
labels
found

translationOf(draft, language)

PageEditor.js:908
translationOf(draft, language)
draftObject- draft
languagestring- one of its languages but the default one
retournemissing: Array<{path: string, labels: Array<string>, section: ?number>, total: number}} the texts of the draft $language does not translate, and how many texts it has

draft()

PageEditor.js:933
draft()
retourneslug: string, title: string, layout: string, seo: Object, sections: Array<Object>, languages: Array<string>, translations: Object} the draft as the api takes it: in its default language, and its translations -- the language shown's taken from the form (extractShown)

extractShown()

PageEditor.js:945

[internal] @return {?Object} the translation of the language shown: what its texts say that the default language's do not

extractShown()

showLanguage(draft)

PageEditor.js:964

[internal] Put $draft (draft) in the form, in the language shown: its texts translated, the default language's where they are not

showLanguage(draft)
draft

setLanguage(language)

PageEditor.js:985

Show the page in $language (one of its languages; null or the default one: the default one)

setLanguage(language)
language

baseValue(path)

PageEditor.js:1000
baseValue(path)
path
retourne*the value at $path (the form's: sections/0/data/title, seo/title) in the default language

renderLanguages()

PageEditor.js:1010

[internal] The bar's language, the notice of the language shown, the drawer's languages when it shows them

renderLanguages()

renderLanguagesPanel()

PageEditor.js:1031

[internal] The drawer's languages: the default one, the others -- each with what it does not translate yet, a link to each field -- and adding one

renderLanguagesPanel()

valueAt(draft, path)

PageEditor.js:1078
valueAt(draft, path)
draft
path
retourne*the value at $path in $draft (draft)

excerpt(value, length)

PageEditor.js:1083
excerpt(value, length = 60)
value
length = 60
retournestringthe beginning of a text (html or not), to recognise it

addLanguage(code, defaultLanguage)

PageEditor.js:1092

Add the language $code to the page ($defaultLanguage its default one, when it had none), and show it

addLanguage(code, defaultLanguage)
code
defaultLanguage

removeLanguage(code)

asyncPageEditor.js:1107

Take $code out of the page's languages: its translation goes with it (it can be undone)

async removeLanguage(code)
code

setDefaultLanguage(code)

PageEditor.js:1121

The page's texts are in $code: what its default language is called (nothing is translated)

setDefaultLanguage(code)
code

goToField(language, path)

PageEditor.js:1132

Open the field $path (the form's data-path) in $language, to translate it

goToField(language, path)
language
path

visible(field)

PageEditor.js:1166
visible(field)
field
retournebooleanwhether $field (or a type) is shown at the level

defaults(schema)

PageEditor.js:1171
defaults(schema)
schema
retourne*the default value of $schema (its default, or its fields' for an object)

translateExample(value, schema)

PageEditor.js:1190
translateExample(value, schema)
value*- an example of a schema (its default), in English
schemaObject- its field's
retourne*the example in the user's language: its texts translated (MMO.i18n), but a choice (enum) and an address, which the page needs as they are

newSection(type)

PageEditor.js:1202
newSection(type)
type
retournetype: string, data: Object} a section of $type, with its defaults (its id is the server's to make)

indexOf(id)

PageEditor.js:1207
indexOf(id)
id
retournenumberthe index of the section $id in the draft, -1 if it has none

addSection(type, after)

PageEditor.js:1212

Add a section of $type, after the section $after (at the end without it)

addSection(type, after = null)
type
after = null

fieldInput(field, obj, key, path)

PageEditor.js:1263
fieldInput(field, obj, key, path)
fieldObject- its schema
objObject- what holds its value
keystring- its key in obj
pathstring- its path, as the api's errors name it (sections/0/data/title)
retourneHTMLElementthe input of a field, writing into obj[key]

imageInput(field, obj, key, path)

PageEditor.js:1320

[internal] @return {Array<HTMLElement>} an image: its address, a file sent to mmo.edms, its description

imageInput(field, obj, key, path)
field
obj
key
path

listInput(field, obj, key, path)

PageEditor.js:1346

[internal] @return {HTMLElement} a list of items: each its fields, moved, removed, added

listInput(field, obj, key, path)
field
obj
key
path

sectionCard(section, i, alone)

PageEditor.js:1388
sectionCard(section, i, alone = false)
sectionObject
inumber- its index in the draft
alone = falseboolean- in the drawer: open, its tools alone
retourneHTMLElementthe form of a section: its fields, and tools to move, copy, remove it

showErrors(errors)

PageEditor.js:1407

Show what the api says is wrong: in a list, and next to each field (the closest one the form has)

showErrors(errors)
errors

preview(version, label)

PageEditor.js:1444

Render $version (the draft by default) in the preview, a moment after the last change

preview(version = null, label = null)
version = null?Object- {title, layout, seo, sections}
label = null?string- what it is

showPreview(html, expert)

PageEditor.js:1472

[internal] $html in the preview: its addresses resolved from this page, its sections clickable

showPreview(html, expert)
html
expert

hookPreview(scroll, expert, tries)

PageEditor.js:1488

[internal] Once the preview's document is parsed (its load may never come: a request of the page staying open): a click on a section opens its form; at the expert level, the edits in place go into the draft

hookPreview(scroll = 0, expert = false, tries = 60)
scroll = 0
expert = false
tries = 60

setFromPreview(path, html, region)

PageEditor.js:1526

Write what the expert level edited in place into the draft

setFromPreview(path, html, region)
pathstring- the field's data-path: sections.{id}.data.{key}[.{index}.{key}…]
htmlstring- the region's html (MMO.editor.sanitize)
regionElement- the region, whose text a plain text field takes

sectionTools(doc)

PageEditor.js:1548

[internal] The toolbar of the section under the pointer, in the preview: move, copy, remove, add one after it

sectionTools(doc)
doc

select(id, scroll)

PageEditor.js:1600

Select the section $id: framed in the preview, its form opened

select(id, scroll = true)
id
scroll = true

resize(button, width)

PageEditor.js:1616

The preview's width: a desktop's, a tablet's, a phone's

resize(button, width)
button
width