Software, your way.
burger menu icon
WillMaster

WillMaster > LibraryWeb Page and Site Features

FREE! Coding tips, tricks, and treasures.

Possibilities weekly ezine

Get the weekly email website developers read:

 

Your email address

name@example.com
YES! Send Possibilities every week!

On-Page Editing

Imagine that you are able to edit a section of a web page right there on the page. Maybe a "this week's speaker" section, as an example. Or a place where you have a to-do list.

Well, it's possible.

One or more parts of your web page can be made editable. The parts then can be edited right on the page.

Simply load the page into your browser and do edits. The edits are then available for future page loads.

The on-page updates are automatically saved, whether typed with a keyboard or spoken through a microphone.

To save edits typed with a keyboard, a save-this timer is set. If another key is pressed, the save-this timer is reset to start over. When the save-this timer has aged 4 seconds (or however many seconds you specify when you implement this system), it is cleared and the changed content is saved.

To save edits spoken through a microphone, the size of the content is checked. If the size has changed since 3 seconds ago (or another timing you specify), the save-this timer is set. As with the keyboard edits, when the save-this timer has aged a specific amount of time it is cleared and the content is saved.

The edits are saved in plain text files. No MySQL setup is required.

What you have with this article is the basic code. It works a treat. Use it to see what can be done. Implement it live, if you want. But before going live, consider adding security so not just anyone can change your page. Security might be IP address check, login with cookie, or other restriction depending on what your implementation's needs are.

