
Imaginez un modèle de contrat envoyé à des dizaines de clients. L'équipe juridique a soigneusement rédigé chaque clause, et les seuls éléments que chaque destinataire doit toucher sont le bloc de signature, le nom du projet et la date d'acceptation. Remettez-leur un fichier Word entièrement modifiable et quelqu'un reformulera inévitablement une clause pénale ou supprimera une section de responsabilité. Verrouillez l'intégralité du document et personne ne pourra remplir les champs. Ce dont vous avez réellement besoin, c'est d'une édition sélective — un moyen de dire « ces paragraphes précis sont modifiables, tout le reste est figé ».
C'est exactement ce que vous offrent les plages modifiables. Vous protégez l'ensemble du document en lecture seule, puis vous placez une paire de marqueurs d'autorisation autour des paragraphes que vous souhaitez laisser ouverts. Toute personne ouvrant le fichier dans Word peut saisir du texte à l'intérieur de la zone balisée, mais ne peut modifier le moindre caractère en dehors. Spire.Doc for JavaScript met cette fonctionnalité à la disposition du navigateur via WebAssembly, ce qui vous permet de générer des documents protégés depuis une application React sans aller-retour vers le serveur — les polices et les fichiers d'entrée sont gérés par un système de fichiers virtuel en mémoire (VFS).
Ce guide parcourt les deux volets du processus :
- Définir une plage modifiable — protéger le document et baliser la zone ouverte
- Supprimer une plage modifiable — retirer les marqueurs et lever la restriction
Si vous n'avez pas encore intégré Spire.Doc à votre projet, commencez par Intégrer Spire.Doc for JavaScript dans un projet React. Les extraits de code ci-dessous supposent que le module WebAssembly est chargé et prêt.
Définir une plage modifiable
Le processus comporte trois étapes. Tout d'abord, chargez les fichiers de polices et le document Word cible dans le système de fichiers virtuel WASM avec FetchFileToVFS. Ensuite, instanciez un Document, chargez le fichier, appelez Protect pour verrouiller l'intégralité du document en lecture seule, puis créez une paire PermissionStart / PermissionEnd partageant le même id — ces deux marqueurs encadrent le paragraphe que vous souhaitez laisser modifiable. Enfin, enregistrez le fichier, relisez-le depuis le VFS, encapsulez-le dans un Blob et déclenchez un téléchargement.
function App() {
const SetEditableRange = async () => {
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// Load the input document into VFS
const inputFileName = "SetEditableRange.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}static/data/`);
// Create a document object and load the document
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// Protect the whole document: everything outside the editable range is read-only
doc.Protect({ type: docModule.ProtectionType.AllowOnlyReading, password: "password" });
// Create the permission markers: a start and an end with the same id form one editable range
const start = new docModule.PermissionStart(doc, "testID");
const end = new docModule.PermissionEnd(doc, "testID");
// Insert the markers into the first paragraph: the start at the beginning, the end appended at the end
doc.Sections.get_Item(0).Paragraphs.get_Item(0).ChildObjects.Insert(0, start);
doc.Sections.get_Item(0).Paragraphs.get_Item(0).ChildObjects.Add(end);
// Save the document
const outputFileName = "Set Editable Range.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
doc.Dispose();
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Editable Range in a Word Document</h1>
<button onClick={SetEditableRange}>
Generate
</button>
</div>
);
}
export default App;
Dans le fichier d'exemple, les champs qu'un relecteur est autorisé à remplir portent un léger grisé — il s'agit uniquement d'un repère visuel pour le lecteur, sans aucune incidence sur la façon dont la plage modifiable est définie dans le code. Une fois les marqueurs en place, Word considère le paragraphe grisé comme modifiable et tous les autres paragraphes comme verrouillés.

Supprimer une plage modifiable
Supprimer la plage modifiable ne demande qu'un seul parcours : bouclez sur chaque section et chaque paragraphe, inspectez chaque objet de la collection ChildObjects du paragraphe et extrayez tout ce qui est un PermissionStart ou un PermissionEnd.
Une subtilité prend souvent les gens au dépourvu : ChildObjects.Remove réduit la collection immédiatement, de sorte que chaque élément suivant celui qui a été supprimé remonte d'un index. Si vous incrémentez votre compteur de boucle pendant la suppression, chaque suppression fait sauter le marqueur suivant — et plus vous avez de marqueurs, plus vous en laissez derrière vous.
function App() {
const RemoveEditableRange = async () => {
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// Load the input document into VFS
const inputFileName = "RemoveEditableRange.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}static/data/`);
// Create a document object and load the document
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// Iterate over every section and paragraph and delete the permission markers
for (let i = 0; i < doc.Sections.Count; i++) {
const section = doc.Sections.get_Item(i);
for (let j = 0; j < section.Body.Paragraphs.Count; j++) {
const paragraph = section.Body.Paragraphs.get_Item(j);
// Remove on a match; the collection shrinks, so the index is not incremented
for (let k = 0; k < paragraph.ChildObjects.Count;) {
const obj = paragraph.ChildObjects.get_Item(k);
if (obj instanceof docModule.PermissionStart || obj instanceof docModule.PermissionEnd) {
paragraph.ChildObjects.Remove(obj);
} else {
k++;
}
}
}
}
// Save the document
const outputFileName = "Remove Editable Range.docx";
doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
// Release resources
doc.Dispose();
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Remove Editable Ranges from a Word Document</h1>
<button onClick={RemoveEditableRange}>
Generate
</button>
</div>
);
}
export default App;
La suppression des marqueurs ne fait que redéfinir la limite de ce qui est modifiable — le texte lui-même et toute la mise en forme restent intacts.

