Merge branch 'dev'

This commit is contained in:
Robbie Antenesse 2016-06-29 10:40:33 -06:00
commit cf5e74e073
26 changed files with 2591 additions and 705 deletions

View File

@ -1,3 +1,13 @@
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^view/([0-9]+)/?$ view/index.php?dict=$1 [NC,L] # Handle dictionary ids.
RewriteRule ^([0-9]+)/?$ view/index.php?dict=$1 [NC,L] # Handle dictionary ids.
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^view/([0-9]+)/([0-9]+)/?$ index.php?dict=$1&word=$2 [NC,L] # Handle word ids.
RewriteRule ^([0-9]+)/([0-9]+)/?$ index.php?dict=$1&word=$2 [NC,L] # Handle word ids.
RewriteRule ^view/([0-9]+)/?$ index.php?dict=$1 [NC,L] # Handle dictionary ids.
RewriteRule ^([0-9]+)/?$ index.php?dict=$1 [NC,L] # Handle dictionary ids.
RewriteRule ^issues/?$ https://github.com/Alamantus/Lexiconga/issues [R=301,L] # Shorten issues url.
RewriteRule ^updates/?$ https://github.com/Alamantus/Lexiconga/releases [R=301,L] # Shorten updates url.

18
EXPORT.form Normal file
View File

@ -0,0 +1,18 @@
<h2>Export</h2>
<div id="exportOptions">
<div class="settingsCol">
<label>
<span>Word List</span>
</label>
<p style="font-size:12px;">This process exports all of the words in the dictionary as a CSV format file.</p>
<p style="font-size:12px;">You can either use the exported file to re-import them into a different dictionary in Lexiconga, or taken and used somewhere else you might need them!</p>
<button type="button" onclick="ExportWords(); return false;">Export Words</button>
</div>
<div class="settingsCol">
<label>
<span>Full Dictionary</span>
<p style="font-size:12px;">This process exports the full dictionary, words and all information, in a ".dict" format to be re-imported back into Lexiconga as a new dictionary.</p>
<button type="button" onclick="ExportDictionary(); return false;">Export Dictionary</button>
</label>
</div>
</div>

23
IMPORT.form Normal file
View File

@ -0,0 +1,23 @@
<h2>Import</h2>
<div id="importOptions">
<div class="settingsCol">
<label>
<span>Word List</span>
</label>
<p style="font-size:12px;">This process imports words in a CSV format to the currently loaded dictionary. <small>(Note: You can save an Excel file as a CSV)</small></p>
<p style="font-size:12px;">The CSV file must have a header line in this order: word,pronunciation,part of speech,equivalent,explanation. Your word data must be in the appropriate order according to the headers. You can use <span class="clickable inline-button" onclick="download('import_template.csv','word,pronunciation,part of speech,equivalent,explanation\n');">this CSV file as a template</span> if you need help.</p>
<p style="font-size:12px;">Make sure the parts of speech for each word correspond to your dictionary's parts of speech or else you won't be able to find it using a filter. If a part of speech is left blank, you can find the blanks using the "Blank" option in the Filter so you can clean up.</p>
<p style="font-size:12px;">At a minimum, all of your words <em>must</em> have the "word" field <em>and</em> either the "equivalent" or "explanation" field filled out in the CSV file.</p>
<input type="file" id="importWordsCSV" />
<button type="button" onclick="ImportWords(); return false;">Import Words</button>
</div>
<div class="settingsCol">
<label>
<span>Full Dictionary</span>
<p style="font-size:12px;">This process imports a full dictionary previously exported from Lexiconga in a .dict format.</p>
<p style="font-size:12px;">All imported dictionaries are set to not be public by default, even if the source dictionary was public. Be sure to check the settings after importing to make sure everything is how you want it after importing.</p>
<input type="file" id="importFile" />
<button type="button" onclick="ImportDictionary(); return false;">Import Dictionary</button>
</label>
</div>
</div>

View File

@ -15,7 +15,7 @@
<h2>Create a New Account</h2>
<p style="font-size: 12px;">Creating an account allows you to save and switch between as many dictionaries as you need and access them from any device for free! If you have a dictionary you've been working on loaded already, it will automatically be uploaded to your account when you log in for the first time.</p>
<p style="font-size: 12px;">Plus if you allow us to send you emails, we'll make sure that you're the first to hear about any new features that get added or if any of our policies change for any reason. We'll never spam you or sell your information.</p>
<p style="font-size: 12px;">By creating an account, you are indicating that you agree to the <span class="clickable" onclick="ShowInfo('termsText')" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">Terms of Service</span> and that you understand Lexiconga's <span class="clickable" onclick="ShowInfo('privacyText')" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">Privacy Policy</span>.</p>
<p style="font-size: 12px;">By creating an account, you are indicating that you agree to the <span class="clickable inline-button" onclick="ShowInfo('termsText')">Terms of Service</span> and that you understand Lexiconga's <span class="clickable inline-button" onclick="ShowInfo('privacyText')">Privacy Policy</span>.</p>
<label><span>Email</span>
<input type="email" id="createAccountEmailField" name="email" />
</label>
@ -25,12 +25,12 @@
<label><span>Confirm Password</span>
<input type="password" id="createAccountPasswordConfirmField" name="confirmpassword" />
</label>
<label><span>Public Name <span class="clickable" onclick="ExplainPublicName()" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">?</span></span>
<label><span>Public Name <span class="clickable inline-button" onclick="ExplainPublicName()">?</span></span>
<input type="text" id="createAccountPublicNameField" name="publicname" />
</label>
<label style="display:inline;"><b>Allow Emails</b>
<input type="checkbox" id="createAccountAllowEmailsField" name="allowemails" checked="checked" />
</label> <span class="clickable" onclick="ExplainAllowEmails()" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">?</span>
</label> <span class="clickable inline-button" onclick="ExplainAllowEmails()">?</span>
<div id="createAccountError" style="font-weight:bold;color:red;"></div>
<button type="submit" id="createAccountSubmitButton" onclick="ValidateCreateAccount(); return false;">Create Account</button>
</form></div>

View File

@ -42,7 +42,7 @@ Some of the ads may be served by Google. Google's use of the DART cookie enables
### Changes to this privacy policy
Lexiconga Dictionary Builder has the discretion to update this privacy policy at any time. When we do, we will post a notification on the main page of our Site. We encourage Users to frequently check this page for any changes to stay informed about how we are helping to protect the personal information we collect. You acknowledge and agree that it is your responsibility to review this privacy policy periodically and become aware of modifications.
###Your acceptance of these terms
### Your acceptance of these terms
By using this Site, you signify your acceptance of this policy. If you do not agree to this policy, please do not use our Site. Your continued use of the Site following the posting of changes to this policy will be deemed your acceptance of those changes. This policy was originally generated using PrivacyPolicies.com and modified for our use.
### Contacting us

View File