Here is an illustration of the working system. When you make changes and reload the page, your edits persist. (Note: This illustration separates edits by IP address so article readers don't clobber each other's edits. Therefore, if you use a browser with a different IP address you won't see your previous edits.)

Here is an editable part of the web page.

Here is another editable part.

Implementation

There are 3 steps to implement the system.

Step 1:
To implement, the first step is to assign a directory on your server where edit files are to be saved. Into that same directory, upload the PHP script. The source code is below. Name it liveupdate.php or other *.php file name that suits you.

<?php /*
On-Page Editing
Version 1.0
February 3, 2025
Will Bontrager Software LLC
https://www.willmaster.com/
*/
if(! (isset($_POST['DO']) and isset($_POST['which'])) ) { exit; }
mb_internal_encoding('UTF-8');
$file = __DIR__ . "/{$_POST['which']}.html";
switch($_POST['DO'])
{
   case 'GET' : echo (file_exists($file) ? file_get_contents($file) : ''); break;
   case 'PUT' : file_put_contents($file,$_POST['content']); break;
}
exit;
?>

The liveupdate.php file saves and retrieves edited content. No customizations are required to use that PHP script.

When you install the JavaScript (see Step 3), the JavaScript will need to know the location of your liveupdate.php file. The location will be the URL to liveupdate.php but with the leading protocol and domain name removed. (The location at URL https://example.com/edits/liveupdate.php would be /edits/liveupdate.php)

Step 2:
Put the HTML code for the system into your web page. This HTML code will present edit boxes like the illustration further above.

<p style="margin-bottom:.25em;">
Here is an editable part of the web page.
</p>
<div id="intro-container" 
   contenteditable="true" spellcheck="true" 
   onkeyup="TheDataHasChanged(this)" onblur="ImmediateDataUpdate(this)"
   style="border:3px dashed #ccc; border-radius:.5rem; font-size:100%; line-height:130%; padding:.5rem; min-height:1in;">
</div>

<p style="margin-bottom:.25em;">
Here is another editable part.
</p>
<div id="document-container" 
   contenteditable="true" spellcheck="true" 
   onkeyup="TheDataHasChanged(this)" onblur="ImmediateDataUpdate(this)"
   style="border:3px dashed #ccc; border-radius:.5rem; font-size:100%; line-height:130%; padding:.5rem; min-height:1in;">
</div>

The id values found in id="intro-container" and id="document-container" will need to be specified in the JavaScript found in the next implementation step, Step 3. The JavaScript uses the id values to determine which HTML element containers to interact with.

The boxes may be styled as you please. The contenteditable="true" attribute turns the div into an editable container. The spellcheck="true" attribute turns the browser's spell checking on if it is available.

The JavaScript function calls for the onkeyup and onblur attributes are provided in the JavaScript at the next step.

Step 3:
The JavaScript code needs to be on the same web page as the HTML code. It can be placed anywhere on the web page that JavaScript can run. Near the end of the page, above the closing </body> tag should work.

Here is the code. The code requires customization. Customization notes follow the code.

<script type="text/javascript">
/* Customization: */
var SaveUpdateURL = "/edits/liveupdate.php";
var SaveAfterSoManySecondsOfNoActivity = 4;
var CheckDataSizeEverySoManySeconds = 3;
var ContentIDs = new Array( 
   "intro-container", 
   "document-container", 
);
/* Customization Completed */

var Timer = new Object;
var Sizer = new Object;
for( var i=0; i<ContentIDs.length; i++ ) { Sizer[ContentIDs[i]]=0; }

function ImmediateDataUpdate(d)
{
   try { clearTimeout(Timer[d.id]) } catch(error) {}
   var http = new XMLHttpRequest();
   if( ! http ) { alert("Unable to save content."); return; }
   var params = new Array();
   params.push( "DO=PUT" );
   params.push( "which=" + encodeURIComponent(d.id) );
   params.push( "content=" + encodeURIComponent(d.innerHTML) );
   http.open("POST",SaveUpdateURL,true);
   http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   http.send( params.join("&") );
} // function ImmediateDataUpdate()

function GetContent(d)
{
   var http = new XMLHttpRequest();
   if( ! http ) { alert("Unable to retrieve content."); return; }
   var params = new Array();
   params.push( "DO=GET" );
   params.push( "which=" + encodeURIComponent(d.id) );
   http.onreadystatechange = function()
   {
      if(http.readyState == 4 && http.status == 200)
      {
         Sizer[d.id]=http.responseText.length;
         document.getElementById(d.id).innerHTML=http.responseText;
      }
   }
   http.open("POST",SaveUpdateURL,true);
   http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   http.send( params.join("&") );
} // function GetContent()

function TheDataHasChanged(d)
{
   try { clearTimeout(Timer[d.id]) } catch(error) {}
   Timer[d.id] = setTimeout(ImmediateDataUpdate,parseInt(SaveAfterSoManySecondsOfNoActivity*1000),d);
} // function TheDataHasChanged()

function CheckIfSizeHasChanged()
{
   for( var i=0; i<ContentIDs.length; i++ )
   {
      var d = document.getElementById(ContentIDs[i]);
      var thelen = d.innerHTML.length;
      if( Sizer[ContentIDs[i]] != thelen )
      {
         Sizer[ContentIDs[i]] = thelen;
         TheDataHasChanged(d);
      }
   }
} // function CheckIfSizeHasChanged()

for( var i=0; i<ContentIDs.length; i++ ) { GetContent(document.getElementById(ContentIDs[i])); }
setInterval(CheckIfSizeHasChanged,parseInt(CheckDataSizeEverySoManySeconds*1000));
</script>

Customization —

Four places in the above JavaScript need to be customized. They are all within a couple lines of the top of the above source code.

  1. var SaveUpdateURL = "/edits/liveupdate.php";

    Replace /edits/liveupdate.php with the location on your server where liveupdate.php is installed. The location is the URL with the leading protocol and domain name removed.

  2. var SaveAfterSoManySecondsOfNoActivity = 4;

    The 4 may remain as is or it can be replaced with the number of seconds to wait after the last edit activity before saving accumulated edits. It is what I call the save-this timer.

    With a low number, the server may be hit often while you are in the process of editing. With a high number, the ending edit might not be saved if you don't wait that number of seconds before closing the web page. With most implementations, I would recommend a low of 3 and a high of 6.

  3. var CheckDataSizeEverySoManySeconds = 3;

    The 3 may remain as is or it can be replaced with the number of seconds to wait between checking the data size. This is the way the software detects when the microphone has been used for editing. It does not save the edit but triggers the save-this timer addressed in the previous customization step.

    There would be a downside to using a low number if the web page is likely to be busy with other things (like animated ads, for example, or videos playing). With a high number, it might not trigger the save-this timer soon enough to save the last of the spoken editing. As with the previous customization step, with most implementations I would recommend a low of 3 and a high of 6.

  4. var ContentIDs = new Array( "intro-container", "document-container", );

    This is where to list the id values of the div tags that may be edited. You may have as few or as many editable div tags as you wish.

    List the id values one per line. Each id value is enclosed in quotes and the line ends with a comma.

    The
    var ContentIDs = new Array(
    line above the list of id values and the
    );
    line below the list of id values must each be on a line by themself.

When the JavaScript has been customized, it needs to be on the same web page as the HTML code for the system. The JavaScript can be placed anywhere on the web page that JavaScript can run. Above the closing tag should work.

When this system is implemented, the web page can be edited within the editable divs. The edits are saved as part of the web page.

(This content first appeared in Possibilities newsletter.)

Will Bontrager

Was this article helpful to you?
(anonymous form)

Support This Website

Some of our support is from people like you who see the value of all that's offered for FREE at this website.

"Yes, let me contribute."

Amount (USD):

Tap to Choose
Contribution
Method

All information in WillMaster Library articles is presented AS-IS.

We only suggest and recommend what we believe is of value. As remuneration for the time and research involved to provide quality links, we generally use affiliate links when we can. Whenever we link to something not our own, you should assume they are affiliate links or that we benefit in some way.

How Can We Help You? balloons
How Can We Help You?
bullet Custom Programming
bullet Ready-Made Software
bullet Technical Support
bullet Possibilities Newsletter
bullet Website "How-To" Info
bullet Useful Information List

© 1998-2001 William and Mari Bontrager
© 2001-2011 Bontrager Connection, LLC
© 2011-2025 Will Bontrager Software LLC