Until HTML 4 it was possible to create layouts with frames loading different HTML files in different panes.
What I want to do is to achieve a similar result but loading and showing on screen two different part of the same document.
My ideal paradigm is MS Word which allows to split the window in 2 horizontal parts to show in each one different sections of the same document (extremely useful when paring different parts of the document or when moving parts from one distant side to the other on long documents) or MS Excel (even LibreOffice or OpenOffice Calc have a similar feature) that allows to split the pane of the sheet in 2 (or even in 4) sections for the same reason or to keep visible some rows on top or some columns at the right (row or column header for example).
The following picture shows it:
The red arrow indicate the gutter that splits the window document in two allowing to scroll each part separately, as you can see looking at the number of the row that in the upper pane is 3 and 21 the bottom pane. Also the gutter is resizable.
Is it possible to do this using vanilla JS with HTML & CSS (no jQuery or other framework please)?
Constraints:
- The document must be the same for all 2 panes (top and bottom) (old frameset needs to load two different documents or the same document twice: I'm using this already but I want a more clean approach if possible!)
- The separator (gutter?) has to be resizable
- The two different parts of the document are perfectly in sync in the sense that if I modify something (with the
contenteditable
property) in the top (or bottom) pane the bottom (or the top) pane shows instantly the edit just done as does MS Word or Excel... so if I delete something in any bottom pane table cell even the top content is adjusted accordingly (even the column size), as happens with MS Word, Excel, Calc, etc.. - The split view will be switched on and off on click on a specific button
- I don't care about old browsers, just ECMA script 2015 or more recent ones
- The HTML file has lots of event listeners attached with
addEventListener()
Method to various HTML elements like buttons, text boxes, checkboxes, selectboxes, etc: this means that the answered solution must be able to keep them intact and working in both panes.
Where will I use this?
I have a bunch of tables in a local HTML file (no web server involved) that loads data from a csv file or from the browser session storage, and I frequently need to pare data from different points or to keep the header fixed on top while scrolling the rest of a specific table or while inserting new data or updating old data in one of them to continuously see in which table cell I'm inserting or updating data in.
Situation:
At the moment I'm using the following code:
function splitView()
{
var tgtSrc = location.href;
var frameset = '<frameset rows="*,*">' +
'<frame name="' + upFrame + '" src="' + tgtSrc + '">' +
'<frame name="' + dwFrame + '" src="' + tgtSrc + '">' +
'</frameset>';
document.write(frameset);
}
The above function splits horizontally the current window pane in two frames called upFrame and dwFrame (that are two variables). After splitting a resizable gutter is placed between the two frames.
Plus the algorithm to sync both instances of the document's data: it works by saving at each data edit in one frame the data into the session storage of that frame and reloads the same data into the other frame.
It kinda works but frames aren't the way to go, I would like to get rid of the need to load the document twice and sync each instance with all the relative drawback involved. So unfortunately this isn't the ultimate answer I'm looking for because it has some drawbacks:
- The frame and frameset tags are not supported in modern HTML5-pliant files even if they are still supported by browsers
- The file has to be loaded twice (once per frame) this means a noticeable lack of performance and difficult to sync in real time any edits in one frame with the other frame (possibly bidirectional sync is needed so edits could be done in both shown part of the document). Unfortunately even the sync process needed means loosing performances that lock the UI for some instant every sync loop
- The sync process isn't in real time, it has some delay (some seconds): if I make it shorter I have a large lack of performances that includes browser freezing
So I'm open to better answers with cleaner and more efficient solutions. (I have even proposed to Chrome devs to implement a function for it in the browser, because I really think this is a Must Have feature especially considering the expanding online data management systems.)
What I'm looking for:
The use of the above code I'm using already isn't mandatory at all: the answers can propose a plete different approach as well.
So the ultimate solution I'm looking for is something similar to the splitting function used by Google Spreadsheet (if they can, I hope we could too), here's an image with the example
Look carefully at it: there is the gutter that is possible to move horizontally (there is a vertical gutter too, but I don't really care about vertical splitting, just horizontal) and when the spreadsheet scrolls down the rows disappear under it: in fact the first row above the gutter is the n. 1 the first row down the gutter is n. 45.
Also notice the little double headed white arrow indicated by the big red arrow at the extreme left of the picture.
I tried to study the Google spreadsheet approach to reverse engineer it and extract the salient features and adapt the same "philosophy" to my local application but I'm not good enough to understand what they did exactly: my suspect is that when a "table row hits the gutter" just hides behind it, but I'm not sure.
IMHO this is a feature that every browser (even those for portable devices) have to have implemented natively and without using the old technology of frames that are no more supported in html 5. Unfortunately this possibility to split the same document to show and edit different parts of it (as a very long table for example) keeping each pane reciprocally updated, isn't (yet) a browser feature, so in the meanwhile... it is needed a workaround.
Notice:
The CSS property
position: sticky;
would be also usable to solve part of the problem (to keep the thead stuck when editing or when inserting data into the tbody), but unfortunately it doesn't seem to work as expected on thead elements, at least on some browsers. Also it solves just part of the problem: in fact if it is needed to pare data from different parts of the same table or of different tables into the same document this solution isn't good at all. So something else is needed.
Until HTML 4 it was possible to create layouts with frames loading different HTML files in different panes.
What I want to do is to achieve a similar result but loading and showing on screen two different part of the same document.
My ideal paradigm is MS Word which allows to split the window in 2 horizontal parts to show in each one different sections of the same document (extremely useful when paring different parts of the document or when moving parts from one distant side to the other on long documents) or MS Excel (even LibreOffice or OpenOffice Calc have a similar feature) that allows to split the pane of the sheet in 2 (or even in 4) sections for the same reason or to keep visible some rows on top or some columns at the right (row or column header for example).
The following picture shows it:
The red arrow indicate the gutter that splits the window document in two allowing to scroll each part separately, as you can see looking at the number of the row that in the upper pane is 3 and 21 the bottom pane. Also the gutter is resizable.
Is it possible to do this using vanilla JS with HTML & CSS (no jQuery or other framework please)?
Constraints:
- The document must be the same for all 2 panes (top and bottom) (old frameset needs to load two different documents or the same document twice: I'm using this already but I want a more clean approach if possible!)
- The separator (gutter?) has to be resizable
- The two different parts of the document are perfectly in sync in the sense that if I modify something (with the
contenteditable
property) in the top (or bottom) pane the bottom (or the top) pane shows instantly the edit just done as does MS Word or Excel... so if I delete something in any bottom pane table cell even the top content is adjusted accordingly (even the column size), as happens with MS Word, Excel, Calc, etc.. - The split view will be switched on and off on click on a specific button
- I don't care about old browsers, just ECMA script 2015 or more recent ones
- The HTML file has lots of event listeners attached with
addEventListener()
Method to various HTML elements like buttons, text boxes, checkboxes, selectboxes, etc: this means that the answered solution must be able to keep them intact and working in both panes.
Where will I use this?
I have a bunch of tables in a local HTML file (no web server involved) that loads data from a csv file or from the browser session storage, and I frequently need to pare data from different points or to keep the header fixed on top while scrolling the rest of a specific table or while inserting new data or updating old data in one of them to continuously see in which table cell I'm inserting or updating data in.
Situation:
At the moment I'm using the following code:
function splitView()
{
var tgtSrc = location.href;
var frameset = '<frameset rows="*,*">' +
'<frame name="' + upFrame + '" src="' + tgtSrc + '">' +
'<frame name="' + dwFrame + '" src="' + tgtSrc + '">' +
'</frameset>';
document.write(frameset);
}
The above function splits horizontally the current window pane in two frames called upFrame and dwFrame (that are two variables). After splitting a resizable gutter is placed between the two frames.
Plus the algorithm to sync both instances of the document's data: it works by saving at each data edit in one frame the data into the session storage of that frame and reloads the same data into the other frame.
It kinda works but frames aren't the way to go, I would like to get rid of the need to load the document twice and sync each instance with all the relative drawback involved. So unfortunately this isn't the ultimate answer I'm looking for because it has some drawbacks:
- The frame and frameset tags are not supported in modern HTML5-pliant files even if they are still supported by browsers
- The file has to be loaded twice (once per frame) this means a noticeable lack of performance and difficult to sync in real time any edits in one frame with the other frame (possibly bidirectional sync is needed so edits could be done in both shown part of the document). Unfortunately even the sync process needed means loosing performances that lock the UI for some instant every sync loop
- The sync process isn't in real time, it has some delay (some seconds): if I make it shorter I have a large lack of performances that includes browser freezing
So I'm open to better answers with cleaner and more efficient solutions. (I have even proposed to Chrome devs to implement a function for it in the browser, because I really think this is a Must Have feature especially considering the expanding online data management systems.)
What I'm looking for:
The use of the above code I'm using already isn't mandatory at all: the answers can propose a plete different approach as well.
So the ultimate solution I'm looking for is something similar to the splitting function used by Google Spreadsheet (if they can, I hope we could too), here's an image with the example
Look carefully at it: there is the gutter that is possible to move horizontally (there is a vertical gutter too, but I don't really care about vertical splitting, just horizontal) and when the spreadsheet scrolls down the rows disappear under it: in fact the first row above the gutter is the n. 1 the first row down the gutter is n. 45.
Also notice the little double headed white arrow indicated by the big red arrow at the extreme left of the picture.
I tried to study the Google spreadsheet approach to reverse engineer it and extract the salient features and adapt the same "philosophy" to my local application but I'm not good enough to understand what they did exactly: my suspect is that when a "table row hits the gutter" just hides behind it, but I'm not sure.
IMHO this is a feature that every browser (even those for portable devices) have to have implemented natively and without using the old technology of frames that are no more supported in html 5. Unfortunately this possibility to split the same document to show and edit different parts of it (as a very long table for example) keeping each pane reciprocally updated, isn't (yet) a browser feature, so in the meanwhile... it is needed a workaround.
Notice:
The CSS property
position: sticky;
would be also usable to solve part of the problem (to keep the thead stuck when editing or when inserting data into the tbody), but unfortunately it doesn't seem to work as expected on thead elements, at least on some browsers. Also it solves just part of the problem: in fact if it is needed to pare data from different parts of the same table or of different tables into the same document this solution isn't good at all. So something else is needed.
Share Improve this question edited May 25, 2018 at 13:07 willy wonka asked Feb 13, 2018 at 14:48 willy wonkawilly wonka 1,6861 gold badge22 silver badges32 bronze badges 6- the mac mand line does this too, very handy.. unfortuantely i really dont see any way you could do this without loading the same page twice in 2 iframes. – I wrestled a bear once. Commented Feb 13, 2018 at 14:53
- @Iwrestledabearonce. Unfortunately loading the same page twice in 2 iframes doesn't work properly because they have to stay in sync in case of data changes happened in one or the other. Of course I'm hoping that browser developer will add an easy way to do such a thing like window.splitableV = true window.splitableH = true.... But in the meanwhile... – willy wonka Commented Feb 13, 2018 at 16:09
- 1 i don't think it would be too hard to build, but it would be implementation specific.. in otherwords that page that you're putting in the frame would have to be built to go in that frame. i don't think there's going to be an easy plug and play option.. – I wrestled a bear once. Commented Feb 13, 2018 at 16:24
- @Occam'sRazor Implementation specific is fine for me – willy wonka Commented May 12, 2018 at 16:23
-
1
How exactly will you change the contents of the document? Via an external editor or in the browser like with the
contenteditable
property or ... ? – Code4R7 Commented May 24, 2018 at 20:51
4 Answers
Reset to default 3Just curious, if it's local files on your puter why are you trying to edit table data from csv files in a browser instead of just using the native abilities of a program like Excel you mentioned above? Or if you want to do it in browser does google sheets allow for the split screen thing? No disrespect I just don't understand why not using a program dedicated and optimized for this type of work.
if you want to continue using frames you should be able to load the file back into one frame and just copy the innerHTML from one frame to another, something like the following. If you're using session storage though it should (?) be faster to save edits to that and the csv file but load from session storage instead of the file.
window.frames[upFrame].document.body.innerHTML = window.frames[dwFrame].document.body.innerHTML;
Instead of using frames you can use DIVs as containers, load into local storage as you suggest and populate both DIVs from there. saves would go to both csv file and local storage like the frames solution. Javascript can keep track of the scroll top so once reloaded from local storage you can "pop" the two sections to the rows they were on.
A faster solution though might be keeping the csv data in memory (array) and save out to the csv but updating from memory would be much faster than a file in theory right :)
There are probably better solutions than the hack I've e up with, but let's give it a try.
If you want to take the entire page and just split it, you can use your frameset solution, but instead of making the browser load the resource twice you can just copy its HTML and write it into the frames:
<html>
<head>
<style type="text/css">
body { color: red; } /* Only used to test if CSS is copied as well
</style>
</head>
<body>
Hello world!
</body>
<script type="text/javascript">
function inFrame () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
function buildFrames() {
const documentHTML = document.documentElement.innerHTML;
const frameset = document.createElement('frameset');
frameset.rows = '*,*';
const frame1 = document.createElement('frame');
const frame2 = document.createElement('frame');
document.documentElement.innerHTML = '<html><body></body></html>';
frameset.appendChild(frame1);
frameset.appendChild(frame2);
document.body.appendChild(frameset);
frame1.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
frame2.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
}
if (!inFrame()) {
buildFrames();
}
</script>
</html>
You need to be careful about the javascript code that's executed inside your pages though. As you can see, I've also had to check if the page is not already inside an frame, otherwise it would keep appending framesets to the document forever (or at least until the browser prevents it).
i think you can achieve that with divs.
first create two divs to hold the upper and lower views.
then clone then main content to each div.
by adjusting the dimensions and position for each div you can get the view of one div spitted into two parts
also you can create re size script to manage the height of each view div
for cascading actions across multiple views. you can use events on upper view to make the changes on the lower view. and on lower view to make the changes on the upper view.
finally sorry for bad explanation.
i made jsfiddle to explain the approach
[1]: https://jsfiddle/EmadElpurgy/r9w93zo7/sample code
I'm only going to partially address your question, since I don't have a plete solution.
The frame and frameset tags are not supported in modern HTML5-pliant files even if they are still supported by browsers
Frame has been deprecated in favour of iframe. This should behave in pretty much the same way.
To guarantee syncing between the two panes with the constraints you have laid out, you're going to have to write custom JS, especially since you're framework/package averse.