@ -10,6 +10,7 @@
* [The Settings Menu](#the-settings-menu)
* [Search/Filter](#search-filter)
* [Keyboard Shortcuts](#keyboard-shortcuts)
* [Importing and Exporting](#importing-and-exporting)
* [Accounts](#accounts)
* [Creating An Account](#creating-an-account)
* [Logging In](#logging-in)
@ -59,7 +60,7 @@ After adding some words to your dictionary, you'll notice a link icon (🔗) and
The link icon (🔗) is a link to that word. These links only work when there is nothing entered in the search box and no filters are set. Also note that the links are only intended for linking within the same dictionary and will only work properly when your dictionary is loaded, so only share them with friends if your friends also have your dictionary imported.
The **Edit** button will scroll to the top of the screen and fill the Word form with the current details of the word you edited. You can make any changes you want and click the "Edit Word" button. You will be asked to confirm your changes, and once you do, your word will be saved. If you do not want to make changes, just click the "Cancel" button.
The **Edit** button will cause a form with the current details of the word you edited to display in the same space that the word previously appeared. You can make any changes you want and click the "Edit Word" button. You will be asked to confirm your changes, and once you do, your word will be saved. If you do not want to make changes, just click the "Cancel" button.
The **Delete** button will ask you to confirm that you want to delete the entry, and if you say yes, the word will be _permanently deleted and **cannot be retrieved**_.
@ -78,9 +79,7 @@ The **Dictionary is Complete** checkbox will make the word add/edit form go away
The **Total Entries** label is just a live tally of how many words you have added to the current dictionary.
The **Export Current Dictionary** button will immediately do exactly that. Your browser will start downloading a file with your dictionary's name in a ".dict" format. Please note that this may not work as expected on mobile platforms. This export can be a personal backup for your own uses, to work on multiple dictionaries at a time (i.e. export one dictionary and import the other to work on the one you'd like), or you can share it with friends to view it.
The **Import Dictionary** form allows you to upload and view any previously-exported ".dict" files. After selecting your ".dict" file, click the "Import" button to _overwrite your current dictionary_ and view the imported one. Again, please note that this import process will _**permanently overwrite your current dictionary**_, so please be sure to export your dictionary _before_ you import a new one.
The **Export...** and **Import...** buttons are discussed in the [Importing and Exporting](#importing-and-exporting) section below.
The **Empty Current Dictionary** should only be used if you want to completely start over from scratch. It will ask you to confirm that you want to delete, and if you confirm, your dictionary will be gone forever. If you have not exported your dictionary before emptying it, there will be absolutely no way to get it back. Please be careful with this!
@ -117,6 +116,23 @@ The "Filter Words" drop-down box allows you to filter your dictionary by part of
* **A** : Toggle Account Settings window (if logged in).
* **S** : Toggle Dicitonary Settings window. Saves & Closes if it's already open.
### Importing and Exporting
In the Settings screen, you may notice the buttons labeled "**Export...**" and "**Import...**". If you click on either of these, the respective Export and Import page will appear.
#### Exporting
Clicking the **"Export Words"** button will start a download of all of the words in the currently loaded dictionary into a convenient CSV file format that you can use to re-import into another Lexiconga dictionary or otherwise use as you need it! All of the data is wrapped in double quotes (`"`) to comply with standard CSV format.
Clicking the **"Export Dictionary"** button will start a download of a file with your dictionary's name in a ".dict" format. _Please note that this may not work as expected on mobile platforms._ This export can be a personal backup for your own uses, to work on multiple dictionaries at a time (i.e. export one dictionary and import the other to work on the one you'd like), or you can share it with friends to view it. The .dict file contains your whole dictionary in a JSON format, and is mainly only useful for importing back into Lexiconga.
#### Importing
Clicking the **"Import Words"** button after choosing a file allows you to import a correctly-formatted CSV list of words into your currently loaded dictionary. This can either be a previously-exported list of words from another Lexiconga dictionary or a list created in Excel with the correct column headers that has been saved as a CSV file. You can download a CSV file as a template from the Import page as an example to help you format and save your Excel lists properly.
Please note that when importing words, you must make sure that the parts of speech specified in the parts of speech column are written _exactly as they are in your dictionary settings_ (capitalized, spelled correctly, or any other details). If they are not the same, then you will not be able to use the filters to find the words! So if you import a word with the part of speech set to "adj" or "adjective", but the part of speech in your dictionary's settings is "Adjective", then you will not be able to find the word using the filters!
If you import a word _without_ a part of speech, you _can_ use the filter's "Blanks" option to find any words with empty parts of speech to help you clean up after the import.
Clicking the **"Import Dictionary"** button after choosing a file allows you to upload and view any previously-exported ".dict" files. After selecting your ".dict" file, click the "Import Dictionary" button to _overwrite your current dictionary_ and view the imported one. Again, please note that if you are not logged in, this import process will _**permanently overwrite your current dictionary**_, so please be sure to export your dictionary _before_ you import a new one!
## Accounts
If you are using an account with Lexiconga, your experience should remain essentially the same, but you will see some additional options in the Settings menu and you might notice some slight changes in performance as it saves to and loads from the database.
@ -156,9 +172,9 @@ The **Import Dictionary** button acts the same as before, but instead of overwri
The **Delete Current Dictionary** button will permanently and irretrievably delete the currently loaded dictionary from your account! Be careful with that one. After deleting, you will then be prompted to either select another dictionary to load or create a new one, _or_ if you have no other dictionaries, immediately create a new one for you.
#### Public Dictionaries
When a dictionary is marked as public, you can share its public link and allow anyone to view its contents without being able to make changes. The dictionary's description and the search/filter area is visible by default, and the viewer can scroll through or search your dictionary without being able to make changes.
When a dictionary is marked as public, you can share its public link and allow anyone to view its contents without being able to make changes. The dictionary's description and the search/filter area is visible by default, and the viewer can scroll through or search your dictionary without being able to make changes. Public dictionaries also have the ability to share specific word entries using the "➦" buttons in each word box. When viewing a word, the search/filter options are not available, but anyone can still read the dictionary's description.
To log in or create an account when viewing a dictionary, you need to go back to the main Lexiconga page. You can get there by clicking either the logo or the "Go Home" button.
To log in or create an account when viewing a dictionary, you need to go back to the main Lexiconga page. You can get there by clicking either the logo or the "Go Home" button. Or, if you are the owner of the dictionary and are currently logged in, the "Go Home" button will be replaced with an "Edit Dictionary" button, and you can click that to change your current dictionary adn start editing it.
### Forgot Your Password?
If you forget your password, you can request a password reset email by clicking the "Forgot Password" button on the "Log In/Create Account" button entering the email address associated with your account and clicking "Email Password Reset Key". This will send an email (_check your spam_) with a link that will allow you to reset your password. When you go to the link provided, you'll be able to enter a new password that you can log in with.
@ -167,16 +183,11 @@ If you forget your password, you can request a password reset email by clicking
If you manage to enter your password wrong 10 times, you'll be locked out from logging in for an hour. Use this time to try to remember your password or something. You can get an idea of how long you've waited by refreshing the page and clicking the unfortunate "Can't Login" button. After an hour has passed, refresh the page again and you'll get another 10 tries.
## Problems or Requests
Please report any problems you come across to the [Dictionary Builder Issues page](https://github.com/Alamantus/DictionaryBuilder/issues). You can also submit enhancement requests to the same place if you have any requests for new features.
Please report any problems you come across to the [Dictionary Builder Issues page](http://lexicon.ga/issues). You can also submit enhancement requests to the same place if you have any requests for new features.
## Update Log
You can see all previous updates to Lexiconga here:
[https://github.com/Alamantus/DictionaryBuilder/releases](https://github.com/Alamantus/DictionaryBuilder/releases/tag/Production)
## Future Plans
In the future, I'm planning to:
* enable account deletion if you lose trust or hope in Lexiconga's services
* provide an ad removal option?
[http://lexicon.ga/updates](http://lexicon.ga/updates)
## Thanks!
If you like Lexiconga and want to buy me a cup of coffee for the service, you can **[donate throughPaypal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=MCCSYGQCR5TLY&lc=US&item_name=Lexiconga&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)** to help keep it online if you want.
@ -188,4 +199,5 @@ I hope you enjoy Lexiconga and that it helps you build some awesome languages.
## Libraries Used
* [Marked.js](https://github.com/chjj/marked) by Christopher Jeffrey (JJ) (a.k.a. chjj)
* [Defiant.js](http://defiantjs.com) by Hakan Bilgin (a.k.a. hbi99)
* [Papa Parse](http://papaparse.com/) by Matt Holt (a.k.a. mholt)
* [removeDiacritics.js](http://stackoverflow.com/a/18391901/3508346) by [rdllopes](http://meta.stackoverflow.com/users/1879686/rdllopes)

View File

@ -1 +1 @@
The Filter system has been updated—you can now filter on as many parts of speech as you want!
<i><small>[Release Date]</small></i> | So much has been updated! Check the <a href="/updates" target="_blank">Updates page</a> to see all the changes!

View File

@ -6,8 +6,11 @@ header {
height: 50px;
width: 100%;
background: #eacc9d;
margin-bottom: 3px;
border-bottom: 3px solid #e3bb7d;
margin-bottom: 10px;
border: none;
-webkit-box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
-moz-box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
}
/* Smartphones (portrait and landscape) ----------- */
@ -42,7 +45,6 @@ a {
}
#aboutButton {
background: #dcb078;
}
#loginoutArea {
@ -86,69 +88,80 @@ and (max-device-width : 480px) {
}
#wordEntryForm {
background: #c05d5d;
border-color: #c08d8d #b00d0d #b00d0d #c08d8d;
background: #ba5536;
-webkit-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
border: none;
}
input, textarea, select, option, button {
input, textarea, select, option {
background: #efdfc0;
}
#announcementArea {
background:#a0c066;
background: #a0c066;
}
#notificationArea {
background:#c0c088;
background: #c0c088;
}
#dictionaryContainer {
background: #bd7251;
padding: 15px;
border: outset;
border-color: #d09b84 #915237 #915237 #d09b84;
border: none;
-webkit-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
}
#dictionaryDescription, .management, #settingsOptions, #infoPage, #loadAfterDeletePage,
#accountSettingsPage, #fullScreenTextboxPage {
#settingsOptions, #infoPage, #loadAfterDeletePage, #accountSettingsPage, #fullScreenTextboxPage {
background: #f2d5b2;
}
.management {
border-width: 2px;
border-color: #ebbe87 #f9ecdd #f9ecdd #ebbe87;
border: none;
}
#dictionaryName {
text-shadow: 2px 2px 2px #915337;
}
#dictionaryDescription {
width: 90%;
#dictionaryShareLink {
text-shadow: none;
}
#loginLink, #logoutLink,
#descriptionToggle, #searchFilterToggle, #settingsButton,
.deleteCancelButton, .deleteConfirmButton,
#settingsScreenCloseButton, #infoScreenCloseButton,
.clickable, .helperlink {
background: #e0c19c;
#dictionaryDescription {
width: 90%;
background: #f2d5b2;
}
#loginLink, #logoutLink, #descriptionToggle, #searchFilterToggle, #settingsButton, .deleteCancelButton, .deleteConfirmButton, #settingsScreenCloseButton, #infoScreenCloseButton, .clickable, button {
background: #dcb078;
}
entry {
background: #d7ad7d;
border-color: #e7cfb3 #c78b47 #c78b47 #e7cfb3;
border: none;
-webkit-box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
-moz-box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
box-shadow: 3px 3px 10px -1px rgba(0,0,0,0.75);
}
.editButton {
background: #89cb89;
background: #86ac41;
}
.deleteButton {
background: #cc8888;
background: #ba5536;
}
footer {
background: #d69c42;
border-top: 3px solid #e3bb7d;
background: #cb6318;
border: none;
-webkit-box-shadow: 0px -3px 7px -1px rgba(0,0,0,0.75);
-moz-box-shadow: 0px -3px 7px -1px rgba(0,0,0,0.75);
box-shadow: 0px -3px 7px -1px rgba(0,0,0,0.75);
}

View File

@ -1,8 +1,8 @@
body {
body {
padding: 0;
margin: 0;
border: none;
font-family: Georgia, 'Times New Roman', Times, serif;
font-family: "Helvetica", Arial, sans-serif;
}
contents {
@ -18,7 +18,7 @@ footer {
bottom: 0px;
left: 0px;
background: #aaaaaa;
padding: 6px;
padding: 8px;
max-height: 32px; /* Update Dictionary Container's bottom margin to account for footer */
}
@ -72,10 +72,6 @@ label span {
font-weight: bold;
}
label span .helperlink {
font-size: 10px;
}
label label {
margin-left: 20px;
}
@ -87,7 +83,9 @@ label span.checkboxlabel {
input, textarea {
display: block;
padding-left: 5px;
padding: 2px 0 2px 5px;
border: none;
margin: 2px 0;
}
input[type=checkbox] {
@ -95,7 +93,7 @@ input[type=checkbox] {
margin: 5px;
}
#longDefinition {
.longDefinition {
width: 80%;
min-width: 260px;
height: 150px;
@ -141,17 +139,19 @@ input[type=checkbox] {
#announcementArea, #notificationArea {
text-align:center;
padding:10px;
border-radius:5px;
margin:0 auto;
width:50%;
min-width:200px;
-webkit-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
}
#dictionaryContainer {
margin: 15px 0 36px 15px; /* bottom margin must clear footer */
width: 60%;
min-width: 260px;
max-width: 600px;
max-width: 800px;
float: left;
}
@ -159,34 +159,44 @@ input[type=checkbox] {
margin: 0 0 5px;
}
#dictionaryShareLink {
margin-left: 10px;
vertical-align: middle;
text-decoration: none;
}
#dictionaryDescription {
width: 100%;
max-height: 400px;
overflow-y: auto;
padding: 15px;
border: 1px solid #cacaca;
border: none;
margin: 10px;
}
.clickable, .helperlink {
.clickable, button {
display: inline;
font-weight: bold;
font-size: 13px;
padding: 4px;
padding: 5px;
border: none;
background: #dddddd;
border-radius: 5px;
}
.clickable {
.clickable, button {
cursor: pointer;
}
#descriptionToggle, #searchFilterToggle {
.inline-button {
font-size: 11px;
padding: 2px 4px;
}
.toggleButton {
display: inline-block;
margin: 8px;
font-weight: bold;
font-size: 12px;
cursor: pointer;
}
.searchOption, .filterOption {
@ -323,8 +333,8 @@ searchTerm {
left: 0;
width: 100%;
height: 100%;
background: #aaaaaa;
opacity: 0.75;
background: #000000;
opacity: 0.6;
}
#settingsOptions, #infoPage, #loadAfterDeletePage,
@ -341,12 +351,14 @@ searchTerm {
overflow-x: hidden;
background: #ffffff;
opacity: 1;
border-radius: 5px;
border: 1px solid black;
border: none;
-webkit-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
box-shadow: 5px 5px 7px 0px rgba(0,0,0,0.75);
}
#announcementCloseButton, #notificationCloseButton,
#settingsButton, #settingsScreenCloseButton,
#settingsButton, #settingsScreenCloseButton, #accountSettingsScreenCloseButton,
#settingsSaveButtons button, #infoScreenCloseButton,
#fullScreenTextboxScreenCloseButton {
float: right;

4
import_test.csv Normal file
View File

@ -0,0 +1,4 @@
word,pronunciation,part of speech,equivalent,explanation
test0, [tehst], ,dah,
test1, [tehst], a ,dah,
test2, [tehst], a ,dah,
1 word pronunciation part of speech equivalent explanation
2 test0 [tehst] dah
3 test1 [tehst] a dah
4 test2 [tehst] a dah

292
index.php
View File

@ -4,6 +4,19 @@ require_once('required.php');
session_start();
$current_user = isset($_SESSION['user']) ? $_SESSION['user'] : 0;
$dictionary_to_load = (isset($_GET['dict'])) ? intval($_GET['dict']) : 0;
$the_public_dictionary = '"That dictionary doesn\'t exist."';
$dictionary_name = 'ERROR';
$dictionary_creator = 'nobody';
$word_to_load = (isset($_GET['word'])) ? intval($_GET['word']) : 0;
$the_public_word = '"That word doesn\'t exist."';
$word_name = 'ERROR';
$is_owner = false;
$display_mode = ($dictionary_to_load > 0) ? (($word_to_load > 0) ? "word" : "view") : "build";
$announcement = get_include_contents(SITE_LOCATION . '/announcement.php');
$notificationMessage = "";
@ -17,6 +30,70 @@ if ($current_user > 0 || !isset($_SESSION['loginfailures']) || (isset($_SESSION[
require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
if ($display_mode != "build") {
$dbconnection = new PDO('mysql:host=' . DATABASE_SERVERNAME . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD);
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$dictionary_query = "SELECT `d`.`id`, `d`.`user`, `d`.`name`, `d`.`description`, `u`.`public_name`, `d`.`parts_of_speech`, `d`.`is_complete` ";
$dictionary_query .= "FROM `dictionaries` AS `d` LEFT JOIN `users` AS `u` ON `d`.`user`=`u`.`id`";
$dictionary_query .= "WHERE `d`.`is_public`=1 AND `d`.`id`=" . $dictionary_to_load . ";";
$word_query = "SELECT `w`.`word_id`, `w`.`name`, `w`.`pronunciation`, `w`.`part_of_speech`, `w`.`simple_definition`, `w`.`long_definition` ";
$word_query .= "FROM `words` AS `w` LEFT JOIN `dictionaries` AS `d` ON `w`.`dictionary`=`d`.`id` ";
$word_query .= "WHERE `d`.`is_public`=1 AND `w`.`dictionary`=" . $dictionary_to_load . (($display_mode == "word") ? " AND `w`.`word_id`=" . $word_to_load : "") . " ";
$word_query .= "ORDER BY IF(`d`.`sort_by_equivalent`, `w`.`simple_definition`, `w`.`name`) COLLATE utf8_unicode_ci;";
try {
$dictionary_results = $dbconnection->prepare($dictionary_query);
$dictionary_results->execute();
if ($dictionary_results) {
$word_results = $dbconnection->prepare($word_query);
$word_results->execute();
$dictionary_words = "[";
if ($word_results) {
$words_counted = 0;
$words_total = num_rows($word_results);
while ($word = fetch($word_results)) {
$words_counted++;
$word_name = $word['name'];
$dictionary_words .= '{"name":"' . $word['name'] . '",';
$dictionary_words .= '"pronunciation":"' . $word['pronunciation'] . '",';
$dictionary_words .= '"partOfSpeech":"' . $word['part_of_speech'] . '",';
$dictionary_words .= '"simpleDefinition":"' . $word['simple_definition'] . '",';
$dictionary_words .= '"longDefinition":"' . $word['long_definition'] . '",';
$dictionary_words .= '"wordId":"' . $word['word_id'] . '"';
$dictionary_words .= '}';
if ($words_counted < $words_total) {
$dictionary_words .= ',';
}
}
}
$dictionary_words .= "]";
if (num_rows($dictionary_results) === 1) {
while ($dict = fetch($dictionary_results)) {
$dictionary_name = $dict['name'];
$dictionary_creator = $dict['public_name'];
$is_owner = $current_user == $dict['user'];
$the_public_dictionary = '{"name":"' . $dict['name'] . '",';
$the_public_dictionary .= '"description":"' . $dict['description'] . '",';
$the_public_dictionary .= '"createdBy":"' . $dict['public_name'] . '",';
$the_public_dictionary .= '"words":' . $dictionary_words . ',';
$the_public_dictionary .= '"settings":{';
$the_public_dictionary .= '"partsOfSpeech":"' . $dict['parts_of_speech'] . '",';
$the_public_dictionary .= '"isComplete":' . (($dict['is_complete'] == 1) ? 'true' : 'false') . '},';
$the_public_dictionary .= '"id":"' . $dictionary_to_load . '"';
$the_public_dictionary .= '}';
}
}
}
}
catch (PDOException $ex) {}
}
?>
<!DOCTYPE html>
<html>
@ -24,10 +101,25 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Lexiconga Dictionary Builder</title>
<?php if ($display_mode != "build") { ?>
<title><?php echo (($display_mode == "word") ? ($word_name . " | ") : "") . $dictionary_name; ?> Dictionary on Lexiconga</title>
<meta property="og:url" content="http://lexicon.ga/<?php echo $dictionary_to_load . (($display_mode == "word") ? ("/" . $word_to_load) : ""); ?>" />
<meta property="og:type" content="article" />
<meta property="og:title" content="<?php echo (($display_mode == "word") ? ("\"" . $word_name . "\" in the ") : "") . $dictionary_name; ?> Dictionary" />
<meta property="og:description" content="A Lexiconga dictionary by <?php echo $dictionary_creator; ?>" />
<meta property="og:image" content="http://lexicon.ga/images/logo.svg" />
<script>var publicDictionary = <?php echo $the_public_dictionary; ?></script>
<?php } else { ?>
<title>Lexiconga Dictionary Builder</title>
<meta property="og:url" content="http://lexicon.ga" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Lexiconga Dictionary Builder" />
<meta property="og:description" content="Build lexicons for contructed languages or anything that you can think of!" />
<meta property="og:image" content="http://lexicon.ga/images/logo.svg" />
<?php } ?>
<link href="css/styles.css" rel="stylesheet" />
<link href="css/lexiconga.css" rel="stylesheet" />
<link href="/css/styles.css" rel="stylesheet" />
<link href="/css/lexiconga.css" rel="stylesheet" />
</head>
<body>
<header>
@ -37,17 +129,27 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<span id="aboutButton" class="clickable" onclick="ShowInfo('aboutText')">About Lexiconga</span>
</div>
<div id="loginoutArea" style="font-size:12px;">
<?php if ($display_mode == "build") { ?>
<?php if ($current_user > 0) { //If logged in, show the log out button. ?>
<span id="accountSettings" class="clickable" onclick="ShowAccountSettings()">Account Settings</span> <a href="?logout" id="logoutLink" class="clickable">Log Out</a>
<?php } elseif (!isset($_SESSION['loginfailures']) || (isset($_SESSION['loginfailures']) && $_SESSION['loginfailures'] < 10)) { ?>
<span id="loginLink" class="clickable" onclick="ShowInfo('loginForm')">Log In/Create Account</span>
<?php } else { ?>
<span id="loginLink" class="clickable" title="<?php echo $hoverlockoutmessage; ?>" onclick="alert('<?php echo $alertlockoutmessage; ?>');">Can't Login</span>
<?php } ?>
<?php }
} else { ?>
<h3 style="display:inline; margin:0 5px;">Viewing</h3>
<?php if ($is_owner) { ?>
<span class="clickable" onclick="ChangeDictionaryToId(<?php echo $dictionary_to_load; ?>, function(response) {if (response.length >= 60) window.location.href = '/';});">&laquo; Edit Dictionary</span>
<?php } else { ?>
<a class="clickable" href="/">&laquo; Go Home to Lexiconga</a>
<?php }?>
<?php } ?>
</div>
</div>
</header>
<contents>
<?php if ($display_mode == "build") { ?>
<div id="announcementArea" style="display:<?php echo (($announcement) ? "block" : "none"); ?>;margin-bottom:10px;">
<span id="announcementCloseButton" class="clickable" onclick="document.getElementById('announcementArea').style.display='none';">Close</span>
<div id="announcement"><?php echo $announcement; ?></div>
@ -57,60 +159,72 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<div id="notificationMessage"><?php echo $notificationMessage; ?></div>
</div>
<div id="leftColumn">
<form id="wordEntryForm">
<div id="formLockButton" class="clickable" onclick="ToggleWordFormLock()" title="Lock/unlock form from the top of the page">&#128274;</div>
<label><span>Word</span>
<input type="text" id="word" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Pronunciation <a class="helperlink" href="/ipa_character_picker/" target="_blank" title="IPA Character Picker backed up from http://r12a.github.io/pickers/ipa/">IPA Characters</a></span>
<input type="text" id="pronunciation" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Part of Speech</span>
<select id="partOfSpeech" onkeydown="SubmitWordOnCtrlEnter(this)"></select>
</label>
<label><span>Equivalent Word(s)</span>
<input type="text" id="simpleDefinition" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Explanation/Long Definition <span id="showFullScreenTextbox" class="clickable" onclick="ShowFullScreenTextbox('longDefinition', 'Explanation/Long Definition')">Maximize</span></span>
<textarea id="longDefinition" onkeydown="SubmitWordOnCtrlEnter(this)"></textarea>
</label>
<input type="hidden" id="editIndex" />
<span id="errorMessage"></span>
<div id="newWordButtonArea" style="display: block;">
<button type="button" onclick="AddWord(); return false;">Add Word</button>
</div>
<div id="editWordButtonArea" style="display: none;">
<button type="button" onclick="AddWord(); return false;">Edit Word</button> <button type="button" onclick="ClearForm(); window.scroll(savedScroll.x, savedScroll.y); return false;">Cancel</button>
</div>
<div id="updateConflict" style="display: none;"></div>
</form>
<form id="wordEntryForm">
<div id="formLockButton" class="clickable" onclick="ToggleWordFormLock()" title="Lock/unlock form from the top of the page">&#128274;</div>
<label><span>Word</span>
<input type="text" id="word" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Pronunciation <a class="clickable inline-button" href="http://r12a.github.io/pickers/ipa/" target="_blank" title="IPA Character Picker located at http://r12a.github.io/pickers/ipa/">IPA Characters</a></span>
<input type="text" id="pronunciation" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Part of Speech</span>
<select id="partOfSpeech" onkeydown="SubmitWordOnCtrlEnter(this)"></select>
</label>
<label><span>Equivalent Word(s)</span>
<input type="text" id="simpleDefinition" onkeydown="SubmitWordOnCtrlEnter(this)" />
</label>
<label><span>Explanation/Long Definition <span id="showFullScreenTextbox" class="clickable inline-button" onclick="ShowFullScreenTextbox('longDefinition', 'Explanation/Long Definition')">Maximize</span></span>
<textarea id="longDefinition" class="longDefinition" onkeydown="SubmitWordOnCtrlEnter(this)"></textarea>
</label>
<input type="hidden" id="editIndex" />
<span id="errorMessage"></span>
<div id="newWordButtonArea" style="display: block;">
<button type="button" onclick="AddWord(); return false;">Add Word</button>
</div>
<div id="editWordButtonArea" style="display: none;">
<button type="button" onclick="AddWord(); return false;">Edit Word</button> <button type="button" onclick="ClearForm(); window.scroll(savedScroll.x, savedScroll.y); return false;">Cancel</button>
</div>
<div id="updateConflict" style="display: none;"></div>
</form>
</div>
<?php } ?>
<div id="dictionaryContainer">
<?php if ($display_mode == "build") { ?>
<span id="settingsButton" class="clickable" onclick="ShowSettings()">Settings</span>
<?php } ?>
<h1 id="dictionaryName"></h1>
<?php if ($display_mode != "build") { ?>
<h4 id="dictionaryBy"></h4>
<div id="incompleteNotice"></div>
<?php } ?>
<span id="descriptionToggle" class="clickable" onclick="ToggleDescription();">Show Description</span>
<div id="dictionaryDescription" style="display:none;"></div>
<?php if ($display_mode == "word") { ?>
<a class="clickable toggleButton" href="/<?php echo $dictionary_to_load; ?>">View Full Dictionary</a>
<?php } ?>
<span id="descriptionToggle" class="clickable toggleButton" onclick="ToggleDescription();"><?php if ($display_mode == "view") { ?>Hide<?php } else { ?>Show<?php } ?> Description</span>
<div id="dictionaryDescription" style="display:<?php if ($display_mode == "view") { ?>block<?php } else { ?>none<?php } ?>;"></div>
<span id="searchFilterToggle" class="clickable" onclick="ToggleSearchFilter();">Search/Filter Options</span>
<div id="searchFilterArea" style="display:none;">
<?php if ($display_mode != "word") { ?>
<span id="searchFilterToggle" class="clickable toggleButton" onclick="ToggleSearchFilter();"><?php if ($display_mode == "view") { ?>Hide <?php } ?>Search/Filter Options</span>
<div id="searchFilterArea" style="display:<?php if ($display_mode == "view") { ?>block<?php } else { ?>none<?php } ?>;">
<div id="searchArea" style="display:block;">
<label style="margin-top:10px;">
<span>Search</span>
<div style="display:block;">
<input type="text" id="searchBox" onclick="this.select();" onchange="ShowDictionary()" style="display:inline;" />&nbsp;
<span style="display:inline;cursor:pointer;font-size:10px;font-weight:bold;" onclick="document.getElementById('searchBox').value='';ShowDictionary();">Clear Search</span>
<input type="text" id="searchBox" onclick="this.select();" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" style="display:inline;" />&nbsp;
<span class="clickable inline-button" onclick="document.getElementById('searchBox').value='';<?php Show_Dictionary_Function($display_mode == "view") ?>;">Clear Search</span>
</div>
<div id="searchOptions">
<label class="searchOption">Word <input type="checkbox" id="searchOptionWord" checked="checked" onchange="ShowDictionary()" /></label>
<label class="searchOption">Equivalent <input type="checkbox" id="searchOptionSimple" checked="checked" onchange="ShowDictionary()" /></label>
<label class="searchOption">Explanation <input type="checkbox" id="searchOptionLong" checked="checked" onchange="ShowDictionary()" /></label>
<label class="searchOption">Word <input type="checkbox" id="searchOptionWord" checked="checked" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" /></label>
<label class="searchOption">Equivalent <input type="checkbox" id="searchOptionSimple" checked="checked" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" /></label>
<label class="searchOption">Explanation <input type="checkbox" id="searchOptionLong" checked="checked" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" /></label>
<br />
<label class="searchOption">Search Case-Sensitive <input type="checkbox" id="searchCaseSensitive" onchange="ShowDictionary()" /></label>
<label class="searchOption" title="Note: Matching diacritics will appear but may not highlight.">Ignore Diacritics/Accents <input type="checkbox" id="searchIgnoreDiacritics" onchange="ShowDictionary()" /></label>
<label class="searchOption">Search Case-Sensitive <input type="checkbox" id="searchCaseSensitive" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" /></label>
<label class="searchOption" title="Note: Matching diacritics will appear but may not highlight.">Ignore Diacritics/Accents <input type="checkbox" id="searchIgnoreDiacritics" onchange="<?php Show_Dictionary_Function($display_mode == "view") ?>" /></label>
</div>
</label>
</div>
@ -118,10 +232,17 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<label style="display:block;margin-bottom:0;"><b>Filter Words</b></label>
<div id="filterOptions" style="display:block"></div>
<div style="display:block;">
<span style="display:inline;cursor:pointer;font-size:12px;font-weight:bold;" onclick="ToggleAllFilters(true);ShowDictionary();">Check All</span>&nbsp;/&nbsp;<span style="display:inline;cursor:pointer;font-size:12px;font-weight:bold;" onclick="ToggleAllFilters(false);ShowDictionary();">Uncheck All</span>
<span class="clickable inline-button" onclick="ToggleAllFilters(true);<?php Show_Dictionary_Function($display_mode == "view") ?>;">
Check All
</span>
&nbsp;
<span class="clickable inline-button" onclick="ToggleAllFilters(false);<?php Show_Dictionary_Function($display_mode == "view") ?>;">
Uncheck All
</span>
</div>
</div>
<div id="filterWordCount"></div>
<?php } ?>
<div id="theDictionary"></div>
</div>
@ -130,6 +251,8 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<?php if ($_GET['adminoverride'] != "noadsortracking") { include_once("php/google/adsense.php"); } ?>
</div>
<?php if ($display_mode == "build") { ?>
<div id="settingsScreen" style="display:none;">
<div id="settingsBackgroundFade" onclick="HideSettings()"></div>
<div id="settingsOptions">
@ -142,7 +265,7 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<span>Dictionary Name</span>
<input type="text" id="dictionaryNameEdit" />
</label>
<label><span>Dictionary Details <span id="showFullScreenTextbox" class="clickable" onclick="ShowFullScreenTextbox('dictionaryDescriptionEdit', 'Dictionary Details')">Maximize</span></span>
<label><span>Dictionary Details <span id="showFullScreenTextbox" class="clickable inline-button" onclick="ShowFullScreenTextbox('dictionaryDescriptionEdit', 'Dictionary Details')">Maximize</span></span>
<textarea id="dictionaryDescriptionEdit"></textarea>
</label>
@ -161,7 +284,7 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<label class="inline">
<span class="checkboxlabel">Sort by Equivalent Word</span>
<input type="checkbox" id="dictionarySortByEquivalent" />
</label> <span class="helperlink clickable" onclick='alert("By default, your dictionary is organized alphabetically by word. Checking this box will organize it by the \"Equivalent Word\" field instead");'>?</span>
</label> <span class="clickable inline-button" onclick='alert("By default, your dictionary is organized alphabetically by word. Checking this box will organize it by the \"Equivalent Word\" field instead");'>?</span>
</div>
<br>
<label>
@ -172,7 +295,7 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<label class="inline">
<span class="checkboxlabel">Dictionary is Public</span>
<input type="checkbox" id="dictionaryIsPublic" onchange="TogglePublicLink()" />
</label> <span class="helperlink clickable" onclick='alert("If you save your settings with this checked, your dictionary will be viewable by anyone if they have the public link.");'>?</span>
</label> <span class="clickable inline-button" onclick='alert("If you save your settings with this checked, your dictionary will be viewable by anyone if they have the public link.");'>?</span>
<div id="publicLink"></div>
<?php } ?>
</div>
@ -180,18 +303,17 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<label>
<b>Total Entries:</b> <i id="numberOfWordsInDictionary"></i>
</label>
<label><button type="button" onclick="ExportDictionary()" style="cursor:pointer;">Export Current Dictionary</button></label>
<br>
<?php if ($current_user > 0) { //If logged in, show the special options. ?>
<label><span>Change Dictionaries</span>
<select id="userDictionaries" onchange="ChangeDictionary();"></select>
</label>
<br>
<label><button type="button" onclick="CreateNewDictionary()" style="cursor:pointer;">Create a New Dictionary</button></label>
<?php } ?>
<label>
<span>Import Dictionary</span>
<input type="file" id="importFile" />
<button type="button" onclick="ImportDictionary(); return false;">Import</button>
</label>
<label style="display:inline-block;margin-right:8px;"><button type="button" onclick="ShowInfo('exportForm')">Export...</button></label>
<label style="display:inline-block;"><button type="button" onclick="ShowInfo('importForm')">Import...</button></label>
<br><br>
<?php if ($current_user > 0) { //If logged in, show the log out button. ?>
<label><button type="button" onclick="DeleteCurrentDictionary()" style="cursor:pointer;">Delete Current Dictionary</button></label>
<?php } else { //If logged in, show the log out button. ?>
@ -201,7 +323,7 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<div id="settingsSaveButtons">
<span id="settingsErrorMessage"></span><br>
<button type="button" onclick="SaveSettings(); HideSettings(); return false;">Save and Close</button>
<button type="button" onclick="SaveSettings(); return false;">Save</button>
<button type="button" onclick="SaveSettings(); return false;" style="margin-right:2px;">Save</button>
</div>
</form>
</div>
@ -216,6 +338,8 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<textarea id="fullScreenTextbox"></textarea>
</div>
</div>
<?php } ?>
<div id="infoScreen" style="display:none;">
<div id="infoBackgroundFade" onclick="HideInfo()"></div>
@ -239,25 +363,29 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<input type="hidden" id="accountSettingsPreviousEmailField" name="previousemail" value="<?php echo $user_email; ?>" />
</label>
<div id="accountSettingsEmailChangeWarning" style="display:none;font-weight:bold;color:#dd5500;font-size:11px;margin-bottom:10px;">If you change your email address, please note that you will no longer be able to log in with your old email address, <?php echo $user_email; ?>.<br>Change it back unless you are completely sure that you want to change your email address!</div>
<label><span>Public Name <span class="clickable" onclick="ExplainPublicName()" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">?</span></span>
<label><span>Public Name <span class="clickable inline-button" onclick="ExplainPublicName()">?</span></span>
<input type="text" id="accountSettingsPublicNameField" name="publicname" value="<?php echo Get_Public_Name_By_Id($current_user); ?>" />
</label>
<label style="display:inline;"><b>Allow Emails</b>
<input type="checkbox" id="createAccountAllowEmailsField" name="allowemails" checked="checked" />
</label> <span class="clickable" onclick="ExplainAllowEmails()" style="font-size:11px;vertical-align:top;background:#e0c19c;padding:4px 7px;">?</span>
</label> <span class="clickable inline-button" onclick="ExplainAllowEmails()">?</span>
<div id="accountSettingsError" style="font-weight:bold;color:red;"></div>
<button type="submit" id="accountSettingsSubmitButton" onclick="ValidateAccountSettings(); return false;">Save Settings</button>
<br><br>
<br>
</form></div>
<div class="settingsCol">
<br>
<h2>Reset Your Password</h2>
<p style="font-size: 12px;">Click the button below to reload the page and show the Reset Password form. Filling out this form will instantly change your password, and you will need to log in using the new password from that point forward.</p>
<span id="resetPassword" class="clickable" onclick="this.innerHTML='Loading...';LoggedInResetPassword();" style="margin-top:20px;">Reset Password</span>
</form></div>
</div>
</div>
</div>
<?php
}
?>
<?php if ($display_mode == "build") { ?>
<div id="loadAfterDeleteScreen" style="display:none;">
<div id="loadAfterDeleteFade"></div>
<div id="loadAfterDeletePage">
@ -267,34 +395,60 @@ require_once(SITE_LOCATION . '/php/notificationconditiontree.php');
<select id="loadAfterDelete" onchange="ChangeDictionary(this);document.getElementById('loadAfterDeleteScreen').style.display = 'none';"></select>
</label>
<p>Or</p>
<label><button type="button" onclick="CreateNewDictionary();document.getElementById('loadAfterDeleteScreen').style.display = 'none';" style="cursor:pointer;">Create a New Dictionary</button></label>
<label><button type="button" onclick="CreateNewDictionary();document.getElementById('loadAfterDeleteScreen').style.display = 'none';">Create a New Dictionary</button></label>
</div>
</div>
</div>
<?php } ?>
</contents>
<footer>
Dictionary Builder only guaranteed to work with most up-to-date HTML5 browsers. <a href="https://github.com/Alamantus/DictionaryBuilder/issues" target="_blank">Report a Problem</a> | <span class="clickable" onclick="ShowInfo('termsText')" style="font-size:12px;">Terms</span> <span class="clickable" onclick="ShowInfo('privacyText')" style="font-size:12px;">Privacy</span>
Dictionary Builder only guaranteed to work with most up-to-date HTML5 browsers. <a href="/issues" class="clickable" target="_blank">Issues</a> <a href="/updates" class="clickable" target="_blank">Updates</a> | <span class="clickable" onclick="ShowInfo('termsText')" style="font-size:12px;">Terms</span> <span class="clickable" onclick="ShowInfo('privacyText')" style="font-size:12px;">Privacy</span>
</footer>
<!-- Markdown Parser -->
<script src="js/marked.js"></script>
<script src="/js/marked.js"></script>
<!-- CSV Parser -->
<script src="/js/papaparse.js"></script>
<!-- JSON Search -->
<script src="js/defiant.js"></script>
<script src="/js/defiant.js"></script>
<!-- Diacritics Removal for Exports -->
<script src="js/removeDiacritics.js"></script>
<script src="/js/removeDiacritics.js"></script>
<!-- Helper Functions -->
<script src="js/helpers.js"></script>
<script src="/js/helpers.js"></script>
<!-- Main Functions -->
<script src="js/dictionaryBuilder.js"></script>
<script src="/js/dictionaryBuilder.js"></script>
<!-- UI Functions -->
<script src="js/ui.js"></script>
<script src="/js/ui.js"></script>
<?php if ($display_mode != "build") { ?>
<!-- Public View Functions -->
<script src="/js/publicView.js"></script>
<?php } ?>
<?php if ($_GET['adminoverride'] != "noadsortracking") { include_once("php/google/analytics.php"); } ?>
<script>
var aboutText = termsText = privacyText = loginForm = forgotForm = "Loading...";
var aboutText = termsText = privacyText = loginForm = forgotForm = exportForm = importForm = "Loading...";
<?php if ($display_mode != "build") { ?>
window.onload = function () {
ShowPublicDictionary(<?php if ($display_mode == "word") echo "true"; ?>);
<?php
if ($display_mode != "word") { // don't try to set the filters
echo "SetPublicPartsOfSpeech()";
} ?>
GetTextFile("/README.md", "aboutText", true);
GetTextFile("/TERMS.md", "termsText", true);
GetTextFile("/PRIVACY.md", "privacyText", true);
GetTextFile("/LOGIN.form", "loginForm", false);
GetTextFile("/FORGOT.form", "forgotForm", false);
GetTextFile("/EXPORT.form", "exportForm", false);
GetTextFile("/IMPORT.form", "importForm", false);
}
<?php } else { ?>
ready(function() {
Initialize();
});
});
<?php } ?>
var loggedIn = <?php echo ($current_user > 0) ? "true" : "false"; ?>;
</script>
</body>
</html>

View File

@ -34,7 +34,7 @@ function AddWord() {
var partOfSpeech = htmlEntities(document.getElementById("partOfSpeech").value).trim();
var simpleDefinition = htmlEntities(document.getElementById("simpleDefinition").value).trim();
var longDefinition = htmlEntities(document.getElementById("longDefinition").value);
var editIndex = htmlEntities(document.getElementById("editIndex").value);
// var editIndex = htmlEntities(document.getElementById("editIndex").value);
var errorMessageArea = document.getElementById("errorMessage");
var errorMessage = "";
var updateConflictArea = document.getElementById("updateConflict");
@ -42,26 +42,10 @@ function AddWord() {
if (word != "" && (simpleDefinition != "" || longDefinition != "")) {
var wordIndex = (!currentDictionary.settings.allowDuplicates) ? WordIndex(word) : -1;
if (editIndex != "") {
if (WordAtIndexWasChanged(editIndex, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition)) {
document.getElementById("editWordButtonArea").style.display = "none";
DisableForm();
updateConflictArea.style.display = "block";
updateConflictArea.innerHTML = "<span id='updateConflictMessage'>Do you really want to change the word \"" + currentDictionary.words[parseInt(editIndex)].name + "\" to what you have set above?</span>";
updateConflictArea.innerHTML += '<button type="button" id="updateConfirmButton" \
onclick="UpdateWord(' + editIndex + ', \'' + htmlEntities(word) + '\', \'' + htmlEntities(pronunciation) + '\', \'' + htmlEntities(partOfSpeech) + '\', \'' + htmlEntities(simpleDefinition) + '\', \'' + htmlEntities(longDefinition) + '\'); \
return false;">Yes, Update it</button>';
updateConflictArea.innerHTML += '<button type="button" id="updateCancelButton" onclick="CloseUpdateConflictArea(\'editWordButtonArea\'); return false;">No, Leave it</button>';
} else {
errorMessage = "No change has been made to \"" + word + "\"";
if (currentDictionary.words[parseInt(editIndex)].name != word) {
errorMessage += ". (Your dictionary is currently set to ignore case.)"
}
}
} else if (wordIndex >= 0) {
if (wordIndex >= 0) {
if (WordAtIndexWasChanged(wordIndex, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition)) {
document.getElementById("newWordButtonArea").style.display = "none";
DisableForm();
DisableForm('');
updateConflictArea.style.display = "block";
var updateConflictText = "<span id='updateConflictMessage'>\"" + word + "\" is already in the dictionary";
@ -74,7 +58,7 @@ function AddWord() {
updateConflictText += '<button type="button" id="updateConfirmButton" \
onclick="UpdateWord(' + wordIndex + ', \'' + htmlEntities(word) + '\', \'' + htmlEntities(pronunciation) + '\', \'' + htmlEntities(partOfSpeech) + '\', \'' + htmlEntities(simpleDefinition) + '\', \'' + htmlEntities(longDefinition) + '\'); \
return false;">Yes, Update it</button>';
updateConflictText += ' <button type="button" id="updateCancelButton" onclick="CloseUpdateConflictArea(\'newWordButtonArea\'); return false;">No, Leave it</button>';
updateConflictText += ' <button type="button" id="updateCancelButton" onclick="CloseUpdateConflictArea(\'\'); return false;">No, Leave it</button>';
updateConflictArea.innerHTML = updateConflictText;
} else {
@ -84,10 +68,10 @@ function AddWord() {
}
}
} else {
currentDictionary.words.push({name: word, pronunciation: pronunciation, partOfSpeech: partOfSpeech, simpleDefinition: simpleDefinition, longDefinition: longDefinition, wordId: currentDictionary.nextWordId++});
currentDictionary.words.push({name: word, pronunciation: pronunciation, partOfSpeech: ((partOfSpeech.length > 0) ? partOfSpeech : " "), simpleDefinition: simpleDefinition, longDefinition: longDefinition, wordId: currentDictionary.nextWordId++});
SaveAndUpdateWords("new");
FocusAfterAddingNewWord();
NewWordNotification(word);
SaveAndUpdateDictionary(false);
}
errorMessageArea.innerHTML = "";
@ -107,33 +91,81 @@ function AddWord() {
errorMessageArea.innerHTML = errorMessage;
}
function EditWord(index) {
SaveScroll();
if (wordFormIsLocked()) {
window.scroll(0, 0);
function ShowWordEditForm(index) {
var indexString = index.toString(); // Variable for reduced processing
var word = currentDictionary.words[index]; // Reference for easier reading
var editForm = '<form id="editForm' + indexString + '">\
<h2>Editing ' + htmlEntitiesParse(word.name) + '</h2>\
<label><span>Word</span>\
<input type="text" id="word' + indexString + '" value="' + htmlEntitiesParse(word.name) + '" onkeydown="SubmitWordOnCtrlEnter(this)" />\
</label>\
<label><span>Pronunciation <a class="clickable inline-button" href="http://r12a.github.io/pickers/ipa/" target="_blank" title="IPA Character Picker located at http://r12a.github.io/pickers/ipa/">IPA Characters</a></span>\
<input type="text" id="pronunciation' + indexString + '" value="' + htmlEntitiesParse(word.pronunciation) + '" onkeydown="SubmitWordOnCtrlEnter(this)" />\
</label>\
<label><span>Part of Speech</span>\
<select id="partOfSpeech' + indexString + '" onkeydown="SubmitWordOnCtrlEnter(this)"></select>\
</label>\
<label><span>Equivalent Word(s)</span>\
<input type="text" id="simpleDefinition' + indexString + '" value="' + htmlEntitiesParse(word.simpleDefinition) + '" onkeydown="SubmitWordOnCtrlEnter(this)" />\
</label>\
<label><span>Explanation/Long Definition <span id="showFullScreenTextbox" class="clickable inline-button" onclick="ShowFullScreenTextbox(\'longDefinition' + indexString + '\', \'Explanation/Long Definition\')">Maximize</span></span>\
<textarea id="longDefinition' + indexString + '" class="longDefinition" onkeydown="SubmitWordOnCtrlEnter(this)">' + htmlEntitiesParse(word.longDefinition) + '</textarea>\
</label>\
<span id="errorMessage' + indexString + '"></span>\
<div id="editWordButtonArea' + indexString + '" style="display: block;">\
<button type="button" onclick="EditWord(\'' + indexString + '\'); return false;">Edit Word</button> <button type="button" onclick="CancelEditForm(' + indexString + '); return false;">Cancel</button>\
</div>\
<div id="updateConflict' + indexString + '" style="display: none;"></div>\
</form>';
document.getElementById("entry" + indexString).innerHTML = editForm;
SetPartsOfSpeech("partOfSpeech" + indexString);
document.getElementById("partOfSpeech" + indexString).value = htmlEntitiesParse(word.partOfSpeech);
}
function CancelEditForm(index) {
document.getElementById("entry" + index.toString()).innerHTML = DictionaryEntry(index).replace("<entry id='entry" + index.toString() + "'>", "").replace("</entry>", "");
}
function EditWord(indexString) {
var word = htmlEntities(document.getElementById("word" + indexString).value).trim();
var pronunciation = htmlEntities(document.getElementById("pronunciation" + indexString).value).trim();
var partOfSpeech = htmlEntities(document.getElementById("partOfSpeech" + indexString).value).trim();
var simpleDefinition = htmlEntities(document.getElementById("simpleDefinition" + indexString).value).trim();
var longDefinition = htmlEntities(document.getElementById("longDefinition" + indexString).value);
var errorMessageArea = document.getElementById("errorMessage" + indexString);
var errorMessage = "";
var updateConflictArea = document.getElementById("updateConflict" + indexString);
if (WordAtIndexWasChanged(indexString, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition)) {
document.getElementById("editWordButtonArea" + indexString).style.display = "none";
DisableForm(indexString);
updateConflictArea.style.display = "block";
updateConflictArea.innerHTML = "<span id='updateConflictMessage" + indexString + "'>Do you really want to change the word \"" + currentDictionary.words[parseInt(indexString)].name + "\" to what you have set above?</span><br>";
updateConflictArea.innerHTML += '<button type="button" id="updateConfirmButton' + indexString + '" \
onclick="UpdateWord(' + indexString + ', \'' + htmlEntities(word) + '\', \'' + htmlEntities(pronunciation) + '\', \'' + htmlEntities(partOfSpeech) + '\', \'' + htmlEntities(simpleDefinition) + '\', \'' + htmlEntities(longDefinition) + '\'); \
return false;">Yes, Update it</button>';
updateConflictArea.innerHTML += '<button type="button" id="updateCancelButton' + indexString + '" onclick="CloseUpdateConflictArea(\'' + indexString + '\'); return false;">No, Leave it</button>';
} else {
errorMessage = "No change has been made to \"" + word + "\"";
if (currentDictionary.words[parseInt(indexString)].name != word) {
errorMessage += ". (Your dictionary is currently set to ignore case.)";
}
}
ClearForm();
document.getElementById("editIndex").value = index.toString();
document.getElementById("word").value = htmlEntitiesParse(currentDictionary.words[index].name);
document.getElementById("pronunciation").value = htmlEntitiesParse(currentDictionary.words[index].pronunciation);
document.getElementById("partOfSpeech").value = htmlEntitiesParse(currentDictionary.words[index].partOfSpeech);
document.getElementById("simpleDefinition").value = htmlEntitiesParse(currentDictionary.words[index].simpleDefinition);
document.getElementById("longDefinition").value = htmlEntitiesParse(currentDictionary.words[index].longDefinition);
document.getElementById("newWordButtonArea").style.display = "none";
document.getElementById("editWordButtonArea").style.display = "block";
errorMessageArea.innerHTML = errorMessage;
}
function UpdateWord(wordIndex, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition) {
currentDictionary.words[wordIndex].name = word;
currentDictionary.words[wordIndex].pronunciation = pronunciation;
currentDictionary.words[wordIndex].partOfSpeech = partOfSpeech;
currentDictionary.words[wordIndex].partOfSpeech = ((partOfSpeech.length > 0) ? partOfSpeech : " ");
currentDictionary.words[wordIndex].simpleDefinition = simpleDefinition;
currentDictionary.words[wordIndex].longDefinition = longDefinition;
SaveAndUpdateDictionary();
SaveAndUpdateWords("update", wordIndex);
window.scroll(savedScroll.x, savedScroll.y);
@ -143,12 +175,23 @@ function UpdateWord(wordIndex, word, pronunciation, partOfSpeech, simpleDefiniti
}
function DeleteWord(index) {
if (document.getElementById("editIndex").value != "")
ClearForm();
currentDictionary.words.splice(index, 1);
SaveAndUpdateDictionary(true);
var deleteWord = new XMLHttpRequest();
deleteWord.open('POST', "/php/ajax_dictionarymanagement.php?action=worddelete");
deleteWord.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
deleteWord.onreadystatechange = function() {
if (deleteWord.readyState == 4 && deleteWord.status == 200) {
if (deleteWord.responseText == "deleted successfully" || deleteWord.responseText == "not signed in") {
currentDictionary.words.splice(index, 1);
SaveWords(false);
}
console.log(deleteWord.responseText);
return true;
} else {
return false;
}
}
deleteWord.send("dict=" + currentDictionary.externalID.toString() + "&word=" + currentDictionary.words[index].wordId.toString());
}
function ShowDictionary() {
@ -186,6 +229,9 @@ function ShowDictionary() {
var dictionaryNameArea = document.getElementById("dictionaryName");
dictionaryNameArea.innerHTML = htmlEntitiesParse(currentDictionary.name) + " Dictionary";
if (loggedIn && currentDictionary.settings.isPublic) {
dictionaryNameArea.innerHTML += "<a href='/" + currentDictionary.externalID + "' target='_blank' id='dictionaryShareLink' class='clickable' title='Share Dictionary'>&#10150;</a>";
}
var dictionaryDescriptionArea = document.getElementById("dictionaryDescription");
dictionaryDescriptionArea.innerHTML = marked(htmlEntitiesParse(currentDictionary.description));
@ -218,9 +264,6 @@ function ShowDictionary() {
}
function DictionaryEntry(itemIndex) {
displayPublic = (typeof displayPublic !== 'undefined' && displayPublic != null) ? displayPublic : false;
var entryText = "<entry><a name='" + currentDictionary.words[itemIndex].wordId + "'></a><a href='#" + currentDictionary.words[itemIndex].wordId + "' class='wordLink clickable'>&#x1f517;</a>";
var searchTerm = regexParseForSearch(document.getElementById("searchBox").value);
var searchByWord = document.getElementById("searchOptionWord").checked;
var searchBySimple = document.getElementById("searchOptionSimple").checked;
@ -230,67 +273,54 @@ function DictionaryEntry(itemIndex) {
var searchRegEx = new RegExp("(" + ((searchIgnoreDiacritics) ? removeDiacritics(searchTerm) + "|" + searchTerm : searchTerm) + ")", "g" + ((searchIgnoreCase) ? "i" : ""));
entryText += "<word>";
var wordName = wordPronunciation = wordPartOfSpeech = wordSimpleDefinition = wordLongDefinition = "";
if (searchTerm != "" && searchByWord) {
entryText += htmlEntitiesParse(currentDictionary.words[itemIndex].name).replace(searchRegEx, "<searchTerm>$1</searchterm>");
// Parse HTML Entities while searching so the regex can search actual characters instead of HTML.
wordName += htmlEntitiesParse(currentDictionary.words[itemIndex].name).replace(searchRegEx, "<searchTerm>$1</searchterm>");
} else {
entryText += currentDictionary.words[itemIndex].name;
// Don't need to parse if not searching because HTML displays correctly anyway!
wordName += currentDictionary.words[itemIndex].name.toString(); // Use toString() to prevent using a reference instead of the value.
}
entryText += "</word>";
if (currentDictionary.words[itemIndex].pronunciation != "") {
entryText += "<pronunciation>";
entryText += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].pronunciation)).replace("<p>","").replace("</p>","");
entryText += "</pronunciation>";
wordPronunciation += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].pronunciation)).replace("<p>","").replace("</p>","");
}
if (currentDictionary.words[itemIndex].partOfSpeech != "") {
entryText += "<partofspeech>";
entryText += currentDictionary.words[itemIndex].partOfSpeech;
entryText += "</partofspeech>";
if (currentDictionary.words[itemIndex].partOfSpeech != " " && currentDictionary.words[itemIndex].partOfSpeech != "") {
wordPartOfSpeech += currentDictionary.words[itemIndex].partOfSpeech.toString();
}
entryText += "<br>";
if (currentDictionary.words[itemIndex].simpleDefinition != "") {
entryText += "<simpledefinition>";
if (currentDictionary.words[itemIndex].simpleDefinition != "") {
if (searchTerm != "" && searchBySimple) {
entryText += htmlEntitiesParse(currentDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>");
wordSimpleDefinition += htmlEntitiesParse(currentDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>");
} else {
entryText += currentDictionary.words[itemIndex].simpleDefinition;
wordSimpleDefinition += currentDictionary.words[itemIndex].simpleDefinition.toString();
}
entryText += "</simpledefinition>";
}
if (currentDictionary.words[itemIndex].longDefinition != "") {
entryText += "<longdefinition>";
if (searchTerm != "" && searchByLong) {
entryText += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>"));
wordLongDefinition += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>"));
} else {
entryText += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].longDefinition));
wordLongDefinition += marked(htmlEntitiesParse(currentDictionary.words[itemIndex].longDefinition));
}
entryText += "</longdefinition>";
}
if (!currentDictionary.settings.isComplete) {
entryText += ManagementArea(itemIndex);
}
entryText += "</entry>";
return entryText;
return DictionaryEntryTemplate({
name : wordName,
pronunciation : wordPronunciation,
partOfSpeech : wordPartOfSpeech,
simpleDefinition : wordSimpleDefinition,
longDefinition : wordLongDefinition,
wordId : currentDictionary.words[itemIndex].wordId.toString()
}, (!currentDictionary.settings.isComplete) ? itemIndex : false);
}
function ManagementArea(itemIndex) {
var managementHTML = "<div class='management'>";
managementHTML += "<span class='clickable editButton' onclick='EditWord(" + itemIndex + ")'>Edit</span>";
managementHTML += "<span class='clickable editButton' onclick='ShowWordEditForm(" + itemIndex + ")'>Edit</span>";
managementHTML += "<span class='clickable deleteButton' onclick='document.getElementById(\"delete" + itemIndex + "Confirm\").style.display = \"block\";'>Delete</span>";
managementHTML += "<div class='deleteConfirm' id='delete" + itemIndex + "Confirm' style='display:none;'>Are you sure you want to delete this entry?<br><br>";
@ -303,6 +333,50 @@ function ManagementArea(itemIndex) {
return managementHTML;
}
function DictionaryEntryTemplate(wordObject, managementIndex) {
managementIndex = (typeof managementIndex !== 'undefined') ? managementIndex : false;
var entryText = "<entry id='entry";
if (managementIndex !== false) {
// If there's a managementIndex, append index number to the element id.
entryText += managementIndex.toString();
}
entryText += "'><a name='" + wordObject.wordId + "'></a>";
if (loggedIn && currentDictionary.settings.isPublic) {
entryText += "<a href='/" + currentDictionary.externalID + "/" + wordObject.wordId + "' target='_blank' class='wordLink clickable' title='Share Word' style='margin-left:5px;'>&#10150;</a>";
}
entryText += "<a href='#" + wordObject.wordId + "' class='wordLink clickable' title='Link Within Page'>&#x1f517;</a>";
entryText += "<word>" + wordObject.name + "</word>";
if (wordObject.pronunciation != "") {
entryText += "<pronunciation>" + wordObject.pronunciation + "</pronunciation>";
}
if (wordObject.partOfSpeech != "") {
entryText += "<partofspeech>" + wordObject.partOfSpeech + "</partofspeech>";
}
entryText += "<br>";
if (wordObject.simpleDefinition != "") {
entryText += "<simpledefinition>" + wordObject.simpleDefinition + "</simpledefinition>";
}
if (wordObject.longDefinition != "") {
entryText += "<longdefinition>" + wordObject.longDefinition + "</longdefinition>";
}
if (managementIndex !== false) {
entryText += ManagementArea(managementIndex);
}
entryText += "</entry>";
return entryText;
}
function SaveSettings() {
if (htmlEntities(document.getElementById("dictionaryNameEdit").value) != "") {
currentDictionary.name = htmlEntities(document.getElementById("dictionaryNameEdit").value);
@ -339,6 +413,8 @@ function CreateNewDictionary() {
SaveAndUpdateDictionary(false);
SetPartsOfSpeech();
HideSettings();
ShowSettings();
document.getElementById("dictionaryNameEdit").focus();
}
function DeleteCurrentDictionary() {
@ -346,7 +422,7 @@ function DeleteCurrentDictionary() {
ResetDictionaryToDefault();
var deleteDictionary = new XMLHttpRequest();
deleteDictionary.open('POST', "php/ajax_dictionarymanagement.php?action=delete");
deleteDictionary.open('POST', "/php/ajax_dictionarymanagement.php?action=delete");
deleteDictionary.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
deleteDictionary.onreadystatechange = function() {
if (deleteDictionary.readyState == 4 && deleteDictionary.status == 200) {
@ -376,46 +452,78 @@ function ResetDictionaryToDefault() {
currentDictionary = JSON.parse(defaultDictionaryJSON);
}
function SaveAndUpdateDictionary(keepFormContents) {
function SaveAndUpdateWords(action, wordIndex) {
var dataToSend = "";
if (action == "all") {
// For dictionaries not already in the db. Send all the words to database.
dataToSend = JSON.stringify(currentDictionary.words);
} else if (action == "update") {
// Only send the specified word to update.
dataToSend = JSON.stringify(currentDictionary.words[wordIndex]);
} else if (action == "new") {
// Send the last word pushed to the words array before it's sorted.
dataToSend = JSON.stringify(currentDictionary.words[currentDictionary.words.length - 1]);
}
var sendWords = new XMLHttpRequest();
sendWords.open('POST', "/php/ajax_dictionarymanagement.php?action=word" + action + "&dict=" + currentDictionary.externalID.toString() + "&nextwordid=" + currentDictionary.nextWordId.toString());
sendWords.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
sendWords.onreadystatechange = function() {
if (sendWords.readyState == 4 && sendWords.status == 200) {
SaveWords();
ClearForm();
console.log(sendWords.responseText);
return true;
} else {
return false;
}
}
sendWords.send(dataToSend);
}
function SaveWords() {
if (!currentDictionary.settings.sortByEquivalent) {
currentDictionary.words.sort(dynamicSort(['name', 'partOfSpeech']));
} else {
currentDictionary.words.sort(dynamicSort(['simpleDefinition', 'partOfSpeech']));
}
SaveDictionary(true, true);
SaveDictionary(false);
ProcessLoad();
}
function SaveAndUpdateDictionary(keepFormContents) {
SaveDictionary(true);
ShowDictionary();
if (!keepFormContents) {
ClearForm();
}
CloseUpdateConflictArea('newWordButtonArea');
CloseUpdateConflictArea('');
}
function SaveDictionary(sendToDatabase, sendWords) {
localStorage.setItem('dictionary', JSON.stringify(currentDictionary));
function SaveDictionary(sendToDatabase) {
//Always save local copy of current dictionary, but if logged in also send to database.
if (sendToDatabase) {
sendWords = (typeof sendWords !== 'undefined') ? sendWords : false;
SendDictionary(sendWords);
SendDictionary();
}
localStorage.setItem('dictionary', JSON.stringify(currentDictionary));
SavePreviousDictionary();
}
function SendDictionary(sendWords) {
sendWords = (typeof sendWords !== 'undefined') ? sendWords : false;
function SendDictionary() {
var action = "";
var postString = "";
if (currentDictionary.externalID > 0) {
action = "update";
postString = DataToSend(sendWords);
postString = DataToSend(false);
} else {
action = "new";
postString = DataToSend(true, true);
postString = DataToSend(true);
}
var sendDictionary = new XMLHttpRequest();
sendDictionary.open('POST', "php/ajax_dictionarymanagement.php?action=" + action);
sendDictionary.open('POST', "/php/ajax_dictionarymanagement.php?action=" + action);
sendDictionary.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
sendDictionary.onreadystatechange = function() {
if (sendDictionary.readyState == 4 && sendDictionary.status == 200) {
@ -427,9 +535,12 @@ function SendDictionary(sendWords) {
console.log(sendDictionary.responseText);
} else { // It will only be a number if it is a new dictionary.
currentDictionary.externalID = parseInt(sendDictionary.responseText);
if (currentDictionary.words.length > 0) {
SaveAndUpdateWords("all");
}
LoadUserDictionaries();
ProcessLoad();
console.log("saved successfully");
console.log("saved " + parseInt(sendDictionary.responseText).toString() + " successfully");
}
return true;
} else {
@ -439,7 +550,7 @@ function SendDictionary(sendWords) {
sendDictionary.send(postString);
}
function DataToSend(doSendWords, sendAll) {
function DataToSend(sendAll) {
sendAll = (typeof sendAll !== 'undefined' && sendAll != null) ? sendAll : false;
var data = "";
if (currentDictionary.externalID == 0) {
@ -453,9 +564,6 @@ function DataToSend(doSendWords, sendAll) {
if (sendAll || currentDictionary.description != previousDictionary.description) {
data += ((data=="") ? "" : "&") + "description=" + encodeURIComponent(currentDictionary.description);
}
if (sendAll || doSendWords) {
data += ((data=="") ? "" : "&") + "words=" + encodeURIComponent(JSON.stringify(currentDictionary.words));
}
if (sendAll || currentDictionary.nextWordId != previousDictionary.nextWordId) {
data += ((data=="") ? "" : "&") + "nextwordid=" + currentDictionary.nextWordId;
}
@ -484,7 +592,7 @@ function DataToSend(doSendWords, sendAll) {
function LoadDictionary() {
LoadLocalDictionary();
var loadDictionary = new XMLHttpRequest();
loadDictionary.open('GET', "php/ajax_dictionarymanagement.php?action=load");
loadDictionary.open('GET', "/php/ajax_dictionarymanagement.php?action=load");
loadDictionary.onreadystatechange = function() {
if (loadDictionary.readyState == 4 && loadDictionary.status == 200) {
if (loadDictionary.responseText == "no dictionaries") {
@ -496,7 +604,7 @@ function LoadDictionary() {
console.log(loadDictionary.responseText);
} else {
currentDictionary = JSON.parse(loadDictionary.responseText);
SaveDictionary(false, false);
SaveDictionary(false);
}
}
ProcessLoad();
@ -507,28 +615,38 @@ function LoadDictionary() {
function ChangeDictionary(userDictionariesSelect) {
userDictionariesSelect = (typeof userDictionariesSelect !== 'undefined' && userDictionariesSelect != null) ? userDictionariesSelect : document.getElementById("userDictionaries");
if (currentDictionary.externalID != userDictionariesSelect.value && userDictionariesSelect.options.length > 0) {
var changeDictionaryRequest = new XMLHttpRequest();
changeDictionaryRequest.open('POST', "php/ajax_dictionarymanagement.php?action=switch");
changeDictionaryRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var postString = "newdictionaryid=" + userDictionariesSelect.value.toString();
changeDictionaryRequest.onreadystatechange = function() {
if (changeDictionaryRequest.readyState == 4 && changeDictionaryRequest.status == 200) {
if (changeDictionaryRequest.responseText == "no dictionaries") {
console.log(changeDictionaryRequest.responseText);
// Show the info page with loading screen and hide settings and stuff.
ShowInfoWithText("<h1>Loading " + userDictionariesSelect.options[userDictionariesSelect.selectedIndex].text + "...</h1>");
HideSettings();
ChangeDictionaryToId(userDictionariesSelect.value, function(response) {
if (response == "no dictionaries") {
console.log(response);
SendDictionary(false);
} else if (changeDictionaryRequest.responseText.length < 60) {
console.log(changeDictionaryRequest.responseText);
} else if (response.length < 60) {
console.log(response);
} else {
currentDictionary = JSON.parse(changeDictionaryRequest.responseText);
SaveDictionary(false, false);
currentDictionary = JSON.parse(response);
SaveDictionary(false);
ProcessLoad();
LoadUserDictionaries();
HideSettings();
HideInfo(); // Hide the loading screen.
}
});
}
}
function ChangeDictionaryToId(dictionaryId, callbackFunction) {
var changeDictionaryRequest = new XMLHttpRequest();
changeDictionaryRequest.open('POST', "/php/ajax_dictionarymanagement.php?action=switch");
changeDictionaryRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var postString = "newdictionaryid=" + dictionaryId.toString();
changeDictionaryRequest.onreadystatechange = function() {
if (changeDictionaryRequest.readyState == 4 && changeDictionaryRequest.status == 200) {
callbackFunction(changeDictionaryRequest.responseText);
}
}
changeDictionaryRequest.send(postString);
}
}
function LoadLocalDictionary() {
@ -576,14 +694,34 @@ function SavePreviousDictionary () {
}
function ExportDictionary() {
var downloadName = removeDiacritics(stripHtmlEntities(currentDictionary.name)).replace(/\W/g, '');
if (downloadName == "") {
downloadName = "export";
}
download(downloadName + ".dict", localStorage.getItem('dictionary'));
}
function ExportWords() {
if (currentDictionary.words.length > 0) {
var downloadName = removeDiacritics(stripHtmlEntities(currentDictionary.name)).replace(/\W/g, '');
if (downloadName == "") {
downloadName = "export";
}
download(downloadName + ".dict", localStorage.getItem('dictionary'));
downloadName += "_words";
var wordsCSV = "word,pronunciation,part of speech,equivalent,explanation\n";
for (var i = 0; i < currentDictionary.words.length; i++) {
var word = "\"" + htmlEntitiesParse(currentDictionary.words[i].name).trim().replace(/\"/g, "\"\"") + "\"";
var pronunciation = "\"" + htmlEntitiesParse(currentDictionary.words[i].pronunciation).trim().replace(/\"/g, "\"\"") + "\"";
var partOfSpeech = "\"" + htmlEntitiesParse(currentDictionary.words[i].partOfSpeech).trim().replace(/\"/g, "\"\"") + "\"";
var simpleDefinition = "\"" + htmlEntitiesParse(currentDictionary.words[i].simpleDefinition).trim().replace(/\"/g, "\"\"") + "\"";
var longDefinition = "\"" + htmlEntitiesParse(currentDictionary.words[i].longDefinition).replace(/\"/g, "\"\"") + "\"";
wordsCSV += word + "," + pronunciation + "," + partOfSpeech + "," + simpleDefinition + "," + longDefinition + "\n";
}
download(downloadName + ".csv", wordsCSV);
} else {
alert("Dictionary must have at least 1 word to export.")
alert("Dictionary must have at least 1 word to export.");
}
}
@ -610,13 +748,15 @@ function ImportDictionary() {
currentDictionary = JSON.parse(reader.result);
currentDictionary.externalID = 0; // Reset external id for imported dictionary.
currentDictionary.settings.isPublic = false; // Reset public setting for imported dictionary.
SaveDictionary(true, true);
SaveDictionary(true);
ProcessLoad();
HideInfo();
HideSettings();
document.getElementById("importFile").value = "";
NewNotification("Successfully Imported the \"" + currentDictionary.name + "\" Dictionary.");
} else {
var errorString = "File is missing:";
if (!tmpDicitonary.hasOwnProperty("name"))
if (!tmpDicitonary.hasOwnProperty("name"))
errorString += " name";
if (!tmpDicitonary.hasOwnProperty("description"))
errorString += " description";
@ -639,11 +779,74 @@ function ImportDictionary() {
}
}
function WordIndex(word) {
function ImportWords() {
if (currentDictionary.externalID > 0 || confirm("This will add words in a correctly formatted CSV file to your currently loaded dictionary. Do you still want to import?")) {
if (!window.FileReader) {
alert('Your browser is not supported');
return false;
}
if (document.getElementById("importWordsCSV").files.length > 0) {
var file = document.getElementById("importWordsCSV").files[0];
var resultsArea = document.getElementById("importOptions");
resultsArea.innerHTML = "<h3>Importing Words...</h3>";
var currentRow = 0; // Because of the header, the first row of data is always on line 2.
var rowsImported = 0;
Papa.parse(file, {
header: true,
step: function(row, parser) {
currentRow++;
// If there are no errors OR the word and either equivalent or explanation contain data, then import it.
if ((row.data[0].word.trim().length > 0 && (row.data[0].equivalent.trim().length > 0 || row.data[0].explanation.trim().length > 0)) || row.errors.length == 0) {
var wordName = htmlEntities(row.data[0]["word"]).trim(),
wordPronunciation = htmlEntities(row.data[0]["pronunciation"]).trim(),
wordPartOfSpeech = ((htmlEntities(row.data[0]["part of speech"]).trim().length > 0) ? htmlEntities(row.data[0]["part of speech"]).trim() : " "),
wordSimpleDefinition = htmlEntities(row.data[0]["equivalent"]).trim(),
wordLongDefinition = htmlEntities(row.data[0]["explanation"]).trim(),
wordId = currentDictionary.nextWordId++;
currentDictionary.words.push({name: wordName, pronunciation: wordPronunciation, partOfSpeech: wordPartOfSpeech, simpleDefinition: wordSimpleDefinition, longDefinition: wordLongDefinition, wordId: wordId});
var wordEntry = DictionaryEntryTemplate(currentDictionary.words[currentDictionary.words.length - 1]);
resultsArea.innerHTML += wordEntry;
rowsImported++;
} else {
// If it's not just an empty line, give an error.
if (row.data[0].word.trim().length > 0) {
for (var i = 0; i < row.errors.length; i++) {
resultsArea.innerHTML += "<p>Error on record #" + currentRow.toString() + ": " + row.errors[i].message + "</p>";
}
}
}
// Scroll to the bottom.
document.getElementById("infoPage").scrollTop = document.getElementById("infoPage").scrollHeight;
},
complete: function(results) {
SaveAndUpdateWords("all");
resultsArea.innerHTML += "<p>The file has finished importing " + rowsImported.toString() + " words.</p>";
NewNotification("Imported " + rowsImported.toString() + " words.");
// Scroll to the bottom.
document.getElementById("importOptions").scrollTop = document.getElementById("importOptions").scrollHeight;
document.getElementById("numberOfWordsInDictionary").innerHTML = currentDictionary.words.length.toString();
}
});
} else {
alert("You must add a file to import.");
}
}
}
function WordIndex(word, byId) {
// Use byId = true to enter word id number instead of string.
for (var i = 0; i < currentDictionary.words.length; i++)
{
if ((!currentDictionary.settings.caseSensitive && currentDictionary.words[i].name.toLowerCase() == word.toLowerCase()) ||
(currentDictionary.settings.caseSensitive && currentDictionary.words[i].name == word)) {
if ((!byId && (!currentDictionary.settings.caseSensitive && currentDictionary.words[i].name.toLowerCase() == word.toLowerCase()) ||
(currentDictionary.settings.caseSensitive && currentDictionary.words[i].name == word)) ||
(byId && currentDictionary.words[i].wordId == word)) {
return i;
}
}

View File

@ -218,8 +218,8 @@ function dynamicSort(propertiesArray) {
dir = -1;
o=o.substring(1);
}
if (removeDiacritics(a[o]) > removeDiacritics(b[o])) return dir;
if (removeDiacritics(a[o]) < removeDiacritics(b[o])) return -(dir);
if (removeDiacritics(a[o]).toLowerCase() > removeDiacritics(b[o]).toLowerCase()) return dir;
if (removeDiacritics(a[o]).toLowerCase() < removeDiacritics(b[o]).toLowerCase()) return -(dir);
return 0;
})
.reduce(function firstNonZeroValue (p,n) {

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
function ready(e){"loading"!=document.readyState?e():document.addEventListener("DOMContentLoaded",e)}function keyCodeFor(e){return"backspace"==e?8:"tab"==e?9:"ctrlEnter"==e?10:"enter"==e?13:"shift"==e?16:"ctrl"==e?17:"alt"==e?18:"pausebreak"==e?19:"capslock"==e?20:"escape"==e?27:"space"==e?32:"pageup"==e?33:"pagedown"==e?34:"end"==e?35:"home"==e?36:"left"==e?37:"up"==e?38:"right"==e?39:"down"==e?40:"insert"==e?45:"del"==e?46:"zero"==e?48:"one"==e?49:"two"==e?50:"three"==e?51:"four"==e?52:"five"==e?53:"six"==e?54:"seven"==e?55:"eight"==e?56:"nine"==e?57:"a"==e?65:"b"==e?66:"c"==e?67:"d"==e?68:"e"==e?69:"f"==e?70:"g"==e?71:"h"==e?72:"i"==e?73:"j"==e?74:"k"==e?75:"l"==e?76:"m"==e?77:"n"==e?78:"o"==e?79:"p"==e?80:"q"==e?81:"r"==e?82:"s"==e?83:"t"==e?84:"u"==e?85:"v"==e?86:"w"==e?87:"x"==e?88:"y"==e?89:"z"==e?90:"leftwinkey"==e?91:"rightwinkey"==e?92:"selectkey"==e?93:"numpad_0"==e?96:"numpad_1"==e?97:"numpad_2"==e?98:"numpad_3"==e?99:"numpad_4"==e?100:"numpad_5"==e?101:"numpad_6"==e?102:"numpad_7"==e?103:"numpad_8"==e?104:"numpad_9"==e?105:"numpad_asterisk"==e?106:"numpad_plus"==e?107:"numpad_dash"==e?109:"numpad_period"==e?110:"numpad_slash"==e?111:"f1"==e?112:"f2"==e?113:"f3"==e?114:"f4"==e?115:"f5"==e?116:"f6"==e?117:"f7"==e?118:"f8"==e?119:"f9"==e?120:"f10"==e?121:"f11"==e?122:"f12"==e?123:"numlock"==e?144:"scrolllock"==e?145:"semicolon"==e?186:"equal"==e?187:"comma"==e?188:"dash"==e?189:"period"==e?190:"slash"==e?191:"grave"==e?192:"openbracket"==e?219:"backslash"==e?220:"closebraket"==e?221:"quote"==e?222:!1}function getInputSelection(e){var t,n,r,a,c,o=0,l=0;return e.focus(),"number"==typeof e.selectionStart&&"number"==typeof e.selectionEnd?(o=e.selectionStart,l=e.selectionEnd):(n=document.selection.createRange(),n&&n.parentElement()==e&&(a=e.value.length,t=e.value.replace(/\r\n/g,"\n"),r=e.createTextRange(),r.moveToBookmark(n.getBookmark()),c=e.createTextRange(),c.collapse(!1),r.compareEndPoints("StartToEnd",c)>-1?o=l=a:(o=-r.moveStart("character",-a),o+=t.slice(0,o).split("\n").length-1,r.compareEndPoints("EndToEnd",c)>-1?l=a:(l=-r.moveEnd("character",-a),l+=t.slice(0,l).split("\n").length-1)))),{start:o,end:l}}function setSelectionRange(e,t,n){if(e.setSelectionRange)e.focus(),e.setSelectionRange(t,n);else if(e.createTextRange){var r=e.createTextRange();r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r.select()}}function SaveScroll(){var e=document.documentElement,t=(window.pageXOffset||e.scrollLeft)-(e.clientLeft||0),n=(window.pageYOffset||e.scrollTop)-(e.clientTop||0);savedScroll.x=t,savedScroll.y=n}function htmlEntities(e){return String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/\\/g,"&#92;").replace(/\n/g,"<br>")}function htmlEntitiesParse(e){return String(e).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&#92;/g,"\\").replace(/<br>/g,"\n")}function stripHtmlEntities(e){return String(e).replace(/&amp;/g,"").replace(/&lt;/g,"").replace(/&gt;/g,"").replace(/&quot;/g,"").replace(/&apos;/g,"").replace(/&#92;/g,"").replace(/<br>/g,"")}function htmlEntitiesParseForSearchEntry(e){return String(e).replace(/"/g,"%%%%").replace(/'/g,"````")}function htmlEntitiesParseForSearch(e){return String(e).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,"%%%%").replace(/&apos;/g,"````")}function regexParseForSearch(e){return String(e).replace(/([\[\\\^\$\.\|\?\*\+\(\)\{\}\]])/g,"\\$1")}function dynamicSort(e){return function(t,n){return e.map(function(e){var r=1;return"-"===e[0]&&(r=-1,e=e.substring(1)),removeDiacritics(t[e])>removeDiacritics(n[e])?r:removeDiacritics(t[e])<removeDiacritics(n[e])?-r:0}).reduce(function(e,t){return e?e:t},0)}}function download(e,t){var n=document.createElement("a");n.setAttribute("href","data:text/plain;charset=utf-8,"+encodeURIComponent(t)),n.setAttribute("download",e),n.style.display="none",document.body.appendChild(n),n.click(),document.body.removeChild(n)}
function ready(e){"loading"!=document.readyState?e():document.addEventListener("DOMContentLoaded",e)}function keyCodeFor(e){return"backspace"==e?8:"tab"==e?9:"ctrlEnter"==e?10:"enter"==e?13:"shift"==e?16:"ctrl"==e?17:"alt"==e?18:"pausebreak"==e?19:"capslock"==e?20:"escape"==e?27:"space"==e?32:"pageup"==e?33:"pagedown"==e?34:"end"==e?35:"home"==e?36:"left"==e?37:"up"==e?38:"right"==e?39:"down"==e?40:"insert"==e?45:"del"==e?46:"zero"==e?48:"one"==e?49:"two"==e?50:"three"==e?51:"four"==e?52:"five"==e?53:"six"==e?54:"seven"==e?55:"eight"==e?56:"nine"==e?57:"a"==e?65:"b"==e?66:"c"==e?67:"d"==e?68:"e"==e?69:"f"==e?70:"g"==e?71:"h"==e?72:"i"==e?73:"j"==e?74:"k"==e?75:"l"==e?76:"m"==e?77:"n"==e?78:"o"==e?79:"p"==e?80:"q"==e?81:"r"==e?82:"s"==e?83:"t"==e?84:"u"==e?85:"v"==e?86:"w"==e?87:"x"==e?88:"y"==e?89:"z"==e?90:"leftwinkey"==e?91:"rightwinkey"==e?92:"selectkey"==e?93:"numpad_0"==e?96:"numpad_1"==e?97:"numpad_2"==e?98:"numpad_3"==e?99:"numpad_4"==e?100:"numpad_5"==e?101:"numpad_6"==e?102:"numpad_7"==e?103:"numpad_8"==e?104:"numpad_9"==e?105:"numpad_asterisk"==e?106:"numpad_plus"==e?107:"numpad_dash"==e?109:"numpad_period"==e?110:"numpad_slash"==e?111:"f1"==e?112:"f2"==e?113:"f3"==e?114:"f4"==e?115:"f5"==e?116:"f6"==e?117:"f7"==e?118:"f8"==e?119:"f9"==e?120:"f10"==e?121:"f11"==e?122:"f12"==e?123:"numlock"==e?144:"scrolllock"==e?145:"semicolon"==e?186:"equal"==e?187:"comma"==e?188:"dash"==e?189:"period"==e?190:"slash"==e?191:"grave"==e?192:"openbracket"==e?219:"backslash"==e?220:"closebraket"==e?221:"quote"==e?222:!1}function getInputSelection(e){var t,n,r,a,c,o=0,l=0;return e.focus(),"number"==typeof e.selectionStart&&"number"==typeof e.selectionEnd?(o=e.selectionStart,l=e.selectionEnd):(n=document.selection.createRange(),n&&n.parentElement()==e&&(a=e.value.length,t=e.value.replace(/\r\n/g,"\n"),r=e.createTextRange(),r.moveToBookmark(n.getBookmark()),c=e.createTextRange(),c.collapse(!1),r.compareEndPoints("StartToEnd",c)>-1?o=l=a:(o=-r.moveStart("character",-a),o+=t.slice(0,o).split("\n").length-1,r.compareEndPoints("EndToEnd",c)>-1?l=a:(l=-r.moveEnd("character",-a),l+=t.slice(0,l).split("\n").length-1)))),{start:o,end:l}}function setSelectionRange(e,t,n){if(e.setSelectionRange)e.focus(),e.setSelectionRange(t,n);else if(e.createTextRange){var r=e.createTextRange();r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r.select()}}function SaveScroll(){var e=document.documentElement,t=(window.pageXOffset||e.scrollLeft)-(e.clientLeft||0),n=(window.pageYOffset||e.scrollTop)-(e.clientTop||0);savedScroll.x=t,savedScroll.y=n}function htmlEntities(e){return String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/\\/g,"&#92;").replace(/\n/g,"<br>")}function htmlEntitiesParse(e){return String(e).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&#92;/g,"\\").replace(/<br>/g,"\n")}function stripHtmlEntities(e){return String(e).replace(/&amp;/g,"").replace(/&lt;/g,"").replace(/&gt;/g,"").replace(/&quot;/g,"").replace(/&apos;/g,"").replace(/&#92;/g,"").replace(/<br>/g,"")}function htmlEntitiesParseForSearchEntry(e){return String(e).replace(/"/g,"%%%%").replace(/'/g,"````")}function htmlEntitiesParseForSearch(e){return String(e).replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,"%%%%").replace(/&apos;/g,"````")}function regexParseForSearch(e){return String(e).replace(/([\[\\\^\$\.\|\?\*\+\(\)\{\}\]])/g,"\\$1")}function dynamicSort(e){return function(t,n){return e.map(function(e){var r=1;return"-"===e[0]&&(r=-1,e=e.substring(1)),removeDiacritics(t[e]).toLowerCase()>removeDiacritics(n[e]).toLowerCase()?r:removeDiacritics(t[e]).toLowerCase()<removeDiacritics(n[e]).toLowerCase()?-r:0}).reduce(function(e,t){return e?e:t},0)}}function download(e,t){var n=document.createElement("a");n.setAttribute("href","data:text/plain;charset=utf-8,"+encodeURIComponent(t)),n.setAttribute("download",e),n.style.display="none",document.body.appendChild(n),n.click(),document.body.removeChild(n)}

6
js/min/papaparse.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1423
js/papaparse.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,18 +2,20 @@ function IsValidPublicDicitonary() {
return typeof publicDictionary !== 'string';
}
function ShowPublicDictionary() {
function ShowPublicDictionary(ignoreFilters) {
ignoreFilters = (typeof ignoreFilters !== 'undefined') ? ignoreFilters : false;
if (IsValidPublicDicitonary()) {
var filters = GetSelectedFilters();
var filters = (ignoreFilters) ? [] : GetSelectedFilters();
var searchResults = [];
var search = htmlEntitiesParseForSearchEntry(document.getElementById("searchBox").value);
var searchByWord = document.getElementById("searchOptionWord").checked;
var searchBySimple = document.getElementById("searchOptionSimple").checked;
var searchByLong = document.getElementById("searchOptionLong").checked;
var searchIgnoreCase = !document.getElementById("searchCaseSensitive").checked; //It's easier to negate case here instead of negating it every use since ignore case is default.
var searchIgnoreDiacritics = document.getElementById("searchIgnoreDiacritics").checked;
if (search != "" && (searchByWord || searchBySimple || searchByLong)) {
var search = (ignoreFilters) ? "" : htmlEntitiesParseForSearchEntry(document.getElementById("searchBox").value);
var searchByWord = (ignoreFilters) ? null : document.getElementById("searchOptionWord").checked;
var searchBySimple = (ignoreFilters) ? null : document.getElementById("searchOptionSimple").checked;
var searchByLong = (ignoreFilters) ? null : document.getElementById("searchOptionLong").checked;
var searchIgnoreCase = (ignoreFilters) ? null : !document.getElementById("searchCaseSensitive").checked; //It's easier to negate case here instead of negating it every use since ignore case is default.
var searchIgnoreDiacritics = (ignoreFilters) ? null : document.getElementById("searchIgnoreDiacritics").checked;
if (!ignoreFilters && search != "" && (searchByWord || searchBySimple || searchByLong)) {
var xpath = [];
var searchDictionaryJSON = htmlEntitiesParseForSearch(JSON.stringify(publicDictionary));
if (searchIgnoreCase) {
@ -65,7 +67,7 @@ function ShowPublicDictionary() {
if (!publicDictionary.words[i].hasOwnProperty("wordId")) {
publicDictionary.words[i].wordId = i + 1; //Account for new property
}
dictionaryText += PublicDictionaryEntry(i);
dictionaryText += PublicDictionaryEntry(i, ignoreFilters);
numberOfWordsDisplayed++;
}
}
@ -74,70 +76,97 @@ function ShowPublicDictionary() {
dictionaryText = "There are no entries in the dictionary."
}
dictionaryArea.innerHTML = dictionaryText;
ShowFilterWordCount(numberOfWordsDisplayed);
if (!ignoreFilters) {
ShowFilterWordCount(numberOfWordsDisplayed);
}
} else {
document.getElementById("dictionaryContainer").innerHTML = publicDictionary;
}
}
function PublicDictionaryEntry(itemIndex) {
var entryText = "<entry><a name='" + publicDictionary.words[itemIndex].wordId + "'></a><a href='#" + publicDictionary.words[itemIndex].wordId + "' class='wordLink clickable'>&#x1f517;</a>";
var searchTerm = regexParseForSearch(document.getElementById("searchBox").value);
var searchByWord = document.getElementById("searchOptionWord").checked;
var searchBySimple = document.getElementById("searchOptionSimple").checked;
var searchByLong = document.getElementById("searchOptionLong").checked;
var searchIgnoreCase = !document.getElementById("searchCaseSensitive").checked; //It's easier to negate case here instead of negating it every use since ignore case is default.
var searchIgnoreDiacritics = document.getElementById("searchIgnoreDiacritics").checked;
function PublicDictionaryEntry(itemIndex, ignoreFilters) {
var searchTerm = (ignoreFilters) ? "" : regexParseForSearch(document.getElementById("searchBox").value);
var searchByWord = (ignoreFilters) ? false : document.getElementById("searchOptionWord").checked;
var searchBySimple = (ignoreFilters) ? false : document.getElementById("searchOptionSimple").checked;
var searchByLong = (ignoreFilters) ? false : document.getElementById("searchOptionLong").checked;
var searchIgnoreCase = (ignoreFilters) ? false : !document.getElementById("searchCaseSensitive").checked; //It's easier to negate case here instead of negating it every use since ignore case is default.
var searchIgnoreDiacritics = (ignoreFilters) ? false : document.getElementById("searchIgnoreDiacritics").checked;
var searchRegEx = new RegExp("(" + ((searchIgnoreDiacritics) ? removeDiacritics(searchTerm) + "|" + searchTerm : searchTerm) + ")", "g" + ((searchIgnoreCase) ? "i" : ""));
entryText += "<word>";
var wordName = wordPronunciation = wordPartOfSpeech = wordSimpleDefinition = wordLongDefinition = "";
if (searchTerm != "" && searchByWord) {
entryText += htmlEntitiesParse(publicDictionary.words[itemIndex].name).replace(searchRegEx, "<searchTerm>$1</searchterm>");
wordName += htmlEntitiesParse(publicDictionary.words[itemIndex].name).replace(searchRegEx, "<searchTerm>$1</searchterm>");
} else {
entryText += publicDictionary.words[itemIndex].name;
wordName += publicDictionary.words[itemIndex].name.toString(); // Use toString() to prevent using a reference instead of the value.
}
entryText += "</word>";
if (publicDictionary.words[itemIndex].pronunciation != "") {
entryText += "<pronunciation>";
entryText += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].pronunciation)).replace("<p>","").replace("</p>","");
entryText += "</pronunciation>";
wordPronunciation += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].pronunciation)).replace("<p>","").replace("</p>","");
}
if (publicDictionary.words[itemIndex].partOfSpeech != "") {
entryText += "<partofspeech>";
entryText += publicDictionary.words[itemIndex].partOfSpeech;
entryText += "</partofspeech>";
wordPartOfSpeech += publicDictionary.words[itemIndex].partOfSpeech.toString();
}
if (publicDictionary.words[itemIndex].simpleDefinition != "") {
if (searchTerm != "" && searchBySimple) {
wordSimpleDefinition += htmlEntitiesParse(publicDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>");
} else {
wordSimpleDefinition += publicDictionary.words[itemIndex].simpleDefinition.toString();
}
}
if (publicDictionary.words[itemIndex].longDefinition != "") {
if (searchTerm != "" && searchByLong) {
wordLongDefinition += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>"));
} else {
wordLongDefinition += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].longDefinition));
}
}
return PublicDictionaryEntryTemplate({
name : wordName,
pronunciation : wordPronunciation,
partOfSpeech : wordPartOfSpeech,
simpleDefinition : wordSimpleDefinition,
longDefinition : wordLongDefinition,
wordId : publicDictionary.words[itemIndex].wordId.toString()
}, false);
}
function PublicDictionaryEntryTemplate(wordObject, managementIndex) {
managementIndex = (typeof managementIndex !== 'undefined') ? managementIndex : false;
var entryText = "<entry id='entry";
if (managementIndex !== false) {
// If there's a managementIndex, append index number to the element id.
entryText += managementIndex.toString();
}
entryText += "'><a href='/" + publicDictionary.id + "/" + wordObject.wordId + "' class='wordLink clickable' title='Share Word'>&#10150;</a>";
entryText += "<word>" + wordObject.name + "</word>";
if (wordObject.pronunciation != "") {
entryText += "<pronunciation>" + wordObject.pronunciation + "</pronunciation>";
}
if (wordObject.partOfSpeech != "") {
entryText += "<partofspeech>" + wordObject.partOfSpeech + "</partofspeech>";
}
entryText += "<br>";
if (publicDictionary.words[itemIndex].simpleDefinition != "") {
entryText += "<simpledefinition>";
if (searchTerm != "" && searchBySimple) {
entryText += htmlEntitiesParse(publicDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>");
} else {
entryText += publicDictionary.words[itemIndex].simpleDefinition;
}
entryText += "</simpledefinition>";
if (wordObject.simpleDefinition != "") {
entryText += "<simpledefinition>" + wordObject.simpleDefinition + "</simpledefinition>";
}
if (publicDictionary.words[itemIndex].longDefinition != "") {
entryText += "<longdefinition>";
if (wordObject.longDefinition != "") {
entryText += "<longdefinition>" + wordObject.longDefinition + "</longdefinition>";
}
if (searchTerm != "" && searchByLong) {
entryText += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "<searchTerm>$1</searchterm>"));
} else {
entryText += marked(htmlEntitiesParse(publicDictionary.words[itemIndex].longDefinition));
}
entryText += "</longdefinition>";
if (managementIndex !== false) {
entryText += ManagementArea(managementIndex);
}
entryText += "</entry>";

114
js/ui.js
View File

@ -3,11 +3,13 @@ function Initialize() {
ClearForm();
LoadUserDictionaries();
GetTextFile("README.md", "aboutText", true);
GetTextFile("TERMS.md", "termsText", true);
GetTextFile("PRIVACY.md", "privacyText", true);
GetTextFile("LOGIN.form", "loginForm", false);
GetTextFile("FORGOT.form", "forgotForm", false);
GetTextFile("/README.md", "aboutText", true);
GetTextFile("/TERMS.md", "termsText", true);
GetTextFile("/PRIVACY.md", "privacyText", true);
GetTextFile("/LOGIN.form", "loginForm", false);
GetTextFile("/FORGOT.form", "forgotForm", false);
GetTextFile("/EXPORT.form", "exportForm", false);
GetTextFile("/IMPORT.form", "importForm", false);
SetKeyboardShortcuts();
}
@ -132,7 +134,7 @@ function LoadUserDictionaries() {
var getDictionariesRequest = new XMLHttpRequest();
var userDictionariesSelect = document.getElementById("userDictionaries");
if (userDictionariesSelect != null) {
getDictionariesRequest.open('GET', "php/ajax_dictionarymanagement.php?action=getall");
getDictionariesRequest.open('GET', "/php/ajax_dictionarymanagement.php?action=getall");
getDictionariesRequest.onreadystatechange = function() {
if (getDictionariesRequest.readyState == 4 && getDictionariesRequest.status == 200) {
ParseUserDictionariesIntoSelect(userDictionariesSelect, getDictionariesRequest.responseText);
@ -215,7 +217,7 @@ function ValidateCreateAccount() {
return false;
} else {
var emailCheck = new XMLHttpRequest();
emailCheck.open('GET', "php/ajax_createaccountemailcheck.php?email=" + emailValue);
emailCheck.open('GET', "/php/ajax_createaccountemailcheck.php?email=" + emailValue);
emailCheck.onreadystatechange = function() {
if (emailCheck.readyState == 4 && emailCheck.status == 200) {
if (emailCheck.responseText != "ok") {
@ -261,7 +263,7 @@ function ValidateForgotPassword() {
return false;
} else {
var emailCheck = new XMLHttpRequest();
emailCheck.open('GET', "php/ajax_passwordresetemailcheck.php?email=" + emailValue);
emailCheck.open('GET', "/php/ajax_passwordresetemailcheck.php?email=" + emailValue);
emailCheck.onreadystatechange = function() {
if (emailCheck.readyState == 4 && emailCheck.status == 200) {
if (emailCheck.responseText != "email exists") {
@ -306,7 +308,7 @@ function WarnEmailChange() {
function LoggedInResetPassword() {
var resetPasswordRequest = new XMLHttpRequest();
resetPasswordRequest.open('GET', "php/ajax_setnewpassword.php");
resetPasswordRequest.open('GET', "/php/ajax_setnewpassword.php");
resetPasswordRequest.onreadystatechange = function() {
if (resetPasswordRequest.readyState == 4 && resetPasswordRequest.status == 200) {
if (resetPasswordRequest.responseText != "done") {
@ -369,31 +371,34 @@ function LockWordForm() {
wordForm.removeAttribute('style');
}
function CloseUpdateConflictArea(displayId) {
displayId = (typeof displayId !== 'undefined' && displayId != null) ? displayId : false;
if (displayId != false) {
document.getElementById(displayId).style.display = "block";
function CloseUpdateConflictArea(wordIndexString) {// displayId, hideId) {
// displayId = (typeof displayId !== 'undefined' && displayId != null) ? displayId : false;
// if (displayId != false) {
if (wordIndexString == "") {
document.getElementById("newWordButtonArea").style.display = "block";
} else {
document.getElementById("editWordButtonArea" + wordIndexString).style.display = "block";
}
document.getElementById("updateConflict").style.display = "none";
EnableForm();
// }
document.getElementById("updateConflict" + wordIndexString).style.display = "none";
EnableForm(wordIndexString);
}
function DisableForm() {
document.getElementById("word").disabled = true;
document.getElementById("pronunciation").disabled = true;
document.getElementById("partOfSpeech").disabled = true;
document.getElementById("simpleDefinition").disabled = true;
document.getElementById("longDefinition").disabled = true;
document.getElementById("editIndex").disabled = true;
function DisableForm(wordIndexString) {
document.getElementById("word" + wordIndexString).disabled = true;
document.getElementById("pronunciation" + wordIndexString).disabled = true;
document.getElementById("partOfSpeech" + wordIndexString).disabled = true;
document.getElementById("simpleDefinition" + wordIndexString).disabled = true;
document.getElementById("longDefinition" + wordIndexString).disabled = true;
}
function EnableForm() {
document.getElementById("word").disabled = false;
document.getElementById("pronunciation").disabled = false;
document.getElementById("partOfSpeech").disabled = false;
document.getElementById("simpleDefinition").disabled = false;
document.getElementById("longDefinition").disabled = false;
document.getElementById("editIndex").disabled = false;
function EnableForm(wordIndexString) {
document.getElementById("word" + wordIndexString).disabled = false;
document.getElementById("pronunciation" + wordIndexString).disabled = false;
document.getElementById("partOfSpeech" + wordIndexString).disabled = false;
document.getElementById("simpleDefinition" + wordIndexString).disabled = false;
document.getElementById("longDefinition" + wordIndexString).disabled = false;
// document.getElementById("editIndex").disabled = false;
}
function ClearForm() {
@ -409,7 +414,7 @@ function ClearForm() {
document.getElementById("editWordButtonArea").style.display = "none";
document.getElementById("errorMessage").innerHTML = "";
document.getElementById("updateConflict").style.display = "none";
EnableForm();
EnableForm("");
}
}
@ -440,16 +445,20 @@ function ToggleSearchFilter() {
}
function ShowInfo(variableName) {
document.getElementById("infoText").innerHTML = window[variableName];
ShowInfoWithText(window[variableName]);
if (variableName == "loginForm") {
// document.getElementById("infoText").innerHTML = loginForm;
if (currentDictionary.words.length > 0 || currentDictionary.name != "New" || currentDictionary.description != "A new dictionary.") {
document.getElementById("dictionaryWarn").innerHTML = "If your current dictionary is not already saved to your account, be sure to <span class='exportWarnText' onclick='ExportDictionary()'>export it before logging in</span> so you don't lose anything!";
}
}
HideAccountSettings();
document.getElementById("infoPage").scrollTop = 0;
}
function ShowInfoWithText(text) {
document.getElementById("infoText").innerHTML = text;
document.getElementById("infoScreen").style.display = "block";
document.getElementById("infoPage").scrollTop = 0;
HideAccountSettings();
}
function HideInfo() {
@ -579,19 +588,22 @@ function TogglePublicLink() {
}
}
function SetPartsOfSpeech () {
var partsOfSpeechSelect = document.getElementById("partOfSpeech");
function SetPartsOfSpeech (selectId) {
selectId = (typeof selectId !== 'undefined') ? selectId : "partOfSpeech";
var partsOfSpeechSelect = document.getElementById(selectId);
var wordFilterOptions = document.getElementById("filterOptions");
var wordFiltersSelected = GetSelectedFilters();
// Clear parts of speech.
if (partsOfSpeechSelect.options.length > 0) {
for (var i = partsOfSpeechSelect.options.length - 1; i >= 0; i--) {
partsOfSpeechSelect.removeChild(partsOfSpeechSelect.options[i]);
}
wordFilterOptions.innerHTML = "";
}
partsOfSpeechSelect.innerHTML = "";
wordFilterOptions.innerHTML = "";
// Insert blank part of speech as first dropdown option.
var blankpartOfSpeechOption = document.createElement('option');
blankpartOfSpeechOption.appendChild(document.createTextNode(""));
blankpartOfSpeechOption.value = " ";
partsOfSpeechSelect.appendChild(blankpartOfSpeechOption);
// Rebuild parts of speech
var newPartsOfSpeech = htmlEntitiesParse(currentDictionary.settings.partsOfSpeech).trim().split(",");
@ -614,6 +626,18 @@ function SetPartsOfSpeech () {
wordFilterLabel.appendChild(wordFilterCheckbox);
wordFilterOptions.appendChild(wordFilterLabel);
}
// Insert blank part of speech as last filter option
var blankwordFilterLabel = document.createElement('label');
blankwordFilterLabel.appendChild(document.createTextNode("Blanks "));
blankwordFilterLabel['part-of-speech'] = " ";
blankwordFilterLabel.className = 'filterOption';
var blankwordFilterCheckbox = document.createElement('input');
blankwordFilterCheckbox.type = 'checkbox';
blankwordFilterCheckbox.onchange = function(){ShowDictionary()};
if (wordFiltersSelected.indexOf(" ") > -1) blankwordFilterCheckbox.checked = true;
blankwordFilterLabel.appendChild(blankwordFilterCheckbox);
wordFilterOptions.appendChild(blankwordFilterLabel);
}
function GetSelectedFilters() {
@ -651,11 +675,15 @@ function ShowFilterWordCount(numberOfWords) {
}
function NewWordNotification(word) {
var wordId = currentDictionary.nextWordId - 1;
NewNotification("New Word Added: <a href='#" + wordId.toString() + "'>" + word + "</a>");
}
function NewNotification(message) {
var notificationArea = document.getElementById("notificationArea");
var notificationMessage = document.getElementById("notificationMessage");
var wordId = currentDictionary.nextWordId - 1;
notificationArea.style.display = "block";
notificationMessage.innerHTML = "New Word Added: <a href='#" + wordId.toString() + "'>" + word + "</a>";
notificationMessage.innerHTML = message;
}
function FocusAfterAddingNewWord() {

View File

@ -4,234 +4,341 @@ require_once('config.php');
require_once(SITE_LOCATION . '/php/functions.php');
session_start();
if ($_GET['action'] == 'getall') {
Get_Dictionaries(true);
}
elseif ($_GET['action'] == 'load') {
Load_Current_Dictionary();
}
elseif ($_GET['action'] == 'new') {
Save_Current_DictionaryAsNew();
}
elseif ($_GET['action'] == 'update') {
Update_Current_Dictionary();
}
elseif ($_GET['action'] == 'switch') {
Switch_Current_Dictionary($_POST['newdictionaryid'], true);
}
elseif ($_GET['action'] == 'delete') {
Delete_Current_Dictionary();
if ($_SESSION['user'] > 0) {
if ($_GET['action'] == 'getall') {
Get_Dictionaries(true);
}
elseif ($_GET['action'] == 'load') {
Load_Current_Dictionary();
}
elseif ($_GET['action'] == 'new') {
Save_Current_DictionaryAsNew();
}
elseif ($_GET['action'] == 'update') {
Update_Current_Dictionary();
}
elseif ($_GET['action'] == 'wordall') {
Save_New_Word(true);
}
elseif ($_GET['action'] == 'wordnew') {
Save_New_Word(false);
}
elseif ($_GET['action'] == 'wordupdate') {
Update_Word();
}
elseif ($_GET['action'] == 'switch') {
Switch_Current_Dictionary($_POST['newdictionaryid'], true);
}
elseif ($_GET['action'] == 'delete') {
Delete_Current_Dictionary();
}
elseif ($_GET['action'] == 'worddelete') {
Delete_Word();
}
} else {
echo "not signed in";
}
function Get_Dictionaries($return_list = true) {
if ($_SESSION['user'] > 0) {
$query = "SELECT `id`, `name` FROM `dictionaries` WHERE `user`=" . $_SESSION['user'] . " ORDER BY `name` ASC;";
$dictionaries = query($query);
if ($dictionaries) {
if (num_rows($dictionaries) > 0) {
if ($return_list) {
$list = "";
$_SESSION['dictionaries'] = [];
while ($dict = fetch($dictionaries)) {
$_SESSION['dictionaries'][] = $dict['id']; // Save a list of all dictionaries user has.
//list for the switch dictionaries dropdown.
$list .= $dict['id'] . '_IDNAMESEPARATOR_' . $dict['name'] . '_DICTIONARYSEPARATOR_';
}
echo $list;
$query = "SELECT `id`, `name` FROM `dictionaries` WHERE `user`=" . $_SESSION['user'] . " ORDER BY `name` ASC;";
$dictionaries = query($query);
if ($dictionaries) {
if (num_rows($dictionaries) > 0) {
if ($return_list) {
$list = "";
$_SESSION['dictionaries'] = [];
while ($dict = fetch($dictionaries)) {
$_SESSION['dictionaries'][] = $dict['id']; // Save a list of all dictionaries user has.
//list for the switch dictionaries dropdown.
$list .= $dict['id'] . '_IDNAMESEPARATOR_' . $dict['name'] . '_DICTIONARYSEPARATOR_';
}
return true;
} else {
echo "no dictionaries";
echo $list;
}
return true;
} else {
echo "could not load";
echo "no dictionaries";
}
} else {
echo "not signed in";
echo "could not load";
}
return false;
}
function Load_Current_Dictionary() {
if ($_SESSION['user'] > 0) {
$query = "SELECT `d`.`id`, `d`.`name`, `d`.`description`, `u`.`public_name`, `d`.`words`, `d`.`next_word_id`, `d`.`allow_duplicates`, `d`.`case_sensitive`, `d`.`parts_of_speech`, `d`.`sort_by_equivalent`, `d`.`is_complete`, `d`.`is_public` ";
$query .= "FROM `dictionaries` AS `d` LEFT JOIN `users` AS `u` ON `user`=`u`.`id` WHERE `is_current`=1 AND `user`=" . $_SESSION['user'] . ";";
$dictionary = query($query);
if ($dictionary) {
if (num_rows($dictionary) > 0) {
if (num_rows($dictionary) === 1) {
while ($dict = fetch($dictionary)) {
$_SESSION['dictionary'] = $dict['id'];
$json = '{"name":"' . $dict['name'] . '",';
$json .= '"description":"' . $dict['description'] . '",';
$json .= '"createdBy":"' . $dict['public_name'] . '",';
$json .= '"words":' . $dict['words'] . ',';
$json .= '"nextWordId":' . $dict['next_word_id'] . ',';
$json .= '"settings":{';
$json .= '"allowDuplicates":' . (($dict['allow_duplicates'] == 1) ? 'true' : 'false') . ',';
$json .= '"caseSensitive":' . (($dict['case_sensitive'] == 1) ? 'true' : 'false') . ',';
$json .= '"partsOfSpeech":"' . $dict['parts_of_speech'] . '",';
$json .= '"sortByEquivalent":' . (($dict['sort_by_equivalent'] == 1) ? 'true' : 'false') . ',';
$json .= '"isComplete":' . (($dict['is_complete'] == 1) ? 'true' : 'false') . ',';
$json .= '"isPublic":' . (($dict['is_public'] == 1) ? 'true' : 'false') . '},';
$json .= '"externalID":' . $dict['id'] . '}';
echo $json;
return true;
}
} else {
echo "more than 1 returned";
$query = "SELECT `d`.`id`, `d`.`name`, `d`.`description`, `u`.`public_name`, `d`.`words`, `d`.`next_word_id`, `d`.`allow_duplicates`, `d`.`case_sensitive`, `d`.`parts_of_speech`, `d`.`sort_by_equivalent`, `d`.`is_complete`, `d`.`is_public` ";
$query .= "FROM `dictionaries` AS `d` LEFT JOIN `users` AS `u` ON `user`=`u`.`id` WHERE `d`.`id`=`u`.`current_dictionary` AND `user`=" . $_SESSION['user'] . ";";
$dictionary = query($query);
if ($dictionary) {
if (num_rows($dictionary) > 0) {
if (num_rows($dictionary) === 1) {
while ($dict = fetch($dictionary)) {
$_SESSION['dictionary'] = $dict['id'];
$json = '{"name":"' . $dict['name'] . '",';
$json .= '"description":"' . $dict['description'] . '",';
$json .= '"createdBy":"' . $dict['public_name'] . '",';
$json .= '"words":[' . Get_Dictionary_Words($_SESSION['dictionary']) . '],';
$json .= '"nextWordId":' . $dict['next_word_id'] . ',';
$json .= '"settings":{';
$json .= '"allowDuplicates":' . (($dict['allow_duplicates'] == 1) ? 'true' : 'false') . ',';
$json .= '"caseSensitive":' . (($dict['case_sensitive'] == 1) ? 'true' : 'false') . ',';
$json .= '"partsOfSpeech":"' . $dict['parts_of_speech'] . '",';
$json .= '"sortByEquivalent":' . (($dict['sort_by_equivalent'] == 1) ? 'true' : 'false') . ',';
$json .= '"isComplete":' . (($dict['is_complete'] == 1) ? 'true' : 'false') . ',';
$json .= '"isPublic":' . (($dict['is_public'] == 1) ? 'true' : 'false') . '},';
$json .= '"externalID":' . $dict['id'] . '}';
echo $json;
return true;
}
} else {
echo "no dictionaries";
echo "more than 1 returned";
}
} else {
echo "could not load";
echo "no dictionaries";
}
} else {
echo "not logged in";
echo "could not load";
}
return false;
}
function Save_Current_DictionaryAsNew() {
if ($_SESSION['user'] > 0) {
$dbconnection = new PDO('mysql:host=' . DATABASE_SERVERNAME . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD);
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
function Get_Dictionary_Words($dictionary) {
$query = "SELECT `w`.`word_id`, `w`.`name`, `w`.`pronunciation`, `w`.`part_of_speech`, `w`.`simple_definition`, `w`.`long_definition` ";
$query .= "FROM `words` AS `w` LEFT JOIN `dictionaries` AS `d` ON `w`.`dictionary`=`d`.`id` WHERE `w`.`dictionary`=" . $dictionary . " ";
$query .= "ORDER BY IF(`d`.`sort_by_equivalent`, `w`.`simple_definition`, `w`.`name`) COLLATE utf8_unicode_ci;";
$words = query($query);
$query = "INSERT INTO `dictionaries`(`user`, `is_current`, `name`, `description`, `words`, `next_word_id`, `allow_duplicates`, `case_sensitive`, `parts_of_speech`, `sort_by_equivalent`, `is_complete`, `is_public`) ";
$query .= "VALUES (" . $_SESSION['user'] . ",0,'" . $_POST['name'] . "','" . $_POST['description'] . "','" . $_POST['words'] . "'," . $_POST['nextwordid'] . "," . $_POST['allowduplicates'] . "," . $_POST['casesensitive'] . ",'" . $_POST['partsofspeech'] . "'," . $_POST['sortbyequivalent'] . "," . $_POST['iscomplete'] . "," . $_POST['ispublic'] . ")";
try {
$update = $dbconnection->prepare($query);
$update->execute();
$_SESSION['dictionary'] = $dbconnection->lastInsertId();
$_SESSION['dictionaries'][] = $_SESSION['dictionary']; //Add new id to valid dictionaries.
echo $_SESSION['dictionary'];
Switch_Current_Dictionary($_SESSION['dictionary'], false);
return true;
$results = "";
$processed = 0;
if ($words) {
if (num_rows($words) > 0) {
while ($word = fetch($words)) {
$results .= '{"name":"' . $word['name'] . '",';
$results .= '"pronunciation":"' . $word['pronunciation'] . '",';
$results .= '"partOfSpeech":"' . $word['part_of_speech'] . '",';
$results .= '"simpleDefinition":"' . $word['simple_definition'] . '",';
$results .= '"longDefinition":"' . $word['long_definition'] . '",';
$results .= '"wordId":' . $word['word_id'] . '}';
// If it's the last one, then don't add a comma.
if (++$processed < num_rows($words)) {
$results .= ",";
}
}
}
catch (PDOException $ex) {
$errorMessage = $dbconnection->errorInfo();
echo "could not update:\n" . $errorMessage[2] . "\n" . $query;
}
} else {
echo "not logged in";
}
return $results;
}
function Save_Current_DictionaryAsNew() {
$dbconnection = new PDO('mysql:host=' . DATABASE_SERVERNAME . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD);
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$query = "INSERT INTO `dictionaries`(`user`, `name`, `description`, `next_word_id`, `allow_duplicates`, `case_sensitive`, `parts_of_speech`, `sort_by_equivalent`, `is_complete`, `is_public`) ";
$query .= "VALUES (" . $_SESSION['user'] . ",'" . $_POST['name'] . "','" . $_POST['description'] . "'," . $_POST['nextwordid'] . "," . $_POST['allowduplicates'] . "," . $_POST['casesensitive'] . ",'" . $_POST['partsofspeech'] . "'," . $_POST['sortbyequivalent'] . "," . $_POST['iscomplete'] . "," . $_POST['ispublic'] . ")";
try {
$update = $dbconnection->prepare($query);
$update->execute();
$_SESSION['dictionary'] = $dbconnection->lastInsertId();
$_SESSION['dictionaries'][] = $_SESSION['dictionary']; //Add new id to valid dictionaries.
echo $_SESSION['dictionary'];
Switch_Current_Dictionary($_SESSION['dictionary'], false);
return true;
}
catch (PDOException $ex) {
$errorMessage = $dbconnection->errorInfo();
echo "could not update:\n" . $errorMessage[2] . "\n" . $query;
}
return false;
}
function Update_Current_Dictionary() {
if ($_SESSION['user'] > 0) {
if (isset($_SESSION['dictionary'])) {
$query = "UPDATE `dictionaries` SET ";
if (isset($_POST['name'])) {
$query .= "`name`='" . $_POST['name'] . "', ";
}
if (isset($_POST['description'])) {
$query .= "`description`='" . $_POST['description'] . "', ";
}
if (isset($_POST['words'])) {
$query .= "`words`='" . $_POST['words'] . "', ";
}
if (isset($_POST['nextwordid'])) {
$query .= "`next_word_id`=" . $_POST['nextwordid'] . ", ";
}
if (isset($_POST['allowduplicates'])) {
$query .= "`allow_duplicates`=" . $_POST['allowduplicates'] . ", ";
}
if (isset($_POST['casesensitive'])) {
$query .= "`case_sensitive`=" . $_POST['casesensitive'] . ", ";
}
if (isset($_POST['partsofspeech'])) {
$query .= "`parts_of_speech`='" . $_POST['partsofspeech'] . "', ";
}
if (isset($_POST['sortbyequivalent'])) {
$query .= "`sort_by_equivalent`='" . $_POST['sortbyequivalent'] . "', ";
}
if (isset($_POST['iscomplete'])) {
$query .= "`is_complete`=" . $_POST['iscomplete'] . ", ";
}
if (isset($_POST['ispublic'])) {
$query .= "`is_public`=" . $_POST['ispublic'] . ", ";
}
$query .= "`last_updated`='" . date("Y-m-d H:i:s") . "'";
$query .= " WHERE `id`=" . $_SESSION['dictionary'] . " AND `user`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
echo "updated successfully";
return true;
} else {
echo "could not update";
}
if (isset($_SESSION['dictionary'])) {
$query = "UPDATE `dictionaries` SET ";
if (isset($_POST['name'])) {
$query .= "`name`='" . $_POST['name'] . "', ";
}
if (isset($_POST['description'])) {
$query .= "`description`='" . $_POST['description'] . "', ";
}
if (isset($_POST['nextwordid'])) {
$query .= "`next_word_id`=" . $_POST['nextwordid'] . ", ";
}
if (isset($_POST['allowduplicates'])) {
$query .= "`allow_duplicates`=" . $_POST['allowduplicates'] . ", ";
}
if (isset($_POST['casesensitive'])) {
$query .= "`case_sensitive`=" . $_POST['casesensitive'] . ", ";
}
if (isset($_POST['partsofspeech'])) {
$query .= "`parts_of_speech`='" . $_POST['partsofspeech'] . "', ";
}
if (isset($_POST['sortbyequivalent'])) {
$query .= "`sort_by_equivalent`='" . $_POST['sortbyequivalent'] . "', ";
}
if (isset($_POST['iscomplete'])) {
$query .= "`is_complete`=" . $_POST['iscomplete'] . ", ";
}
if (isset($_POST['ispublic'])) {
$query .= "`is_public`=" . $_POST['ispublic'] . ", ";
}
$query .= "`last_updated`='" . date("Y-m-d H:i:s") . "'";
$query .= " WHERE `id`=" . $_SESSION['dictionary'] . " AND `user`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
echo "updated successfully";
return true;
} else {
Save_Current_DictionaryAsNew();
echo "could not update";
}
} else {
echo "not logged in";
Save_Current_DictionaryAsNew();
}
return false;
}
function Save_New_Word($multiple = false) {
if (in_array($_GET['dict'], $_SESSION['dictionaries'])) { // Make sure that the given dictionary is valid before using it in the query.
// Allows users to update previously open dictionaries if they accidentally change dictionaries while in another window and go back.
$worddata = json_decode(file_get_contents("php://input"), true);
$dbconnection = new PDO('mysql:host=' . DATABASE_SERVERNAME . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD);
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$query = "UPDATE `dictionaries` SET `next_word_id`=" . $_GET['nextwordid'] . ", `last_updated`='" . date("Y-m-d H:i:s") . "' WHERE `id`=" . $_GET['dict'] . "; ";
$query .= "INSERT IGNORE INTO `words`(`dictionary`, `word_id`, `name`, `pronunciation`, `part_of_speech`, `simple_definition`, `long_definition`) ";
$query .= "VALUES ";
if ($multiple) {
for ($i = 0; $i < count($worddata); $i++) {
if ($i > 0) {
$query .= ", ";
}
$query .= "(" . $_GET['dict'] . "," . $worddata[$i]['wordId'] . ",'" . $worddata[$i]['name'] . "','" . $worddata[$i]['pronunciation'] . "','" . $worddata[$i]['partOfSpeech'] . "','" . $worddata[$i]['simpleDefinition'] . "','" . $worddata[$i]['longDefinition'] . "')";
}
} else {
$query .= "(" . $_GET['dict'] . "," . $worddata['wordId'] . ",'" . $worddata['name'] . "','" . $worddata['pronunciation'] . "','" . $worddata['partOfSpeech'] . "','" . $worddata['simpleDefinition'] . "','" . $worddata['longDefinition'] . "')";
}
$query .= ";";
try {
$update = $dbconnection->prepare($query);
$update->execute();
echo "added successfully";
return true;
}
catch (PDOException $ex) {
echo "could not update:\n" . $ex->getMessage() . "\n" . $query;
}
} else {
echo "specified dictionary is not owned by user";
}
return false;
}
function Update_Word() {
if (in_array($_GET['dict'], $_SESSION['dictionaries'])) { // Make sure that the given dictionary is valid before using it in the query.
// Allows users to update previously open dictionaries if they accidentally change dictionaries while in another window and go back.
$worddata = json_decode(file_get_contents("php://input"), true);
$query = "UPDATE `words` SET ";
$query .= "`name`='" . $worddata['name'] . "', ";
$query .= "`pronunciation`='" . $worddata['pronunciation'] . "', ";
$query .= "`part_of_speech`='" . $worddata['partOfSpeech'] . "', ";
$query .= "`simple_definition`='" . $worddata['simpleDefinition'] . "', ";
$query .= "`long_definition`='" . $worddata['longDefinition'] . "', ";
$query .= "`last_updated`='" . date("Y-m-d H:i:s") . "'";
$query .= " WHERE `dictionary`=" . $_GET['dict'] . " AND `word_id`=" . $worddata['wordId'] . ";";
$update = query($query);
if ($update) {
echo "updated successfully";
return true;
} else {
echo "could not update";
}
} else {
echo "specified dictionary is not owned by user";
}
return false;
}
function Switch_Current_Dictionary($newdictionaryid, $returndictionary = true) {
if ($_SESSION['user'] > 0) {
if (isset($newdictionaryid)) {
if (in_array($newdictionaryid, $_SESSION['dictionaries'])) {
//Clear is_current from all user's dictionaries and then update the one they chose, only if the chosen dictionary is valid.
$query = "UPDATE `dictionaries` SET `is_current`=0 WHERE `user`=" . $_SESSION['user'] . ";";
$query .= "UPDATE `dictionaries` SET `is_current`=1 WHERE `id`=" . $newdictionaryid . " AND `user`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
if ($returndictionary) {
Load_Current_Dictionary();
} else {
echo "dictionary switched";
}
// return true;
if (isset($newdictionaryid)) {
if (in_array($newdictionaryid, $_SESSION['dictionaries'])) {
//Clear is_current from all user's dictionaries and then update the one they chose, only if the chosen dictionary is valid.
$query .= "UPDATE `users` SET `current_dictionary`=" . $newdictionaryid . " WHERE `id`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
if ($returndictionary) {
Load_Current_Dictionary();
} else {
echo "could not update";
echo "dictionary switched";
}
// return true;
} else {
echo "invalid dictionary";
echo "could not update";
}
} else {
echo "no info provided";
echo "invalid dictionary";
}
} else {
echo "not logged in";
echo "no info provided";
}
return false;
}
function Delete_Current_Dictionary() {
if ($_SESSION['user'] > 0) {
if (isset($_SESSION['dictionary'])) {
if (in_array($_SESSION['dictionary'], $_SESSION['dictionaries'])) {
//Clear is_current from all user's dictionaries and then update the one they chose, only if the chosen dictionary is valid.
$query = "DELETE FROM `dictionaries` WHERE `id`=" . $_SESSION['dictionary'] . " AND `user`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
Get_Dictionaries(true);
} else {
echo "could not delete";
}
if (isset($_SESSION['dictionary'])) {
if (in_array($_SESSION['dictionary'], $_SESSION['dictionaries'])) {
//Clear is_current from all user's dictionaries and then update the one they chose, only if the chosen dictionary is valid.
$query = "DELETE FROM `dictionaries` WHERE `id`=" . $_SESSION['dictionary'] . " AND `user`=" . $_SESSION['user'] . ";";
$update = query($query);
if ($update) {
Get_Dictionaries(true);
} else {
echo "invalid dictionary";
echo "could not delete";
}
} else {
echo "no current dictionary";
echo "invalid dictionary";
}
} else {
echo "not logged in";
echo "no current dictionary";
}
return false;
}
function Delete_Word() {
if (isset($_SESSION['dictionary'])) {
if (in_array($_POST['dict'], $_SESSION['dictionaries'])) { // Make sure that the given dictionary is valid before using it in the query.
// Allows users to update previously open dictionaries if they accidentally change dictionaries while in another window and go back.
//Clear is_current from all user's dictionaries and then update the one they chose, only if the chosen dictionary is valid.
$query = "DELETE FROM `words` WHERE `dictionary`=" . $_POST['dict'] . " AND `word_id`=" . $_POST['word'] . ";";
$update = query($query);
if ($update) {
echo "deleted successfully";
} else {
echo "could not delete: " . $_POST['dict'] . "-" . $_POST['word'] . " caused a problem";
}
} else {
echo "invalid dictionary";
}
} else {
echo "no current dictionary";
}
return false;
}

11
php/display.php Normal file
View File

@ -0,0 +1,11 @@
<?php
function Show_Dictionary_Function($prevent_edit) {
// Used to determine which JavaScript display function to use.
// $prevent_edit is a boolean value.
if ($prevent_edit) {
echo "ShowPublicDictionary()";
} else {
echo "ShowDictionary()";
}
}
?>

View File

@ -5,5 +5,6 @@ require_once(SITE_LOCATION . '/php/helpers.php');
require_once(SITE_LOCATION . '/php/plugins/easycrypt.php');
require_once(SITE_LOCATION . '/php/validation.php');
require_once(SITE_LOCATION . '/php/passwordreset.php');
require_once(SITE_LOCATION . '/php/display.php');
?>

View File

@ -103,6 +103,7 @@ elseif (isset($_GET['login']) && $current_user <= 0) {
if (EmailExists($_POST['email'])) {
if (Validate_Login($_POST['email'], $_POST['password'])) {
$_SESSION['user'] = Get_User_Id($_POST['email']);
query("UPDATE `users` SET `last_login`='" . date("Y-m-d H:i:s") . "' WHERE `id`=" . $_SESSION['user'] . ";");
} else {
$_SESSION['current_status'] = "loginfailed";
}

View File

@ -1,169 +0,0 @@
<?php
//require_once('../required.php');
require_once('../php/config.php');
require_once(SITE_LOCATION . '/php/functions.php');
session_start();
$current_user = isset($_SESSION['user']) ? $_SESSION['user'] : 0;
$dictionary_to_load = (isset($_GET['dict'])) ? intval($_GET['dict']) : 0;
$the_public_dictionary = '"That dictionary doesn\'t exist."';
$dictionary_name = 'ERROR';
$dictionary_creator = 'nobody';
if ($current_user > 0 || !isset($_SESSION['loginfailures']) || (isset($_SESSION['loginlockouttime']) && time() - $_SESSION['loginlockouttime'] >= 3600)) {
// If logged in, never failed, or more than 1 hour has passed, reset login failures.
$_SESSION['loginfailures'] = 0;
} else {
$alertlockoutmessage = "You failed logging in 10 times. To prevent request flooding and hacking attempts, you may not log in or create an account for 1 hour.\\n\\nThe last time this page was loaded, you had been locked out for " . time_elapsed(time() - $_SESSION['loginlockouttime']) . "\\n\\nRefresh the page once the hour has passed.";
$hoverlockoutmessage = str_replace("\\n", "\n", $alertlockoutmessage);
}
$query = "SELECT `d`.`id`, `d`.`name`, `d`.`description`, `u`.`public_name`, `d`.`words`, `d`.`parts_of_speech`, `d`.`is_complete` ";
$query .= "FROM `dictionaries` AS `d` LEFT JOIN `users` AS `u` ON `d`.`user`=`u`.`id` WHERE `d`.`is_public`=1 AND `d`.`id`=" . $dictionary_to_load . ";";
$dbconnection = new PDO('mysql:host=' . DATABASE_SERVERNAME . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD);
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
try {
$queryResults = $dbconnection->prepare($query);
$queryResults->execute();
if ($queryResults) {
if (num_rows($queryResults) === 1) {
while ($dict = fetch($queryResults)) {
$dictionary_name = $dict['name'];
$dictionary_creator = $dict['public_name'];
$the_public_dictionary = '{"name":"' . $dict['name'] . '",';
$the_public_dictionary .= '"description":"' . $dict['description'] . '",';
$the_public_dictionary .= '"createdBy":"' . $dict['public_name'] . '",';
$the_public_dictionary .= '"words":' . $dict['words'] . ',';
$the_public_dictionary .= '"settings":{';
$the_public_dictionary .= '"partsOfSpeech":"' . $dict['parts_of_speech'] . '",';
$the_public_dictionary .= '"isComplete":' . (($dict['is_complete'] == 1) ? 'true' : 'false') . '},';
$the_public_dictionary .= '}';
}
}
}
}
catch (PDOException $ex) {}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo $dictionary_name; ?> Dictionary on Lexiconga</title>
<meta property="og:url" content="http://lexicon.ga/view/?dict=<?php echo $dictionary_to_load; ?>" />
<meta property="og:type" content="article" />
<meta property="og:title" content="<?php echo $dictionary_name; ?> Dictionary" />
<meta property="og:description" content="A Lexiconga dictionary by <?php echo $dictionary_creator; ?>" />
<meta property="og:image" content="http://lexicon.ga/images/logo.svg" />
<link href="/css/styles.css" rel="stylesheet" />
<link href="/css/lexiconga.css" rel="stylesheet" />
<script>var publicDictionary = <?php echo $the_public_dictionary; ?></script>
</head>
<body>
<header>
<div id="headerPadder">
<a href="/" id="siteLogo">Lexiconga Dictionary Builder</a>
<div style="float:right;margin: 16px 8px;font-size:12px;">
<span id="aboutButton" class="clickable" onclick="ShowInfo('aboutText')">About Lexiconga</span>
</div>
<div id="loginoutArea" style="font-size:12px;">
<a id="loginLink" class="clickable" href="/" title="Go home to log in or create an account.">Go Home</a>
</div>
</div>
</header>
<contents>
<div id="dictionaryContainer">
<h1 id="dictionaryName"></h1>
<h4 id="dictionaryBy"></h4>
<div id="incompleteNotice"></div>
<span id="descriptionToggle" class="clickable" onclick="ToggleDescription();">Hide Description</span>
<div id="dictionaryDescription" style="display:block;"></div>
<span id="searchFilterToggle" class="clickable" onclick="ToggleSearchFilter();">Hide Search/Filter Options</span>
<div id="searchFilterArea" style="display:block;">
<div id="searchArea" style="display:block;">
<label style="margin-top:10px;">
<span>Search</span>
<div style="display:block;">
<input type="text" id="searchBox" onclick="this.select();" onchange="ShowPublicDictionary()" style="display:inline;" />&nbsp;
<span style="display:inline;cursor:pointer;font-size:10px;font-weight:bold;" onclick="document.getElementById('searchBox').value='';ShowPublicDictionary();">Clear Search</span>
</div>
<div id="searchOptions" style="font-size:12px;">
<label style="display:inline;margin:0;">Word <input type="checkbox" id="searchOptionWord" checked="checked" onchange="ShowPublicDictionary()" /></label>&nbsp;&nbsp;
<label style="display:inline;margin:0;">Equivalent <input type="checkbox" id="searchOptionSimple" checked="checked" onchange="ShowPublicDictionary()" /></label>&nbsp;&nbsp;
<label style="display:inline;margin:0;">Explanation <input type="checkbox" id="searchOptionLong" checked="checked" onchange="ShowPublicDictionary()" /></label>
<br />
<label style="display:inline;margin:0;">Search Case-Sensitive <input type="checkbox" id="searchCaseSensitive" onchange="ShowPublicDictionary()" /></label>
<label style="display:inline;margin:0;" title="Note: Matching diacritics will appear but may not highlight.">Ignore Diacritics/Accents <input type="checkbox" id="searchIgnoreDiacritics" onchange="ShowPublicDictionary()" /></label>
</div>
</label>
</div>
<label style="display:block;margin-bottom:0;"><b>Filter Words</b></label>
<div id="filterOptions" style="display:block"></div>
<div style="display:block;">
<span style="display:inline;cursor:pointer;font-size:12px;font-weight:bold;" onclick="ToggleAllFilters(true);ShowPublicDictionary();">Check All</span>&nbsp;/&nbsp;<span style="display:inline;cursor:pointer;font-size:12px;font-weight:bold;" onclick="ToggleAllFilters(false);ShowPublicDictionary();">Uncheck All</span>
</div>
</div>
<div id="filterWordCount"></div>
<div id="theDictionary"></div>
</div>
<div id="rightColumn" class="googleads" style="float:right;width:20%;max-width:300px;min-width:200px;overflow:hidden;">
<?php if ($_GET['adminoverride'] != "noadsortracking") { include_once("../php/google/adsense.php"); } ?>
</div>
<div id="infoScreen" style="display:none;">
<div id="infoBackgroundFade" onclick="HideInfo()"></div>
<div id="infoPage">
<span id="infoScreenCloseButton" class="clickable" onclick="HideInfo()">Close</span>
<div id="infoText"></div>
</div>
</div>
</contents>
<footer>
Dictionary Builder only guaranteed to work with most up-to-date HTML5 browsers. <a href="https://github.com/Alamantus/DictionaryBuilder/issues" target="_blank">Report a Problem</a> | <span class="clickable" onclick="ShowInfo('termsText')" style="font-size:12px;">Terms</span> <span class="clickable" onclick="ShowInfo('privacyText')" style="font-size:12px;">Privacy</span>
</footer>
<!-- Markdown Parser -->
<script src="/js/marked.js"></script>
<!-- JSON Search -->
<script src="/js/defiant.js"></script>
<!-- Diacritics Removal for Exports -->
<script src="/js/removeDiacritics.js"></script>
<!-- Helper Functions -->
<script src="/js/helpers.js"></script>
<!-- Main Functions -->
<script src="/js/dictionaryBuilder.js"></script>
<!-- UI Functions -->
<script src="/js/ui.js"></script>
<!-- Public View Functions -->
<script src="/js/publicView.js"></script>
<?php if ($_GET['adminoverride'] != "noadsortracking") { include_once("../php/google/analytics.php"); } ?>
<script>
var aboutText = termsText = privacyText = loginForm = forgotForm = "Loading...";
window.onload = function () {
ShowPublicDictionary();
SetPublicPartsOfSpeech();
GetTextFile("/README.md", "aboutText", true);
GetTextFile("/TERMS.md", "termsText", true);
GetTextFile("/PRIVACY.md", "privacyText", true);
GetTextFile("/LOGIN.form", "loginForm", false);
GetTextFile("/FORGOT.form", "forgotForm", false);
}
</script>
</body>
</html>