Okay, so the last post took an unexpected turn. I was blissfully unaware of how tricky it would be to change the look (or "theme") of Bookworm. It wouldn't be so bad if it was a simple HTML application, but since I'm also using jQuery UI that means I need to go through some extra work. I like the styling of the jQuery UI widgets, you could create the same, or at least very similar, widgets in plain HTML and CSS - but I also like the experience of working with a JavaScript library. You need to look at your code differently when you're adding someone else's library - case in point how I didn't consider that jQuery UI would have it's own stylesheet. And it turns out that the JQUI stylesheet is kind of complicated. So let's look at how it handles themes...
ThemeRoller
There is a great place to go for JQUI themes, a site called ThemeRoller...
Here you can change everything about how JQUI looks. When you get done and click on the link to download your theme though, it gets a little weird. You get taken to this download page....
And there are a lot of checkbox options...
At the bottom of the page it actually mentions something about themes...
What you download is a zip archive with a lot of files in it...
If you leave everything checked, like I did, you get quite a few files and directories. You get a lot more than just the theme you were working on; you end up with the jQuery UI JavaScript file, the jQuery JavaScript file, a package.json for your package manager, some other stuff, and several CSS files. The first thing to note are the jquery-ui.css and the jquery-ui.min.css files...
These are the JQUI stylesheets, both of them, but the second is the "minified" version. You get this with things that go over the web. Just like a zip archive is a compressed format to reduce the time a download takes, a minified file has extra whitespace removed and usually names for variables and functions have been shortened. It makes for a smaller file, but at the cost of something that is difficult if not impossible for a person to read. Here is a screenshot of the full and minified files side-by-side in Notepad++...
So those are two of the files, basically the same information just in different formats. Which happens again...
The jquery-ui.css is the full stylesheet, but there are also jquery-ui.structure.css and jquery-ui.theme.css files. These last two (and their minified versions) are just two halves of the full stylesheet. The 'structure' file has the CSS elements for positioning and size, the structural elements; while the 'theme' file has the colors and appearance elements. This could be useful to split up in some cases, and I think I'll use these for my theme switcher - I'm not changing any of the structure, just the appearance, so why load anything bigger than I have to?
Another thing I want to point out is the way JQUI uses icons...
JQUI can display its icons in different colors, it does that by loading from a different image file. If you look at the filenames you can see that each has the 6 digit hex color code after the "ui-icons_" beginning. So I need all these files to be together in a folder called "images" that's in the same folder as the css files.
Changing Themes, done right this time
Now that I know how the JQUI themes are created, and what files to load, and have a site to create new themes - now I can actually impliment the theme-switcher. So this is going to be in two parts. First there is the background color which is my basic CSS, located in my own bookworm.css file. The second part is the JQUI theme. I'm making two versions of each JQUI theme, both will have the same primary color, like blue, but one will be designed for a white background and the other for a dark background (I'm going to soften it to a dark grey instead of the pure black I did before). So when I swtich themes I need to change two things. I wasn't sure about how hard it was going to be to change the themes, I had a picture in my head of some complicated coding - I even found a special theme switcher widget. Thankfully I was wrong, because I found another site that has a wonderfully simple solution. Niklas Tech Blog has a great way to switch JQUI themes with a simple drop-down. All I need to do is add a line of JavaScript to also change the background CSS at the same time and I'll have a winner. Hopefully :) So let me whip up the code and see what happens.
So here's my revised code...
The first thing I did was remove the extra stylesheet links. I didn't understand about the full and minified versions of the CSS, so I had linked them both (always read the documentation! though that is a little hard with something as complex as JQUI).
Once I removed the bad link I added the good one. I'm using the 'structure' and 'theme' files, and I renamed the 'theme' files into something more descriptive. I've added an id to the <link> for the stylesheet, to make it easier to target later (per the blog I referenced).
With the <head> stuff fixed, time to add the <select> for the theme changer. Now, I'm not just changing the JQUI theme, I'm also changing the background CSS, so each <option> has a value attribute for the stylesheet link, and also a data-background attribute that is going to change the general CSS.
I'm going to make the <select> a JQUI widget as well, so I've added the code to initialize it in the function that handles all the JQUI setup. To trigger the theme switch when the user selects an option means setting an event listener for the "change" and not the "click" you use for buttons. The function does 3 things: it takes the path from the value attribute and changes the stylesheet link the the head section, it clears any light or dark CSS classes, and it applies either the light or dark from the data-background attribute. I did find something when playing with this, I had originally only set the light/dark on the <body> element - but that didn't change the <textarea> for the notes. So I'd set the background for the page dark and then have the notes still be white. That was an oopsie, so I fixed it to change both.
The last change I made was to set the "dark" CSS class to a dark grey instead of pure black, I just think the grey is a little easier on the eyes...
Here's the drop-down...
Which changes the way everything looks, including the textarea...
Woo hoo!!! We've got themes and they work this time :)
Okay, that actually took a lot of time to figure out. These posts may not look like much, but between researching, coding, screenshotting, and posting they usually take 4 hours. Same with this, it took a while to research how JQUI handled themes and how to change themes in general, play with ThemeRoller to get all the colors something I liked, write the code, fix my mistakes when writing the code, take screenshots, and then write and upload the post, images and Google Drive files. That said, here's the Google Drive link. So while this did not add a lot of functionality to my little app, it's taken enough of my life to call it a day (in an already busy day, hence my posting this late). So I'm going to stop here. Next week I'm moving on to what I expect to be one of the hardest and longest parts, adding an editor that will let the user create their own documents. Until then!
Showing posts with label O2E_Bookworm. Show all posts
Showing posts with label O2E_Bookworm. Show all posts
Saturday, November 11, 2017
Friday, November 3, 2017
Open2 Engine: Bookworm - part 4 - Odds and Ends
So I managed to get the first major component of Bookworm up and running, the ability to open text documents and dynamically show the contents. Then I added the ability to save and open notes. I'm happy about the progress, but this is just the beginning of what all I want to do. The next major feature I am going to add is the ability to create/ edit documents (and I needed to be able to open, display and save a document in the first place) - however, before I get to that there are a few little things I want to fix (also because exactly how to add my next feature has been giving me a headache :).
Adding a "splash screen"
In case you hadn't heard the term somehow, a 'splash screen' is the screen you see before a program loads. It's usually small, and nothing more than the program's logo and maybe a progress bar. I want to add one, well, something like it at least, to Bookworm. Why, after all this is not a very complicated program? Well, since I'm using jQuery UI for my styling I layout everything in HTML and then run some JavaScript to format it all. This is causes a moment when the page loads and the text isn't styled. I got some screenshots of it...
This really bugs me, I don't like having that transition. So what I'm going to do is set the "load" div to hidden and add another div that will be the only visible "splash screen" that won't have an UI elements that need styling. This way jQuery UI can do it's stuff behind the scenes. So I'm adding a <div> and setting the <div> for the tabs/ main body to hidden. Then, I need to show it when everything loaded, so I'll add a line to the function that loads the UI elements to show them when finished.
I started playing with GitHub to learn about version tracking, so you can see a little green bar in the screenshots where I added new code...
This was easy enough, and seemed like a simple idea, but it didn't quite turn out how I expected...
The tabs section is weirdly truncated, and I had trouble before getting the height right for some reason, looks like I've still got problems. Hmmm.... So how to fix that?
Well, it was actually pretty easy, I just removed what I had done before. I had set a min-height for the tabs div, which I deleted and everything worked perfectly after that. Okay, so I made the problem myself :) At least it was an easy fix. I did add one new thing, I added a 50px margin-bottom to the main <body> element. That's because I like how the button to "Load Another Document" is at the bottom of the screen and had the border for the tabs div running through it. It's a silly little stylistic thing, but it's hard to see at the bottom of the screen. Which is hard to describe, so here's a before and after set of screenshots...
Right now I'm keeping the "splash screen"/ header at the top of the page. It is kind of nice to have the program's name always visible, but I'm not sure if I want it to be or not. Until I decide I'll leave it the way it is.
Disabling the Save Notes button
Something you can see in the screenshots above is how the "Save Notes to File" button is enabled even though no notes have been loaded. It seems silly to save a blank file as notes, so I want to set that button to be disabled at startup and have the function that loads the notes enable it. I made that button in plain HTML and while I can change it's state in HTML I think I'm going to go ahead and make it a jQuery UI button instead, and add a little icon of a floppy disk to it. I like working with jQuery and jQuery UI to learn how they work, it might even be easier to do a lot of this in plain HTML/ CSS (the tabs, accordion and buttons) but I'm going to focus on doing as much as I can with jQuery UI. I can always re-write it later, which would be another learning experience :)
So, I'm going to add the button, it's icon and set it to disabled in the function that loads the UI elements...
Then it's a line in the function that loads a notes file to enable the save button...
And here's how it looks...
While I'm at it, why not change the "Load Another Document" button as well?
Changing the file load buttons is trickier. They are kind of special, since they interface with the operating system. Turning them into a jQuery UI button just looks weird...
...so for now I'll leave those alone. I'm thinking I can just hide them with "display:hidden", put a jQuery button there and when the jQuery button is clicked have JavaScript call the hidden file button's event handler. That might work. Thing is, while I'm not fond of having different kinds of buttons I also like how they display the filename, which would mean making my own label as well. I'm not sure what I'm going to do with this right now. It's another thing that I'm not fond of but also doesn't bother me that much.
The Textarea Width
This has bugged me, I set the "cols" attribute on the <textarea> just following what I was reading at the time - but I don't like how it's not the full width of the screen. So I'm changing that to be 95% width in CSS. Looks better now.
Light and Dark Themes
While I'm in CSS there's one last thing I'm going to change right now. By default everything's black text on a white page, which is fine but I do sometimes like to read in the dark (I know it's bad for my eyes). So I want to make a dark and light themes that can be changed. To do this I'm going to make a new tab called "settings" and put some buttons that will change a CSS class on the <body> element (which everything should inherit from).
So I need to do a few things. First I need to add a new section to the tabs widget for the settings. Then I need to add some buttons. The easiest way I can think of to switch themes is to use jQuery's "toggleClass" method, which will take a list of classes (in this case "light" and "dark") and will then remove the class already there and add the class not there. I could make an if-then block for each, but this is easier. Then I also need to add the classes to the CSS stylesheet, and the new settings theme buttons to the jQuery UI setup function, with the "light" button disabled to start (since that'll be the default style). Which led to some typing and then this...
So... I forgot that my simple "toggleClass" didn't change the light button to be enabled. I also didn't realize the jQuery UI widgets wouldn't inherit from the <body>'s style. Okay... mistakes were made... I did want to add the ability to change the style of the jQuery UI buttons, to have something like green instead of the default blue. So apparently I need to look at how to change all that styling...
Which I am going to do later. Right now I'm out of my time to work on this, so I'll pick it up from here for next week. I've got the updated file (somewhat broken as it currently is :) that you can download here. Until next week!
Adding a "splash screen"
In case you hadn't heard the term somehow, a 'splash screen' is the screen you see before a program loads. It's usually small, and nothing more than the program's logo and maybe a progress bar. I want to add one, well, something like it at least, to Bookworm. Why, after all this is not a very complicated program? Well, since I'm using jQuery UI for my styling I layout everything in HTML and then run some JavaScript to format it all. This is causes a moment when the page loads and the text isn't styled. I got some screenshots of it...
This really bugs me, I don't like having that transition. So what I'm going to do is set the "load" div to hidden and add another div that will be the only visible "splash screen" that won't have an UI elements that need styling. This way jQuery UI can do it's stuff behind the scenes. So I'm adding a <div> and setting the <div> for the tabs/ main body to hidden. Then, I need to show it when everything loaded, so I'll add a line to the function that loads the UI elements to show them when finished.
I started playing with GitHub to learn about version tracking, so you can see a little green bar in the screenshots where I added new code...
This was easy enough, and seemed like a simple idea, but it didn't quite turn out how I expected...
The tabs section is weirdly truncated, and I had trouble before getting the height right for some reason, looks like I've still got problems. Hmmm.... So how to fix that?
Well, it was actually pretty easy, I just removed what I had done before. I had set a min-height for the tabs div, which I deleted and everything worked perfectly after that. Okay, so I made the problem myself :) At least it was an easy fix. I did add one new thing, I added a 50px margin-bottom to the main <body> element. That's because I like how the button to "Load Another Document" is at the bottom of the screen and had the border for the tabs div running through it. It's a silly little stylistic thing, but it's hard to see at the bottom of the screen. Which is hard to describe, so here's a before and after set of screenshots...
Right now I'm keeping the "splash screen"/ header at the top of the page. It is kind of nice to have the program's name always visible, but I'm not sure if I want it to be or not. Until I decide I'll leave it the way it is.
Disabling the Save Notes button
Something you can see in the screenshots above is how the "Save Notes to File" button is enabled even though no notes have been loaded. It seems silly to save a blank file as notes, so I want to set that button to be disabled at startup and have the function that loads the notes enable it. I made that button in plain HTML and while I can change it's state in HTML I think I'm going to go ahead and make it a jQuery UI button instead, and add a little icon of a floppy disk to it. I like working with jQuery and jQuery UI to learn how they work, it might even be easier to do a lot of this in plain HTML/ CSS (the tabs, accordion and buttons) but I'm going to focus on doing as much as I can with jQuery UI. I can always re-write it later, which would be another learning experience :)
So, I'm going to add the button, it's icon and set it to disabled in the function that loads the UI elements...
Then it's a line in the function that loads a notes file to enable the save button...
And here's how it looks...
While I'm at it, why not change the "Load Another Document" button as well?
Changing the file load buttons is trickier. They are kind of special, since they interface with the operating system. Turning them into a jQuery UI button just looks weird...
...so for now I'll leave those alone. I'm thinking I can just hide them with "display:hidden", put a jQuery button there and when the jQuery button is clicked have JavaScript call the hidden file button's event handler. That might work. Thing is, while I'm not fond of having different kinds of buttons I also like how they display the filename, which would mean making my own label as well. I'm not sure what I'm going to do with this right now. It's another thing that I'm not fond of but also doesn't bother me that much.
The Textarea Width
This has bugged me, I set the "cols" attribute on the <textarea> just following what I was reading at the time - but I don't like how it's not the full width of the screen. So I'm changing that to be 95% width in CSS. Looks better now.
Light and Dark Themes
While I'm in CSS there's one last thing I'm going to change right now. By default everything's black text on a white page, which is fine but I do sometimes like to read in the dark (I know it's bad for my eyes). So I want to make a dark and light themes that can be changed. To do this I'm going to make a new tab called "settings" and put some buttons that will change a CSS class on the <body> element (which everything should inherit from).
So I need to do a few things. First I need to add a new section to the tabs widget for the settings. Then I need to add some buttons. The easiest way I can think of to switch themes is to use jQuery's "toggleClass" method, which will take a list of classes (in this case "light" and "dark") and will then remove the class already there and add the class not there. I could make an if-then block for each, but this is easier. Then I also need to add the classes to the CSS stylesheet, and the new settings theme buttons to the jQuery UI setup function, with the "light" button disabled to start (since that'll be the default style). Which led to some typing and then this...
So... I forgot that my simple "toggleClass" didn't change the light button to be enabled. I also didn't realize the jQuery UI widgets wouldn't inherit from the <body>'s style. Okay... mistakes were made... I did want to add the ability to change the style of the jQuery UI buttons, to have something like green instead of the default blue. So apparently I need to look at how to change all that styling...
Which I am going to do later. Right now I'm out of my time to work on this, so I'll pick it up from here for next week. I've got the updated file (somewhat broken as it currently is :) that you can download here. Until next week!
Sunday, October 15, 2017
Open2 Engine: Bookworm - part 3 - Saving Notes
Okay, now that I've gotten the core of Bookworm up and running, the ability to load documents, time to start adding features. The next thing I want is to let the user add notes to the document. Here are some screenshots:
So what I've done is add a jQuery UI "Accordion" panel to the bottom of the display area, and buttons to load and save a text file for notes. The user can also click on the accordion to close it if they don't want to make notes.
Adding the Accordion
To add the accordion, here's the HTML code...
Basically, the accordion is just an <h3> header with a <div> for the body. In there is a <textarea> for the notes and two buttons, one to load a text file and one to save it. The buttons use this JavaScript...
This function is almost identical to the one that loads the document, it just puts the contents of the file in a different place.
Saving the file is the new thing of the day. It's a little complicated, and is more of the code from the "This Could Be Better" blog I referenced earlier. Basically there are two parts to saving the file. First, you create a "blob" or "binary object." That's basically fancy-speak for a file. You set the contents of the <textarea> as the contents of the file. Then you create an "object URL" to make a download link to the file. And I added a line that sets the filename when you save the file to be the same as the file you loaded, which I thought would be convenient to let you quickly over-write the existing file, but instead you get a "filename (1).txt" because Windows will add a number to keep you from overwriting an existing file. So that didn't work exactly as I'd hoped.
The second part, now that the file has been made, is to actually download it. Here you create a hidden anchor link and add it to the document, then call the "click" event on it (since you can't see it to click on it), and finally destroy the hidden link once it's been used.
I did notice some spacing issues when adding the accordion. The buttons were appearing before the textarea instead of after it, so I added the "clear: both" to the textarea and a "clear: left" to the load button to make sure everybody was on separate lines. The accordion itself was being clipped, so I also added the "min-height" to the tabs to make sure there was enough room to see the accordion (I think the trouble came from the fact that the accordion is under the display area, which is hidden and dynamically populated with the document, so the browser didn't know how much space to reserve for everything).
So there is one more feature added to my little program, it's slowly but surely growing in power :)
So what I've done is add a jQuery UI "Accordion" panel to the bottom of the display area, and buttons to load and save a text file for notes. The user can also click on the accordion to close it if they don't want to make notes.
Adding the Accordion
To add the accordion, here's the HTML code...
Basically, the accordion is just an <h3> header with a <div> for the body. In there is a <textarea> for the notes and two buttons, one to load a text file and one to save it. The buttons use this JavaScript...
This function is almost identical to the one that loads the document, it just puts the contents of the file in a different place.
Saving the file is the new thing of the day. It's a little complicated, and is more of the code from the "This Could Be Better" blog I referenced earlier. Basically there are two parts to saving the file. First, you create a "blob" or "binary object." That's basically fancy-speak for a file. You set the contents of the <textarea> as the contents of the file. Then you create an "object URL" to make a download link to the file. And I added a line that sets the filename when you save the file to be the same as the file you loaded, which I thought would be convenient to let you quickly over-write the existing file, but instead you get a "filename (1).txt" because Windows will add a number to keep you from overwriting an existing file. So that didn't work exactly as I'd hoped.
The second part, now that the file has been made, is to actually download it. Here you create a hidden anchor link and add it to the document, then call the "click" event on it (since you can't see it to click on it), and finally destroy the hidden link once it's been used.
I did notice some spacing issues when adding the accordion. The buttons were appearing before the textarea instead of after it, so I added the "clear: both" to the textarea and a "clear: left" to the load button to make sure everybody was on separate lines. The accordion itself was being clipped, so I also added the "min-height" to the tabs to make sure there was enough room to see the accordion (I think the trouble came from the fact that the accordion is under the display area, which is hidden and dynamically populated with the document, so the browser didn't know how much space to reserve for everything).
So there is one more feature added to my little program, it's slowly but surely growing in power :)
Friday, October 6, 2017
Open2 Engine: Bookworm - part 2 - Loading and Reading Files
Okay, last post I went over the general outline for Bookworm, now let's actually start writing some code. I want to focus on three things right now: formatting my "stories", opening them, and reading them.
The Bookworm Document Format
Here's how this is going to work. Bookworm is going to open a plain text file, that is written in HTML but not saved as a webpage (since it will be missing some necessary parts to be a proper HTML document). That HTML content is going to be appended (or added) to a blank <div> "reading area." Then the reader can use links to show and hide the text as they read through it.
Because these files are going to be added to an existing document, while they will be written in HTML they will not have the <doctype> or <head> or <body> sections. They are just going to be the code that would be within the <body> section (without that wrapper itself). That code is also going to use the "data-goto" attributes linked to "id" attributes to navigate the document. Let me show you some of the sample file I wrote:
Yeah, I love my alternate lorem ipsum generators :) So, the basics of the format: each passage except the first has the class of "passage" which has display: none to hide them by default. Each link is a direct child of the <div> element (that is <div><a></a></div>, basically, it doesn't work if there is another div like <div 1><div 2><a></a></div></div>, it could, just doesn't right now) - and the link has a "data-goto" attribute with the same vaule as the "id" attribute it shows. I wrote this as a fragment of an HTML page (that is to say, there is no <doctype>, <head> or <body> sections), but it works even with a full webpage.
What it looks like
So here are some screenshots of Bookworm in action:
Just the two tabs for now, the loader/reader and credits.
Clicking on the "Choose File" button will load a text file.
And all of the display links work.
HTML files work too. Anything text-based. The "Load Another File" button will hide the reader and go back to the load section.
The Code
Okay, let's look at how this was written. Here is the HTML page, section by section:
<!DOCTYPE html>
<!--
This is my draft of the Open2 Engine "Bookworm", a simple file reader
last updated: 2017-10-04
-->
<html>
<head>
<title>Bookworm Draft</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.structure.css">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.theme.css">
<link rel="stylesheet" type="text/css" href="css/bookworm.css">
<link rel="shortcut icon" href="favicon.ico" />
</head>
I'm going to use jQuery UI to make the tabs and some other elements down the road, so in the <head> I'm linking to all of jQuery UI's CSS stylesheets. I also made a favicon, because the Chrome developer's console keeps throwing an error if one is missing, which is not a big deal, but it annoys me to no end.
Okay, moving on from the boring stuff...
<body>
<!--
SET THE TAB DIV AND HEADERS
-->
<div id="tabs">
<ul>
<li><a href="#reader_tab">Reader</a></li>
<li><a href="#credits_tab">Credits</a></li>
</ul>
<!--
LOAD & READ SECTION
-->
<div id="reader_tab">
<div id="load">
<h1>Welcome To The Open2 Engine: Bookworm</h1>
<p>Bookworm is a simple program to read documents.</p>
<table>
<tr>
<td>Select a File to Load:</td>
<td><input type="file" accept="text/*" id="fileToLoad" onchange='loadFileAsText()'></td>
</tr>
</table>
</div>
<div id="reader" class="passage"></div>
<button id="btnLoadReturn" class="BtnBackToLoad" onclick="backToLoad()">Load Another File</button>
</div>
jQuery UI makes a tab widget from two parts, the first is an unordered list that creates the tabs themselves, and then <div> elements for the contents of each tab.
Okay, 3 important things in this part, which is where we'll load and display the file.
First, the load part - that's done by including a button that opens the filesystem's file picker. That button is an <input> element with "type=file", and I added "accept=text/*" so that the file picker will only show text-based files. That's according to the file's MIME-type, which is like a flag saying what the file is made out of. Plain text is "text/plain" (logical, no?) while HTML is "text/html" since HTML is really plain text that is just interpreted a special way. This "accept" flag will keep the user from opening a file that can't be shown (hopefully). Normally you check for user input with JavaScript, but you can define some events in HTML, which is what I've done with this button by putting the "onchange" event to trigger the JavaScript function that will actually read the file. I'm sure some purists would say you shouldn't mix the "action" of JavaScript with the "structure" of HTML, but I don't see a reason not to. Actually, I got this from the Mozilla Developers Network.
Second, there is the blank <div> with "id=reader" - this is where I'm going to put the contents of the opened file.
Third, there is the button to return to the load section. That button is not inside the <div> for the reader, since when I load the file I'm going to over-write everything in the <div> (thus, it's empty). That button just calls a function to hide the reader and show the load section.
While that's all the active stuff, there is a little more to the page...
<!--
CREDITS SECTION
-->
<div id="credits_tab">
<p>Bookworm was written by <a href="http://d100mechanic.blogspot.com" target="_blank">The d100 Mechanic</a> and is released under a Creative Commons <a href="file:///C:/Users/user/Documents/Saved%20Documents/Writing%20and%20Creating%20Works/Creative%20Commons/legalcode" target="_blank">Attribution 4.0 International</a> License</p>
<p>Using the following Javascript Libraries:
<br><a href="https://jquery.com/" target="_blank">jQuery</a>
<br><a href="https://jqueryui.com/" target="_blank">jQuery UI</a>
<br>
<br>And JavaScript code from the blog: <a href="https://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/" target="_blank">This Could Be Better</a>
</p>
</div>
</div>
<script src="javascript/jquery-3.2.1.js"></script>
<script src="javascript/jquery-ui.js"></script>
<script src="javascript/bookworm.js"></script>
</body>
</html>
Always have to remember the legal stuff. So there is a tab for my information, the Creative Commons license I'm releasing this under, and credit where credit is due so links to the sources I used to make this. The very bottom of the page is where the links to all the JavaScript files are at - that's so that those files are read after the rest of the page has already been processed. That means I don't need to worry about "document.ready" to load my JavaScript, according to the books I've read.
Now, when the page loads there is a little flash of unformatted text before jQuery UI takes over to make the widgets. I'm not fond of that, but it also isn't a huge problem. I think I'm going to try to make some kind of "load screen" to hide that behind though (later).
Okay, there's the HTML for the page, let's look at the little bit of CSS I'm using...
/*
This is the CSS code for The Open2 Engine "Bookworm"
*/
.passage {
display: none;
}
.BtnBackToLoad {
display: none;
float: right;
margin-top: 10px;
}
Not much here, just the "passage" class to hide everything (I guess I should call it "hidden" really) and the styling to put the "back to load section" button at the bottom right.
Now on to the real magic, the JavaScript...
/*
* This is the JavaScript code for The open2 Engine "Bookworm"
*/
//function to load all the jQuery UI elements
function jQueryUIsetup (){
$( "#tabs" ).tabs();
};
jQuery UI runs a function to create each widget, at the moment there is only 1 for the tabs, but I plan on adding more, so there is a function to hold all those commands.
//Set a click handler for the <body> on anything with the attribute of "data-goto"
function setGotoListener() {
$('body').on('click', '[data-goto]', function (event) {
//get the data-goto value and convert to a CSS Selector
let sGoto = "#" + $(this).attr('data-goto');
//hide the current Passage and show the goto Passage
$(this).parent('div').hide();
$(sGoto).show();
});
};
This is the function I worked on before that shows and hides passages. I've talked about it, except for one new feature. The function starts by selecting the <body> element, then setting a listener (on) for the 'click' event - and then has another selector '[data-goto]' - which is critical. The passage links don't exist yet, this JavaScript file is going to run when the page is opened, before the user can click on a file to load. So the event listener is attached to the body of the document, but the second selector means it will only trigger on elements with the "data-goto" attribute within the body. That way it can listen for elements that will be added later.
//Function to load the file and append it to the reader div
function loadFileAsText()
{
var fileToLoad = document.getElementById("fileToLoad").files[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent)
{
var textFromFileLoaded = fileLoadedEvent.target.result;
document.getElementById("reader").innerHTML = textFromFileLoaded;
$('#load').hide();
$('#reader').show();
$('#btnLoadReturn').show();
};
fileReader.readAsText(fileToLoad, "UTF-8");
}
This is the blog code I've mentioned earlier, pretty much exactly. First it gets the file the user selected. Then it creates a "fileReader" that is going to process that file. Next is a function that tells the fileReader what to do: get the text of the file, add it to the "reader" <div>, then show the reader and hide the loader sections. Finally, it actually kicks off the fileReader to do it's magic.
//button to hide loaded file and show load div
function backToLoad () {
$('#reader').hide();
$('#btnLoadReturn').hide();
$('#load').show();
}
//everything defined, so run setup functions
jQueryUIsetup();
setGotoListener();
The last function to define is the button that will hide the reader and show the loader section. Doesn't do much. And with all my functions defined, time to call the ones that have to run on the page load, the jQuery UI setup and adding the event listener.
I'm putting a zip file with the whole code, and a sample text file, on my Google Drive here so you can download it and play with it yourself (should the fancy take you to do so :).
And that's it. Not a lot of code, but then it doesn't do a lot right now. I'm going to fix that though, now that I've got the base "program" working, it's time to start adding features. One thing I want is to let the user take notes on a document and save those notes, so that's going to be the next feature I'll add. Until next week!
The Bookworm Document Format
Here's how this is going to work. Bookworm is going to open a plain text file, that is written in HTML but not saved as a webpage (since it will be missing some necessary parts to be a proper HTML document). That HTML content is going to be appended (or added) to a blank <div> "reading area." Then the reader can use links to show and hide the text as they read through it.
Because these files are going to be added to an existing document, while they will be written in HTML they will not have the <doctype> or <head> or <body> sections. They are just going to be the code that would be within the <body> section (without that wrapper itself). That code is also going to use the "data-goto" attributes linked to "id" attributes to navigate the document. Let me show you some of the sample file I wrote:
<div id="0">
<h2>Lorem ipsum</h2>
<p>dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim...</p>
<a href="#" data-goto="1">Next Section</a>
</div>
<div id="1" class="passage">
<h2>Ni! Ni! Ni! Ni!</h2>
<p>...You can't expect to wield supreme power just 'cause some watery tart threw a sword at you! ...You don't frighten us, English pig-dogs...Your mother was a hamster and your father smelt of elderberries! Now leave before I am forced to taunt you a second time! ...</p>
<a href="#" data-goto="2">Next Section</a>
</div>
<div id="2" class="passage">
<h2>Tonight's the night.</h2>
<p>...I'm Dexter. Boo. I love Halloween. The one time of year when everyone wears a mask … not just me... And it's going to happen again and again. It has to happen. I'm really more an apartment person...I'm not the monster he wants me to be. So I'm neither man nor beast. I'm something new entirely. With my own set of rules...</p>
<a href="#" data-goto="3">Next Section</a>
</div>
<div id="3" class="passage">
<h2>Hi. I'm Troy McClure.</h2>
<p>Attempted murder? Now honestly, what is that? Do they give a Nobel Prize for attempted chemistry? Books are useless! I only ever read one book, "To Kill A Mockingbird," and it gave me absolutely no insight on how to kill mockingbirds...Hi. I'm Troy McClure. You may remember me from such self-help tapes as "Smoke Yourself Thin" and "Get Some Confidence, Stupid...Oh, a *sarcasm* detector. Oh, that's a *really* useful invention...Dear Mr. President, There are too many states nowadays. Please, eliminate three...</p>
<a href="#" data-goto="4">Next Section</a>
</div>
<div id="4" class="passage">
<h2>Yo ho ho and a bottle of rum...</h2>
<p>...Pinnace holystone mizzenmast quarter crow's nest ...Shiver me timbers to go on account lookout wherry doubloon chase...p>
<h3>The End</h3>
</div>
Yeah, I love my alternate lorem ipsum generators :) So, the basics of the format: each passage except the first has the class of "passage" which has display: none to hide them by default. Each link is a direct child of the <div> element (that is <div><a></a></div>, basically, it doesn't work if there is another div like <div 1><div 2><a></a></div></div>, it could, just doesn't right now) - and the link has a "data-goto" attribute with the same vaule as the "id" attribute it shows. I wrote this as a fragment of an HTML page (that is to say, there is no <doctype>, <head> or <body> sections), but it works even with a full webpage.
What it looks like
So here are some screenshots of Bookworm in action:
Just the two tabs for now, the loader/reader and credits.
Clicking on the "Choose File" button will load a text file.
And all of the display links work.
HTML files work too. Anything text-based. The "Load Another File" button will hide the reader and go back to the load section.
The Code
Okay, let's look at how this was written. Here is the HTML page, section by section:
<!DOCTYPE html>
<!--
This is my draft of the Open2 Engine "Bookworm", a simple file reader
last updated: 2017-10-04
-->
<html>
<head>
<title>Bookworm Draft</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.structure.css">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.theme.css">
<link rel="stylesheet" type="text/css" href="css/bookworm.css">
<link rel="shortcut icon" href="favicon.ico" />
</head>
I'm going to use jQuery UI to make the tabs and some other elements down the road, so in the <head> I'm linking to all of jQuery UI's CSS stylesheets. I also made a favicon, because the Chrome developer's console keeps throwing an error if one is missing, which is not a big deal, but it annoys me to no end.
Okay, moving on from the boring stuff...
<body>
<!--
SET THE TAB DIV AND HEADERS
-->
<div id="tabs">
<ul>
<li><a href="#reader_tab">Reader</a></li>
<li><a href="#credits_tab">Credits</a></li>
</ul>
<!--
LOAD & READ SECTION
-->
<div id="reader_tab">
<div id="load">
<h1>Welcome To The Open2 Engine: Bookworm</h1>
<p>Bookworm is a simple program to read documents.</p>
<table>
<tr>
<td>Select a File to Load:</td>
<td><input type="file" accept="text/*" id="fileToLoad" onchange='loadFileAsText()'></td>
</tr>
</table>
</div>
<div id="reader" class="passage"></div>
<button id="btnLoadReturn" class="BtnBackToLoad" onclick="backToLoad()">Load Another File</button>
</div>
jQuery UI makes a tab widget from two parts, the first is an unordered list that creates the tabs themselves, and then <div> elements for the contents of each tab.
Okay, 3 important things in this part, which is where we'll load and display the file.
First, the load part - that's done by including a button that opens the filesystem's file picker. That button is an <input> element with "type=file", and I added "accept=text/*" so that the file picker will only show text-based files. That's according to the file's MIME-type, which is like a flag saying what the file is made out of. Plain text is "text/plain" (logical, no?) while HTML is "text/html" since HTML is really plain text that is just interpreted a special way. This "accept" flag will keep the user from opening a file that can't be shown (hopefully). Normally you check for user input with JavaScript, but you can define some events in HTML, which is what I've done with this button by putting the "onchange" event to trigger the JavaScript function that will actually read the file. I'm sure some purists would say you shouldn't mix the "action" of JavaScript with the "structure" of HTML, but I don't see a reason not to. Actually, I got this from the Mozilla Developers Network.
Second, there is the blank <div> with "id=reader" - this is where I'm going to put the contents of the opened file.
Third, there is the button to return to the load section. That button is not inside the <div> for the reader, since when I load the file I'm going to over-write everything in the <div> (thus, it's empty). That button just calls a function to hide the reader and show the load section.
While that's all the active stuff, there is a little more to the page...
<!--
CREDITS SECTION
-->
<div id="credits_tab">
<p>Bookworm was written by <a href="http://d100mechanic.blogspot.com" target="_blank">The d100 Mechanic</a> and is released under a Creative Commons <a href="file:///C:/Users/user/Documents/Saved%20Documents/Writing%20and%20Creating%20Works/Creative%20Commons/legalcode" target="_blank">Attribution 4.0 International</a> License</p>
<p>Using the following Javascript Libraries:
<br><a href="https://jquery.com/" target="_blank">jQuery</a>
<br><a href="https://jqueryui.com/" target="_blank">jQuery UI</a>
<br>
<br>And JavaScript code from the blog: <a href="https://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/" target="_blank">This Could Be Better</a>
</p>
</div>
</div>
<script src="javascript/jquery-3.2.1.js"></script>
<script src="javascript/jquery-ui.js"></script>
<script src="javascript/bookworm.js"></script>
</body>
</html>
Always have to remember the legal stuff. So there is a tab for my information, the Creative Commons license I'm releasing this under, and credit where credit is due so links to the sources I used to make this. The very bottom of the page is where the links to all the JavaScript files are at - that's so that those files are read after the rest of the page has already been processed. That means I don't need to worry about "document.ready" to load my JavaScript, according to the books I've read.
Now, when the page loads there is a little flash of unformatted text before jQuery UI takes over to make the widgets. I'm not fond of that, but it also isn't a huge problem. I think I'm going to try to make some kind of "load screen" to hide that behind though (later).
Okay, there's the HTML for the page, let's look at the little bit of CSS I'm using...
/*
This is the CSS code for The Open2 Engine "Bookworm"
*/
.passage {
display: none;
}
.BtnBackToLoad {
display: none;
float: right;
margin-top: 10px;
}
Not much here, just the "passage" class to hide everything (I guess I should call it "hidden" really) and the styling to put the "back to load section" button at the bottom right.
Now on to the real magic, the JavaScript...
/*
* This is the JavaScript code for The open2 Engine "Bookworm"
*/
//function to load all the jQuery UI elements
function jQueryUIsetup (){
$( "#tabs" ).tabs();
};
jQuery UI runs a function to create each widget, at the moment there is only 1 for the tabs, but I plan on adding more, so there is a function to hold all those commands.
//Set a click handler for the <body> on anything with the attribute of "data-goto"
function setGotoListener() {
$('body').on('click', '[data-goto]', function (event) {
//get the data-goto value and convert to a CSS Selector
let sGoto = "#" + $(this).attr('data-goto');
//hide the current Passage and show the goto Passage
$(this).parent('div').hide();
$(sGoto).show();
});
};
This is the function I worked on before that shows and hides passages. I've talked about it, except for one new feature. The function starts by selecting the <body> element, then setting a listener (on) for the 'click' event - and then has another selector '[data-goto]' - which is critical. The passage links don't exist yet, this JavaScript file is going to run when the page is opened, before the user can click on a file to load. So the event listener is attached to the body of the document, but the second selector means it will only trigger on elements with the "data-goto" attribute within the body. That way it can listen for elements that will be added later.
//Function to load the file and append it to the reader div
function loadFileAsText()
{
var fileToLoad = document.getElementById("fileToLoad").files[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent)
{
var textFromFileLoaded = fileLoadedEvent.target.result;
document.getElementById("reader").innerHTML = textFromFileLoaded;
$('#load').hide();
$('#reader').show();
$('#btnLoadReturn').show();
};
fileReader.readAsText(fileToLoad, "UTF-8");
}
This is the blog code I've mentioned earlier, pretty much exactly. First it gets the file the user selected. Then it creates a "fileReader" that is going to process that file. Next is a function that tells the fileReader what to do: get the text of the file, add it to the "reader" <div>, then show the reader and hide the loader sections. Finally, it actually kicks off the fileReader to do it's magic.
//button to hide loaded file and show load div
function backToLoad () {
$('#reader').hide();
$('#btnLoadReturn').hide();
$('#load').show();
}
//everything defined, so run setup functions
jQueryUIsetup();
setGotoListener();
The last function to define is the button that will hide the reader and show the loader section. Doesn't do much. And with all my functions defined, time to call the ones that have to run on the page load, the jQuery UI setup and adding the event listener.
I'm putting a zip file with the whole code, and a sample text file, on my Google Drive here so you can download it and play with it yourself (should the fancy take you to do so :).
And that's it. Not a lot of code, but then it doesn't do a lot right now. I'm going to fix that though, now that I've got the base "program" working, it's time to start adding features. One thing I want is to let the user take notes on a document and save those notes, so that's going to be the next feature I'll add. Until next week!
Subscribe to:
Posts (Atom)