Le cycle de vie complet de la protection
Dans un véritable processus de validation, il est rare de ne faire qu'une seule chose. Un aller-retour type se déroule ainsi :
-
Protéger — Appelez
doc.ProtectavecAllowOnlyReading(ouAllowOnlyFormFields) et un mot de passe. L'intégralité du document est désormais verrouillée. -
Baliser — Encadrez chaque paragraphe modifiable par le relecteur dans une paire
PermissionStart/PermissionEndpartageant un même id. Ces zones deviennent les seuls endroits où un relecteur peut saisir du texte. - Débaliser — Une fois la campagne de révision terminée, parcourez le document et supprimez tous les marqueurs d'autorisation. Les zones rejoignent le corps en lecture seule.
-
Déprotéger — Appelez
doc.Unprotect("password")pour libérer entièrement le document et le rétablir dans un état totalement modifiable pour l'étape suivante du traitement.
L'idée clé est que la protection et les plages modifiables sont deux couches indépendantes. La protection détermine si le document est verrouillé ou non ; la paire de marqueurs détermine quelles portions échappent à ce verrou. Vous pouvez ajouter et supprimer des marqueurs autant de fois que vous le souhaitez sans toucher à l'état de protection, et activer ou désactiver la protection sans perturber les marqueurs — mais les marqueurs n'ont de portée réelle que tant que la protection est active.
FAQ
La plage modifiable est définie, mais le contenu qu'elle renferme reste non modifiable
Pourquoi cela se produit : les marqueurs d'autorisation sont inactifs en eux-mêmes. Ils ne font que créer des exceptions à une restriction appliquée à l'ensemble du document ; donc si Protect n'a jamais été appelé, il n'existe aucune restriction dont ils pourraient exempter quoi que ce soit et les marqueurs ne font rien. Une seconde condition est que PermissionStart et PermissionEnd doivent porter la même chaîne d'id — Word ne les traite comme une paire que si les id correspondent.
Solution : activez d'abord la restriction de modification, puis créez les deux marqueurs avec un id identique :
// Enable protection first so that the markers mean something
document.Protect({ type: wasmModule.ProtectionType.AllowOnlyReading, password: "password" });
// The start and the end must use the same id
const start = new wasmModule.PermissionStart(document, "testID");
const end = new wasmModule.PermissionEnd(document, "testID");
Certains marqueurs sont oubliés lors de la suppression des plages modifiables
Pourquoi cela se produit : chaque appel à ChildObjects.Remove réduit la collection d'un élément, ce qui décale vers le bas l'index de tous les éléments suivants. Si le compteur de boucle progresse lors de la même itération qu'une suppression, l'élément qui a glissé à la position courante n'est jamais examiné — il est ignoré, et le problème s'aggrave à chaque marqueur supplémentaire.
Solution : soit maintenez l'index fixe pendant la suppression (ne l'incrémentez que lorsqu'aucune suppression n'a eu lieu), soit collectez d'abord les objets cibles et supprimez-les dans l'ordre inverse :
for (let k = 0; k < paragraph.ChildObjects.Count;) {
const obj = paragraph.ChildObjects.get_Item(k);
if (obj instanceof wasmModule.PermissionStart || obj instanceof wasmModule.PermissionEnd) {
paragraph.ChildObjects.Remove(obj);
// Do not increment k here: check the new object at the current index
} else {
k++;
}
}
Le document reste en lecture seule après la suppression des marqueurs
Pourquoi cela se produit : les marqueurs définissent uniquement les zones exemptées du verrou — ils ne constituent pas le verrou lui-même. Les supprimer ne fait que supprimer les exemptions ; la protection sous-jacente établie par Protect est toujours en vigueur, de sorte que tout le document reste en lecture seule.
Solution : une fois les marqueurs supprimés et la restriction devenue inutile, appelez Unprotect avec le mot de passe d'origine :
document.Unprotect("password");