[3.0] Theme split (wave 1, part 5) — Autosave drafts from an SCEditor plugin - #9337
Conversation
… plugin smf_DraftAutoSave reached into the editor from outside: it waited for window.load in the hope that SCEditor had built its iframe by then, dug that iframe out of the document by index, and hung blur and focus handlers on it by hand. Each caller then repeated its configuration in an inline <script>. Rewrite it as a plugin, so SCEditor tells it when the editor is ready and when focus moves, instead of it guessing. Deciding *when* to save lives in one place; *what* to send comes from a second plugin, messageDrafts or pmDrafts, so the post and personal message cases no longer share a bPM flag and a pile of branches. Configuration moves into the editor's draftOptions. Wave 1, part 5 of breaking up SimpleMachines#7933. Co-Authored-By: John Rayes <live627@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
form.elements['recipient_to[]'] returns a RadioNodeList once there is more than one recipient, and a RadioNodeList carries a value property of its own, so testing for one cannot tell a single recipient apart from several. With two recipients selected it took the single-value branch and posted NaN.
|
One thing to flag for whoever merges: this overlaps #9335 textually. Both add to the editor's $plugins = [];
$options = [ /* autofocus, on Post only */ ];
if (Utils::$context['drafts_autosave']) {
$plugins[] = 'drafts';
$plugins[] = 'messageDrafts';
$options['draftOptions'] = [ /* ... */ ];
}
if (!empty(Config::$modSettings['enable_mentions']) && User::$me->allowedTo('mention')) {
$plugins[] = 'mentions';
}I have built and tested that combination locally — the editor comes up with |
|
The Root cause was a copy-paste slip in That also explains part of why the branch's |
Review feedback on SimpleMachines#9337: multi-line comments should be the /* * ... */ variant rather than stacked // lines.
Review feedback on SimpleMachines#9337: multi-line comments should be the /* * ... */ variant rather than stacked // lines.
Review feedback on SimpleMachines#9337: multi-line comments should be the /* * ... */ variant rather than stacked // lines.
Review feedback on SimpleMachines#9337: multi-line comments should be the /* * ... */ variant rather than stacked // lines.
Wave 1, part 5 of breaking up #7933.
Draft autosave is currently dead
Before anything else: on
release-3.0today, draft autosave never saves anything. The console saysdrafts.jscallsgetText(), which the bundled SCEditor no longer has. I confirmed it on a clean checkout: type a subject and a body, wait past the autosave interval, andsmf_user_draftsstays empty andid_draftstays0. So this PR is less a refactor than a repair.What changes
smf_DraftAutoSavereached into the editor from outside — waited forwindow.loadhoping SCEditor had built its iframe by then, dug that iframe out withdocument.getElementsByTagName('iframe')[0], and attached blur and focus handlers by hand. Every caller then repeated its configuration in an inline<script>.It becomes a plugin, so SCEditor says when it is ready and when focus moves rather than the code guessing:
draftsdecides when to save.messageDrafts/pmDraftsdecide what to send.That splits the old
bPMflag and its branches into two small objects, and configuration moves into the editor'sdraftOptions, whichEditor::setSCEditorOptions()already supports. The two inline<script>blocks go away.Fixes on top of #7933
The version there does not work for personal messages. Three independent faults:
getRecipient()andgetFormData()refer toformandeditor, which are declaredconstinsidethis.initrather than in the plugin closure —ReferenceErroron every call.id_pm_draft, but the server reads$_POST['id_draft'], so every autosave would create another draft instead of updating one.recipient_to[]repeated, making$_POST['recipient_to']an array, whileDraft::setProperties()doesexplode(',', $_POST['recipient_to'])— aTypeError, fatal on every PM autosave.Also dropped: a leftover
console.log(XMLDoc); adraft_sectionlookup that assumes an element only the posting page has; asignalBlurEventthat cleared the interval without clearing the handle, sosignalFocusEventcould never restart it; andphp_to8bit()onFormDatafields, which double-encodes now that the browser does the encoding.One more found while testing, in both the old code and #7933: recipients were collected through
form.elements['recipient_to[]'], which returns aRadioNodeListas soon as there is more than one. ARadioNodeListhas avalueproperty of its own, so a'value' in eltest cannot tell one recipient from several — with two selected it took the single-value branch and postedNaN. Collected by selector instead.Testing
id_draftcomes back and is reused, the "last saved" note updates, the throbber clears. Verified insmf_user_drafts.type = 1andto_listof{"to":[2,3],"bcc":[0]}— the server parsed both recipients from the joined value, which cannot happen with any of the three faults above."","2","2,3".Unrelated bug found, not fixed here
Updating an existing draft does not write. The client sends the right request (
id_draftset, new body) and the server answers with a fresh "last saved" time, but the row never changes. I traced it intoDraft::saveToDatabase(): in the same request the DB layer canSELECTthe row by that id, yet theUPDATEimmediately afterwards reportspg_affected_rows() == 0and the row keeps its oldbodyandposter_time. The same statement run by hand inpsqlupdates the row fine.saveToDatabase()returnstrueregardless, so nothing surfaces.That is server-side and independent of this change — it just was not observable before, because autosave never got as far as saving a first draft. Happy to open it separately.
🤖 Generated with Claude Code