From d914d8f1334b9b55a0b458a4f1f260717ebf791d Mon Sep 17 00:00:00 2001 From: Robbie Antenesse Date: Tue, 20 Sep 2016 15:59:59 -0600 Subject: [PATCH] Started on the path to node compatibility, but it's not usable yet. Need to figure out how to require() defiant.js... --- .gitignore | 1 + package.json | 24 + src/components/login.js | 36 + src/index.html | 19 + src/js/app.js | 877 ++++++++++++++++++++++++ src/js/dependencies/defiant.js | 7 + src/js/dependencies/removeDiacritics.js | 120 ++++ src/js/helpers.js | 256 +++++++ src/js/publicView.js | 194 ++++++ src/js/ui.js | 714 +++++++++++++++++++ src/sass/lexiconga.scss | 149 ++++ src/sass/mobile.scss | 134 ++++ src/sass/styles.scss | 453 ++++++++++++ 13 files changed, 2984 insertions(+) create mode 100644 package.json create mode 100644 src/components/login.js create mode 100644 src/index.html create mode 100644 src/js/app.js create mode 100644 src/js/dependencies/defiant.js create mode 100644 src/js/dependencies/removeDiacritics.js create mode 100644 src/js/helpers.js create mode 100644 src/js/publicView.js create mode 100644 src/js/ui.js create mode 100644 src/sass/lexiconga.scss create mode 100644 src/sass/mobile.scss create mode 100644 src/sass/styles.scss diff --git a/.gitignore b/.gitignore index 9dbb225..7d9e4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ php/google/ ipa_character_picker/ +node_modules/ diff --git a/package.json b/package.json new file mode 100644 index 0000000..9df1146 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "lexiconga", + "title": "Lexiconga", + "version": "1.0.0", + "description": "A tool to build simple dictionaries using JSON.", + "main": "src/app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://Alamantus@github.com/Alamantus/Lexiconga.git" + }, + "author": "Robbie Antenesse ", + "license": "ISC", + "bugs": { + "url": "https://github.com/Alamantus/Lexiconga/issues" + }, + "homepage": "https://github.com/Alamantus/Lexiconga#readme", + "dependencies": { + "marked": "^0.3.6", + "papaparse": "^4.1.2" + } +} diff --git a/src/components/login.js b/src/components/login.js new file mode 100644 index 0000000..3990acc --- /dev/null +++ b/src/components/login.js @@ -0,0 +1,36 @@ +
+

Log In

+ + +
+ +
+ Forgot Password? +
+
+

Create a New Account

+

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.

+

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.

+

By creating an account, you are indicating that you agree to the Terms of Service and that you understand Lexiconga's Privacy Policy.

+ + + + + ? +
+ +
diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..0e556d3 --- /dev/null +++ b/src/index.html @@ -0,0 +1,19 @@ + + + + + + Lexiconga Dictionary Builder + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/js/app.js b/src/js/app.js new file mode 100644 index 0000000..7c38fd9 --- /dev/null +++ b/src/js/app.js @@ -0,0 +1,877 @@ +var publicName = "Someone"; + +var currentDictionary = { + name: "New", + description: "A new dictionary.", + createdBy: publicName, + words: [], + nextWordId: 1, + settings: { + allowDuplicates: false, + caseSensitive: false, + partsOfSpeech: "Noun,Adjective,Verb,Adverb,Preposition,Pronoun,Conjunction", + sortByEquivalent: false, + isComplete: false, + isPublic: false + }, + externalID: 0 +} + +var defaultDictionaryJSON = JSON.stringify(currentDictionary); //Saves a stringifyed default dictionary. +var previousDictionary = {}; + +var savedScroll = { + x: 0, + y: 0 +} + +function AddWord() { + var word = htmlEntities(document.getElementById("word").value).trim(); + var pronunciation = htmlEntities(document.getElementById("pronunciation").value).trim(); + 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 errorMessageArea = document.getElementById("errorMessage"); + var errorMessage = ""; + var updateConflictArea = document.getElementById("updateConflict"); + + if (word != "" && (simpleDefinition != "" || longDefinition != "")) { + var wordIndex = (!currentDictionary.settings.allowDuplicates) ? WordIndex(word) : -1; + + if (wordIndex >= 0) { + if (WordAtIndexWasChanged(wordIndex, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition)) { + document.getElementById("newWordButtonArea").style.display = "none"; + DisableForm(''); + updateConflictArea.style.display = "block"; + + var updateConflictText = "\"" + word + "\" is already in the dictionary"; + if (currentDictionary.words[wordIndex].name != word) { + updateConflictText += " as \"" + currentDictionary.words[wordIndex].name + "\", and your dictionary is set to ignore case."; + } else { + updateConflictText += "." + } + updateConflictText += "
Do you want to update it to what you have set above?
"; + updateConflictText += ''; + updateConflictText += ' '; + + updateConflictArea.innerHTML = updateConflictText; + } else { + errorMessage = "\"" + word + "\" is already in the dictionary exactly as it is written above"; + if (currentDictionary.words[wordIndex].name != word) { + errorMessage += ". (Your dictionary is currently set to ignore case.)" + } + } + } else { + currentDictionary.words.push({name: word, pronunciation: pronunciation, partOfSpeech: ((partOfSpeech.length > 0) ? partOfSpeech : " "), simpleDefinition: simpleDefinition, longDefinition: longDefinition, wordId: currentDictionary.nextWordId++}); + SaveAndUpdateWords("new"); + FocusAfterAddingNewWord(); + NewWordNotification(word); + } + + errorMessageArea.innerHTML = ""; + } else { + if (word == "") { + errorMessage += "Word cannot be blank"; + if (simpleDefinition == "" && longDefinition == "") { + errorMessage += " and you need at least one definition."; + } else { + errorMessage += "."; + } + } else if (simpleDefinition == "" && longDefinition == "") { + errorMessage += "You need at least one definition." + } + } + + errorMessageArea.innerHTML = errorMessage; +} + +function ShowWordEditForm(index) { + var indexString = index.toString(); // Variable for reduced processing + var word = currentDictionary.words[index]; // Reference for easier reading + var editForm = '
\ +

Editing ' + word.name + '

\ + \ + \ + \ + \ + \ + \ +
\ + \ +
\ + \ +
'; + + document.getElementById("entry" + indexString).innerHTML = editForm; + + SetPartsOfSpeech("partOfSpeech" + indexString); + document.getElementById("partOfSpeech" + indexString).value = htmlEntitiesParse(word.partOfSpeech); + + document.getElementById("word" + indexString).focus(); +} + +function CancelEditForm(index) { + document.getElementById("entry" + index.toString()).innerHTML = DictionaryEntry(index).replace("", "").replace("", ""); +} + +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 = "Do you really want to change the word \"" + currentDictionary.words[parseInt(indexString)].name + "\" to what you have set above?
"; + updateConflictArea.innerHTML += ''; + updateConflictArea.innerHTML += ''; + } 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.)"; + } + } + + errorMessageArea.innerHTML = errorMessage; + + if (document.getElementById("updateConfirmButton" + indexString)) { + document.getElementById("updateConfirmButton" + indexString).focus(); + } +} + +function UpdateWord(wordIndex, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition) { + SaveScroll(); + + currentDictionary.words[wordIndex].name = word; + currentDictionary.words[wordIndex].pronunciation = pronunciation; + currentDictionary.words[wordIndex].partOfSpeech = ((partOfSpeech.length > 0) ? partOfSpeech : " "); + currentDictionary.words[wordIndex].simpleDefinition = simpleDefinition; + currentDictionary.words[wordIndex].longDefinition = longDefinition; + + SaveAndUpdateWords("update", wordIndex); + + window.scroll(savedScroll.x, savedScroll.y); + + if (!wordFormIsLocked()) { + FocusAfterAddingNewWord(); + } +} + +function DeleteWord(index) { + 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() { + var filters = 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 xpath = []; + var searchDictionaryJSON = htmlEntitiesParseForSearch(JSON.stringify(currentDictionary)); + if (searchIgnoreCase) { + search = search.toLowerCase(); + } + if (searchIgnoreDiacritics) { + search = removeDiacritics(search); + searchDictionaryJSON = removeDiacritics(searchDictionaryJSON); + } + if (searchByWord) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'name' : 'translate(name, "", "")') +', "'+ search +'")'); + } + if (searchBySimple) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'simpleDefinition' : 'translate(simpleDefinition, "", "")') +', "'+ search +'")'); + } + if (searchByLong) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'longDefinition' : 'translate(longDefinition, "", "")') +', "'+ search +'")'); + } + var searchDictionary = JSON.parse(searchDictionaryJSON); + searchResults = JSON.search(searchDictionary, '//words['+ xpath.join(' or ') +']/wordId'); + } + + var dictionaryNameArea = document.getElementById("dictionaryName"); + dictionaryNameArea.innerHTML = currentDictionary.name + " Dictionary"; + if (loggedIn && currentDictionary.settings.isPublic) { + dictionaryNameArea.innerHTML += ""; + } + + var dictionaryDescriptionArea = document.getElementById("dictionaryDescription"); + dictionaryDescriptionArea.innerHTML = marked(htmlEntitiesParseForMarkdown(currentDictionary.description)); + + var dictionaryArea = document.getElementById("theDictionary"); + var dictionaryText = ""; + var numberOfWordsDisplayed = 0; + + if (currentDictionary.words.length > 0) { + for (var i = 0; i < currentDictionary.words.length; i++) { + if (filters.length == 0 || (filters.length > 0 && filters.indexOf(currentDictionary.words[i].partOfSpeech) > -1)) { + if (search == "" || (search != "" && (searchByWord || searchBySimple || searchByLong) && searchResults.indexOf(currentDictionary.words[i].wordId) >= 0)) { + if (!currentDictionary.words[i].hasOwnProperty("pronunciation")) { + currentDictionary.words[i].pronunciation = ""; //Account for new property + } + if (!currentDictionary.words[i].hasOwnProperty("wordId")) { + currentDictionary.words[i].wordId = i + 1; //Account for new property + } + dictionaryText += DictionaryEntry(i); + numberOfWordsDisplayed++; + } + } + } + } else { + dictionaryText = "There are no entries in the dictionary."; + } + + dictionaryArea.innerHTML = dictionaryText; + ShowFilterWordCount(numberOfWordsDisplayed); +} + +function DictionaryEntry(itemIndex) { + 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; + + var searchRegEx = new RegExp("(" + ((searchIgnoreDiacritics) ? removeDiacritics(searchTerm) + "|" + searchTerm : searchTerm) + ")", "g" + ((searchIgnoreCase) ? "i" : "")); + + var wordName = wordPronunciation = wordPartOfSpeech = wordSimpleDefinition = wordLongDefinition = ""; + + if (searchTerm != "" && searchByWord) { + // Parse HTML Entities while searching so the regex can search actual characters instead of HTML. + wordName += htmlEntities(htmlEntitiesParse(currentDictionary.words[itemIndex].name).replace(searchRegEx, "$1")).replace(/<(\/?)searchterm>/g, '<$1searchterm>'); + } else { + // 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. + } + + if (currentDictionary.words[itemIndex].pronunciation != "") { + wordPronunciation += marked(htmlEntitiesParseForMarkdown(currentDictionary.words[itemIndex].pronunciation)).replace(/<\/?p>/g,""); + } + + if (currentDictionary.words[itemIndex].partOfSpeech != " " && currentDictionary.words[itemIndex].partOfSpeech != "") { + wordPartOfSpeech += currentDictionary.words[itemIndex].partOfSpeech.toString(); + } + + if (currentDictionary.words[itemIndex].simpleDefinition != "") { + if (searchTerm != "" && searchBySimple) { + wordSimpleDefinition += htmlEntities(htmlEntitiesParse(currentDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "$1")).replace(/<(\/?)searchterm>/g, '<$1searchterm>'); + } else { + wordSimpleDefinition += currentDictionary.words[itemIndex].simpleDefinition.toString(); + } + } + + if (currentDictionary.words[itemIndex].longDefinition != "") { + if (searchTerm != "" && searchByLong) { + wordLongDefinition += marked(htmlEntitiesParseForMarkdown(htmlEntities(htmlEntitiesParse(currentDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "$1")))).replace(/<(\/?)searchterm>\;/g, '<$1searchterm>'); + } else { + wordLongDefinition += marked(htmlEntitiesParseForMarkdown(currentDictionary.words[itemIndex].longDefinition)); + } + } + + 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 = "
"; + + managementHTML += "Edit"; + managementHTML += "Delete"; + + managementHTML += ""; + + managementHTML += "
"; + + return managementHTML; +} + +function DictionaryEntryTemplate(wordObject, managementIndex) { + managementIndex = (typeof managementIndex !== 'undefined') ? managementIndex : false; + var entryText = ""; + + if (loggedIn && currentDictionary.settings.isPublic) { + entryText += ""; + } + + entryText += "🔗"; + + entryText += "" + wordObject.name + ""; + + if (wordObject.pronunciation != "") { + entryText += "" + wordObject.pronunciation + ""; + } + + if (wordObject.partOfSpeech != "") { + entryText += "" + wordObject.partOfSpeech + ""; + } + + entryText += "
"; + + if (wordObject.simpleDefinition != "") { + entryText += "" + wordObject.simpleDefinition + ""; + } + + if (wordObject.longDefinition != "") { + entryText += "" + wordObject.longDefinition + ""; + } + + if (managementIndex !== false) { + entryText += ManagementArea(managementIndex); + } + + entryText += "
"; + + return entryText; +} + +function SaveSettings() { + if (htmlEntities(document.getElementById("dictionaryNameEdit").value) != "") { + currentDictionary.name = htmlEntities(document.getElementById("dictionaryNameEdit").value); + } + + currentDictionary.description = htmlEntities(document.getElementById("dictionaryDescriptionEdit").value); + + CheckForPartsOfSpeechChange(); + + currentDictionary.settings.allowDuplicates = document.getElementById("dictionaryAllowDuplicates").checked; + currentDictionary.settings.caseSensitive = document.getElementById("dictionaryCaseSensitive").checked; + + currentDictionary.settings.sortByEquivalent = document.getElementById("dictionarySortByEquivalent").checked; + + currentDictionary.settings.isComplete = document.getElementById("dictionaryIsComplete").checked; + if (document.getElementById("dictionaryIsPublic")) { + currentDictionary.settings.isPublic = document.getElementById("dictionaryIsPublic").checked; + } + + HideSettingsWhenComplete(); + + SaveAndUpdateDictionary(true); + LoadUserDictionaries(); +} + +function EmptyWholeDictionary() { + if (confirm("This will delete the entire current dictionary. If you do not have a backed up export, you will lose it forever!\n\nDo you still want to delete?")) { + CreateNewDictionary(); + } +} + +function CreateNewDictionary() { + ResetDictionaryToDefault(); + SaveAndUpdateDictionary(false); + SetPartsOfSpeech(); + HideSettings(); + ShowSettings(); + document.getElementById("dictionaryNameEdit").focus(); +} + +function DeleteCurrentDictionary() { + if (confirm("This will delete the current dictionary from the database. If you do not have a backed up export, you will lose it forever!\n\nDo you still want to delete?")) { + ResetDictionaryToDefault(); + + var deleteDictionary = new XMLHttpRequest(); + 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) { + if (deleteDictionary.responseText.length < 31) { + console.log(deleteDictionary.responseText); + CreateNewDictionary(); + } else { + HideSettings(); + ShowDictionaryDeleteMenu(deleteDictionary.responseText); + + if (document.getElementById("loadAfterDelete").options.length == 0) { + document.getElementById('loadAfterDeleteScreen').style.display = 'none'; + CreateNewDictionary(); + } + } + return true; + } else { + return false; + } + } + deleteDictionary.send(); + } +} + + +function ResetDictionaryToDefault() { + currentDictionary = JSON.parse(defaultDictionaryJSON); +} + +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(false); + ProcessLoad(); +} + +function SaveAndUpdateDictionary(keepFormContents) { + SaveDictionary(true); + ShowDictionary(); + if (!keepFormContents) { + ClearForm(); + } + CloseUpdateConflictArea(''); +} + +function SaveDictionary(sendToDatabase) { + //Always save local copy of current dictionary, but if logged in also send to database. + if (sendToDatabase) { + SendDictionary(); + } + + localStorage.setItem('dictionary', JSON.stringify(currentDictionary)); + + SavePreviousDictionary(); +} + +function SendDictionary() { + var action = ""; + var postString = ""; + if (currentDictionary.externalID > 0) { + action = "update"; + postString = DataToSend(false); + } else { + action = "new"; + postString = DataToSend(true); + } + + var sendDictionary = new XMLHttpRequest(); + 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) { + if (sendDictionary.responseText == "updated successfully") { + console.log(sendDictionary.responseText); + LoadUserDictionaries(); + ProcessLoad(); + } else if (isNaN(parseInt(sendDictionary.responseText))) { + 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 " + parseInt(sendDictionary.responseText).toString() + " successfully"); + } + return true; + } else { + return false; + } + } + sendDictionary.send(postString); +} + +function DataToSend(sendAll) { + sendAll = (typeof sendAll !== 'undefined' && sendAll != null) ? sendAll : false; + var data = ""; + if (currentDictionary.externalID == 0) { + data = "name=" + encodeURIComponent(currentDictionary.name) + "&description=" + encodeURIComponent(currentDictionary.description) + "&words=" + encodeURIComponent(JSON.stringify(currentDictionary.words)); + data += "&nextwordid=" + currentDictionary.nextWordId + "&allowduplicates=" + ((currentDictionary.settings.allowDuplicates) ? "1" : "0") + "&casesensitive=" + ((currentDictionary.settings.caseSensitive) ? "1" : "0"); + data += "&partsofspeech=" + encodeURIComponent(currentDictionary.settings.partsOfSpeech) + "&sortbyequivalent=" + ((currentDictionary.settings.sortByEquivalent) ? "1" : "0") + "&iscomplete=" + ((currentDictionary.settings.isComplete) ? "1" : "0") + "&ispublic=" + ((currentDictionary.settings.isPublic) ? "1" : "0") + ""; + } else { + if (sendAll || currentDictionary.name != previousDictionary.name) { + data += "name=" + encodeURIComponent(currentDictionary.name); + } + if (sendAll || currentDictionary.description != previousDictionary.description) { + data += ((data=="") ? "" : "&") + "description=" + encodeURIComponent(currentDictionary.description); + } + if (sendAll || currentDictionary.nextWordId != previousDictionary.nextWordId) { + data += ((data=="") ? "" : "&") + "nextwordid=" + currentDictionary.nextWordId; + } + if (sendAll || currentDictionary.settings.allowDuplicates != previousDictionary.allowDuplicates) { + data += ((data=="") ? "" : "&") + "allowduplicates=" + ((currentDictionary.settings.allowDuplicates) ? "1" : "0"); + } + if (sendAll || currentDictionary.settings.caseSensitive != previousDictionary.caseSensitive) { + data += ((data=="") ? "" : "&") + "casesensitive=" + ((currentDictionary.settings.caseSensitive) ? "1" : "0"); + } + if (sendAll || currentDictionary.settings.partsOfSpeech != previousDictionary.partsOfSpeech) { + data += ((data=="") ? "" : "&") + "partsofspeech=" + encodeURIComponent(currentDictionary.settings.partsOfSpeech); + } + if (sendAll || currentDictionary.settings.sortByEquivalent != previousDictionary.sortByEquivalent) { + data += ((data=="") ? "" : "&") + "sortbyequivalent=" + ((currentDictionary.settings.sortByEquivalent) ? "1" : "0"); + } + if (sendAll || currentDictionary.settings.isComplete != previousDictionary.isComplete) { + data += ((data=="") ? "" : "&") + "iscomplete=" + ((currentDictionary.settings.isComplete) ? "1" : "0"); + } + if (sendAll || currentDictionary.settings.isPublic != previousDictionary.isPublic) { + data += ((data=="") ? "" : "&") + "ispublic=" + ((currentDictionary.settings.isPublic) ? "1" : "0"); + } + } + return data; +} + +function LoadDictionary() { + LoadLocalDictionary(); + var loadDictionary = new XMLHttpRequest(); + loadDictionary.open('GET', "/php/ajax_dictionarymanagement.php?action=load"); + loadDictionary.onreadystatechange = function() { + if (loadDictionary.readyState == 4 && loadDictionary.status == 200) { + if (loadDictionary.responseText == "no dictionaries") { + // If there are no dictionaries in the database and there's one in memory, remove the id & public setting and send it as a new one. + currentDictionary.externalID = 0; + currentDictionary.settings.isPublic = false; + SendDictionary(true); + } else if (loadDictionary.responseText.length < 60) { + console.log(loadDictionary.responseText); + } else { + currentDictionary = JSON.parse(loadDictionary.responseText); + SaveDictionary(false); + } + } + ProcessLoad(); + } + loadDictionary.send(); +} + +function ChangeDictionary(userDictionariesSelect) { + userDictionariesSelect = (typeof userDictionariesSelect !== 'undefined' && userDictionariesSelect != null) ? userDictionariesSelect : document.getElementById("userDictionaries"); + if (currentDictionary.externalID != userDictionariesSelect.value && userDictionariesSelect.options.length > 0) { + // Show the info page with loading screen and hide settings and stuff. + ShowInfoWithText("

Loading " + userDictionariesSelect.options[userDictionariesSelect.selectedIndex].text + "...

"); + HideSettings(); + + ChangeDictionaryToId(userDictionariesSelect.value, function(response) { + if (response == "no dictionaries") { + console.log(response); + SendDictionary(false); + } else if (response.length < 60) { + console.log(response); + } else { + currentDictionary = JSON.parse(response); + SaveDictionary(false); + ProcessLoad(); + LoadUserDictionaries(); + 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() { + if (localStorage.getItem('dictionary')) { + var tmpDictionary = JSON.parse(localStorage.getItem('dictionary')); + if (tmpDictionary.words.length > 0 || tmpDictionary.description != "A new dictionary." || tmpDictionary.name != "New") { + currentDictionary = JSON.parse(localStorage.getItem('dictionary')); + } + tmpDictionary = null; + } +} + +function ProcessLoad() { + if (!currentDictionary.hasOwnProperty("nextWordId")) { + currentDictionary.nextWordId = currentDictionary.words.length + 1; + } + + HideSettingsWhenComplete(); + + ShowDictionary(); + + SetPartsOfSpeech(); + + if (currentDictionary.settings.isComplete) { + document.getElementById("wordEntryForm").style.display = "none"; + } + + SavePreviousDictionary(); +} + +function SavePreviousDictionary () { + // Save non-word data to check if anything has changed (words can identify themselves if changed). + // Used to minimize data pushed to database. + previousDictionary = { + name: currentDictionary.name, + description: currentDictionary.description, + nextWordId: currentDictionary.nextWordId, + allowDuplicates: currentDictionary.settings.allowDuplicates, + caseSensitive: currentDictionary.settings.caseSensitive, + partsOfSpeech: currentDictionary.settings.partsOfSpeech, + sortByEquivalent: currentDictionary.settings.sortByEquivalent, + isComplete: currentDictionary.settings.isComplete, + isPublic: currentDictionary.settings.isPublic + }; +} + +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"; + } + downloadName += "_words"; + + var wordsCSV = "word,pronunciation,part of speech,definition,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."); + } +} + +function ImportDictionary() { + if (currentDictionary.externalID > 0 || confirm("Importing this dictionary will overwrite your current one, making it impossible to retrieve if you have not already exported it! Do you still want to import?")) { + if (!window.FileReader) { + alert('Your browser is not supported'); + return false; + } + + var reader = new FileReader(); + if (document.getElementById("importFile").files.length > 0) { + var file = document.getElementById("importFile").files[0]; + // Read the file + reader.readAsText(file); + // When it's loaded, process it + reader.onloadend = function () { + if (reader.result && reader.result.length) { + var tmpDicitonary = JSON.parse(reader.result); + + if (tmpDicitonary.hasOwnProperty("name") && tmpDicitonary.hasOwnProperty("description") && + tmpDicitonary.hasOwnProperty("words") && tmpDicitonary.hasOwnProperty("settings")) + { + 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); + ProcessLoad(); + HideInfo(); + HideSettings(); + document.getElementById("importFile").value = ""; + NewNotification("Successfully Imported the \"" + currentDictionary.name + "\" Dictionary."); + } else { + var errorString = "File is missing:"; + if (!tmpDicitonary.hasOwnProperty("name")) + errorString += " name"; + if (!tmpDicitonary.hasOwnProperty("description")) + errorString += " description"; + if (!tmpDicitonary.hasOwnProperty("words")) + errorString += " words"; + if (!tmpDicitonary.hasOwnProperty("settings")) + errorString += " settings"; + alert("Uploaded file is not compatible.\n\n" + errorString); + } + + tmpDicitonary = null; + } else { + alert("Upload Failed"); + } + reader = null; + } + } else { + alert("You must add a file to import."); + } + } +} + +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 = "

Importing Words...

"; + + 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 definition or explanation contain data, then import it. + if ((row.data[0].word.trim().length > 0 && (row.data[0].definition.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]["definition"]).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 += "

Error on record #" + currentRow.toString() + ": " + row.errors[i].message + "

"; + } + } + } + // Scroll to the bottom. + document.getElementById("infoPage").scrollTop = document.getElementById("infoPage").scrollHeight; + }, + complete: function(results) { + SaveAndUpdateWords("all"); + resultsArea.innerHTML += "

The file has finished importing " + rowsImported.toString() + " words.

"; + 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 ((!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; + } + } + return -1; +} + +function WordAtIndexWasChanged(indexString, word, pronunciation, partOfSpeech, simpleDefinition, longDefinition) { + return (!currentDictionary.settings.caseSensitive && currentDictionary.words[parseInt(indexString)].name.toLowerCase() != word.toLowerCase()) || + (currentDictionary.settings.caseSensitive && currentDictionary.words[parseInt(indexString)].name != word) || + currentDictionary.words[parseInt(indexString)].pronunciation != pronunciation || + currentDictionary.words[parseInt(indexString)].partOfSpeech.trim() != partOfSpeech || + currentDictionary.words[parseInt(indexString)].simpleDefinition != simpleDefinition || + currentDictionary.words[parseInt(indexString)].longDefinition != longDefinition; +} + +function CheckForPartsOfSpeechChange() { + if (htmlEntities(document.getElementById("dictionaryPartsOfSpeechEdit").value) != currentDictionary.settings.partsOfSpeech) { + if (htmlEntities(document.getElementById("dictionaryPartsOfSpeechEdit").value) != "") { + currentDictionary.settings.partsOfSpeech = htmlEntities(document.getElementById("dictionaryPartsOfSpeechEdit").value); + SetPartsOfSpeech(); + } + } +} diff --git a/src/js/dependencies/defiant.js b/src/js/dependencies/defiant.js new file mode 100644 index 0000000..bc041fb --- /dev/null +++ b/src/js/dependencies/defiant.js @@ -0,0 +1,7 @@ +/* + * defiant.js [v1.4.0] + * http://www.defiantjs.com + * Copyright (c) 2013-2016, Hakan Bilgin + * Licensed under the MIT License + */ +if(function(t,e,r){"use strict";var n={is_ie:/(msie|trident)/i.test(navigator.userAgent),is_safari:/safari/i.test(navigator.userAgent),env:"production",xml_decl:'',namespace:'xmlns:d="defiant-namespace"',tabsize:4,render:function(t,e){var r,n,a,s,o=new XSLTProcessor,i=document.createElement("span"),l={match:"/"};switch(typeof t){case"object":this.extend(l,t),l.data||(l.data=e);break;case"string":l.template=t,l.data=e;break;default:throw"error"}if(l.data=JSON.toXML(l.data),r='//xsl:template[@name="'+l.template+'"]',this.xsl_template||this.gatherTemplates(),l.sorter&&(s=this.node.selectSingleNode(this.xsl_template,r+"//xsl:for-each//xsl:sort"),s&&(l.sorter.order&&s.setAttribute("order",l.sorter.order),l.sorter.select&&s.setAttribute("select",l.sorter.select),s.setAttribute("data-type",l.sorter.type||"text"))),a=this.node.selectSingleNode(this.xsl_template,r),a.setAttribute("match",l.match),o.importStylesheet(this.xsl_template),i.appendChild(o.transformToFragment(l.data,document)),a.removeAttribute("match"),this.is_safari){n=i.getElementsByTagName("script");for(var c=0,u=n.length;u>c;c++)n[c].defer=!0}return i.innerHTML},gatherTemplates:function(){for(var t=document.getElementsByTagName("script"),e="",r=0,n=t.length;n>r;r++)"defiant/xsl-template"===t[r].type&&(e+=t[r].innerHTML);this.xsl_template=this.xmlFromString('"+e.replace(/defiant:(\w+)/g,"$1")+"")},getSnapshot:function(t,e){return JSON.toXML(t,e||!0)},xmlFromString:function(t){var e,r;return t=t.replace(/>\s{1,}<"),null===t.trim().match(/<\?xml/)&&(t=this.xml_decl+t),"undefined"!=typeof ActiveXObject?(r=new ActiveXObject("Msxml2.DOMDocument"),r.loadXML(t),-1===t.indexOf("xsl:stylesheet")&&r.setProperty("SelectionLanguage","XPath")):(e=new DOMParser,r=e.parseFromString(t,"text/xml")),r},extend:function(t,e){for(var r in e)t[r]&&"object"==typeof e[r]?this.extend(t[r],e[r]):t[r]=e[r];return t},node:{}};t.Defiant=e.exports=n}("undefined"!=typeof window?window:{},"undefined"!=typeof module?module:{}),"undefined"==typeof XSLTProcessor){var XSLTProcessor=function(){};XSLTProcessor.prototype={importStylesheet:function(t){this.xsldoc=t},transformToFragment:function(t,e){var r=t.transformNode(this.xsldoc),n=document.createElement("span");return n.innerHTML=r,n}}}else if("function"!=typeof XSLTProcessor&&!XSLTProcessor)throw"XSLTProcessor transformNode not implemented";String.prototype.fill||(String.prototype.fill=function(t,e){var r=this;for(e=e||" ";r.length/,rx_constructor:/<(.+?)( d:contr=".*?")>/,rx_namespace:/ xmlns\:d="defiant\-namespace"/,rx_data:/(<.+?>)(.*?)(<\/d:data>)/i,rx_function:/function (\w+)/i,namespace:'xmlns:d="defiant-namespace"',to_xml_str:function(t){return{str:this.hash_to_xml(null,t),map:this.map}},hash_to_xml:function(t,e,r){var n,a,s,o,i,l,c,u,d,m=e.constructor===Array,h=this,p=[],f=[],g=function(e,n){if(a=n[e],(null===a||void 0===a||"NaN"===a.toString())&&(a=null),o="@"===e.slice(0,1),i=r?t:e,i==+i&&n.constructor!==Object&&(i="d:item"),null===a?(l=null,c=!1):(l=a.constructor,c=l.toString().match(h.rx_function)[1]),o)f.push(i.slice(1)+'="'+h.escape_xml(a)+'"'),"String"!==c&&f.push("d:"+i.slice(1)+'="'+c+'"');else if(null===a)p.push(h.scalar_to_xml(i,a));else switch(l){case Function:throw"JSON data should not contain functions. Please check your structure.";case Object:p.push(h.hash_to_xml(i,a));break;case Array:if(e===i){if(s=a.constructor===Array)for(u=a.length;u--;)null!==a[u]&&a[u]&&a[u].constructor!==Array||(s=!0),s||a[u].constructor!==Object||(s=!0);p.push(h.scalar_to_xml(i,a,s));break}case String:if("string"==typeof a&&(a=a.toString().replace(/\&/g,"&").replace(/\r|\n/g," ")),"#text"===i){h.map.push(n),f.push('d:mi="'+h.map.length+'"'),f.push('d:constr="'+c+'"'),p.push(h.escape_xml(a));break}case Number:case Boolean:if("#text"===i&&"String"!==c){h.map.push(n),f.push('d:mi="'+h.map.length+'"'),f.push('d:constr="'+c+'"'),p.push(h.escape_xml(a));break}p.push(h.scalar_to_xml(i,a))}};if(e.constructor===Array)for(u=0,d=e.length;d>u;u++)g(u.toString(),e);else for(n in e)g(n,e);return t||(t="d:data",f.push(this.namespace),m&&f.push('d:constr="Array"')),null===t.match(this.rx_validate_name)&&(f.push('d:name="'+t+'"'),t="d:name"),r?p.join(""):(this.map.push(e),f.push('d:mi="'+this.map.length+'"'),"<"+t+(f.length?" "+f.join(" "):"")+(p.length?">"+p.join("")+"":"/>"))},scalar_to_xml:function(t,e,r){var n,a,s,o="";if(null===t.match(this.rx_validate_name)&&(o+=' d:name="'+t+'"',t="d:name",r=!1),(null===e||"NaN"===e.toString())&&(e=null),null===e)return"<"+t+' d:constr="null"/>';if(1===e.length&&e.constructor===Array&&!e[0])return"<"+t+' d:constr="null" d:type="ArrayItem"/>';if(1===e.length&&e[0].constructor===Object){n=this.hash_to_xml(!1,e[0]);var i=n.match(this.rx_node),l=n.match(this.rx_constructor);return i=null!==i?i[2].replace(this.rx_namespace,"").replace(/>/,"").replace(/"\/$/,'"'):"",l=null!==l?l[2]:"",n=n.match(this.rx_data),n=null!==n?n[2]:"","<"+t+i+" "+l+' d:type="ArrayItem">'+n+""}return 0===e.length&&e.constructor===Array?"<"+t+' d:constr="Array"/>':r?this.hash_to_xml(t,e,!0):(a=e.constructor,s=a.toString().match(this.rx_function)[1],n=a===Array?this.hash_to_xml("d:item",e,!0):this.escape_xml(e),o+=' d:constr="'+s+'"',this.map.push(e),o+=' d:mi="'+this.map.length+'"',"#text"===t?this.escape_xml(e):"<"+t+o+">"+n+"")},escape_xml:function(t){return String(t).replace(//g,">").replace(/"/g,""").replace(/ /g," ")}};switch(typeof e){case"function":return a=x10.compile(s),void a.to_xml_str(t,function(r){e({doc:Defiant.xmlFromString(r.str),src:t,map:r.map})});case"boolean":return r=s.to_xml_str.call(s,t),{doc:Defiant.xmlFromString(r.str),src:t,map:r.map};default:return r=s.to_xml_str.call(s,t),n=Defiant.xmlFromString(r.str),this.search.map=r.map,n}}),JSON.search||(JSON.search=function(t,e,r){"use strict";var n,a,s=t.doc&&t.doc.nodeType,o=s?t.doc:JSON.toXML(t),i=s?t.map:this.search.map,l=s?t.src:t,c=Defiant.node[r?"selectSingleNode":"selectNodes"](o,e.xTransform()),u=[];for(r&&(c=[c]),a=c.length;a--;)switch(c[a].nodeType){case 2:case 3:u.unshift(c[a].nodeValue);break;default:n=+c[a].getAttribute("d:mi"),u.unshift(i[n-1])}return"development"===Defiant.env&&(this.trace=JSON.mtrace(l,u,c)),u}),JSON.mtrace||(JSON.mtrace=function(t,e,r){"use strict";for(var n,a,s,o,i,l=window,c=JSON.stringify,u=c(t,null," ").replace(/\t/g,""),d=[],m=0,h=r.length,p=h?r[m].ownerDocument.documentElement:!1,f=(this.search.map,0);h>m;m++){switch(r[m].nodeType){case 2:a=r[m].ownerElement?r[m].ownerElement.getAttribute("d:"+r[m].nodeName):"String",n='"@'+r[m].nodeName+'": '+l[a](e[m]),s=u.indexOf(n),i=0;break;case 3:a=r[m].parentNode.getAttribute("d:constr"),n=l[a](e[m]),n='"'+r[m].parentNode.nodeName+'": '+("Number"===n?n:'"'+n+'"'),s=u.indexOf(n),i=0;break;default:if(r[m]===p)continue;"String"===r[m].getAttribute("d:constr")||"Number"===r[m].getAttribute("d:constr")?(a=r[m].getAttribute("d:constr"),n=l[a](e[m]),s=u.indexOf(n,f),n='"'+r[m].nodeName+'": '+("Number"===a?n:'"'+n+'"'),i=0,f=s+1):(n=c(e[m],null," ").replace(/\t/g,""),s=u.indexOf(n),i=n.match(/\n/g).length)}o=u.substring(0,s).match(/\n/g).length+1,d.push([o,i])}return d}),Defiant.node.selectNodes=function(t,e){if(t.evaluate){for(var r=t.createNSResolver(t.documentElement),n=t.evaluate(e,t,r,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null),a=[],s=0,o=n.snapshotLength;o>s;s++)a.push(n.snapshotItem(s));return a}return t.selectNodes(e)},Defiant.node.selectSingleNode=function(t,e){if(t.evaluate){var r=this.selectNodes(t,e);return r.length>0?r[0]:null}return t.selectSingleNode(e)},Defiant.node.prettyPrint=function(t){var e,r,n=Defiant,a=n.tabsize,s=n.xml_decl.toLowerCase();n.is_ie?r=t.xml:(e=new XMLSerializer,r=e.serializeToString(t)),"development"!==n.env&&(r=r.replace(/ \w+\:d=".*?"| d\:\w+=".*?"/g,""));for(var o,i,l=r.trim().replace(/(>)\s*(<)(\/*)/g,"$1\n$2$3"),c=l.split("\n"),u=-1,d=0,m=c.length;m>d;d++)(0!==d||c[d].toLowerCase()!==s)&&(o=null!==c[d].match(/<[A-Za-z_\:]+.*?>/g),i=null!==c[d].match(/<\/[\w\:]+>/g),null!==c[d].match(/<.*?\/>/g)&&(o=i=!0),o&&u++,c[d]=String().fill(u," ")+c[d],o&&i&&u--,!o&&i&&u--);return c.join("\n").replace(/\t/g,String().fill(a," "))},Defiant.node.toJSON=function(t,e){"use strict";var r=function(t){var e,n,a,s,o,i,l,c,u,d,m={},h=window;switch(t.nodeType){case 1:for(o=t.getAttribute("d:constr"),"Array"===o?m=[]:"String"===o&&""===t.textContent&&(m=""),e=t.attributes,c=0,u=e.length;u>c;c++)d=e.item(c),null===d.nodeName.match(/\:d|d\:/g)&&(o=t.getAttribute("d:"+d.nodeName),i=o&&"undefined"!==o?"null"===d.nodeValue?null:h[o]("false"===d.nodeValue?"":d.nodeValue):d.nodeValue,m["@"+d.nodeName]=i);break;case 3:n=t.parentNode.getAttribute("d:type"),i=n?h[n]("false"===t.nodeValue?"":t.nodeValue):t.nodeValue,m=i}if(t.hasChildNodes())for(c=0,u=t.childNodes.length;u>c;c++)if(a=t.childNodes.item(c),s=a.nodeName,e=t.attributes,"d:name"===s&&(s=a.getAttribute("d:name")),"#text"===s)o=t.getAttribute("d:constr"),"undefined"===o&&(o=void 0),l=a.textContent||a.text,i="Boolean"===o&&"false"===l?"":l,o||e.length?o&&1===u?m=h[o](i):t.hasChildNodes()&&e.length<3?m=o?h[o](i):i:m[s]=o?h[o](i):i:m=i;else{if("null"===a.getAttribute("d:constr")){m[s]&&m[s].push?m[s].push(null):"ArrayItem"===a.getAttribute("d:type")?m[s]=[m[s]]:m[s]=null;continue}if(m[s]){m[s].push?m[s].push(r(a)):m[s]=[m[s],r(a)];continue}switch(o=a.getAttribute("d:constr")){case"null":m.push?m.push(null):m[s]=null;break;case"Array":a.parentNode.firstChild===a&&"Array"===o&&"d:item"!==s?"d:item"===s||"Array"===o?(i=r(a),m[s]=i.length?[i]:i):m[s]=r(a):m.push?m.push(r(a)):m[s]=r(a);break;case"String":case"Number":case"Boolean":l=a.textContent||a.text,i="Boolean"===o&&"false"===l?"":l,m.push?m.push(h[o](i)):m[s]=r(a);break;default:m.push?m.push(r(a)):m[s]=r(a)}}return 1===t.nodeType&&"ArrayItem"===t.getAttribute("d:type")&&(m=[m]),m},n=9===t.nodeType?t.documentElement:t,a=r(n),s=a[n.nodeName];return n===n.ownerDocument.documentElement&&s&&s.constructor===Array&&(a=s),e&&"true"===e.toString()&&(e=" "),e?JSON.stringify(a,null,e):a},"undefined"!=typeof jQuery&&!function(t){"use strict";t.fn.defiant=function(t,e){return this.html(Defiant.render(t,e)),this}}(jQuery); \ No newline at end of file diff --git a/src/js/dependencies/removeDiacritics.js b/src/js/dependencies/removeDiacritics.js new file mode 100644 index 0000000..981724e --- /dev/null +++ b/src/js/dependencies/removeDiacritics.js @@ -0,0 +1,120 @@ +/* + Retrieved from http://stackoverflow.com/a/18391901/3508346 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +// "what?" version ... http://jsperf.com/diacritics/12 +function removeDiacritics(str) { + var defaultDiacriticsRemovalap = [ + {'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'}, + {'base':'AA','letters':'\uA732'}, + {'base':'AE','letters':'\u00C6\u01FC\u01E2'}, + {'base':'AO','letters':'\uA734'}, + {'base':'AU','letters':'\uA736'}, + {'base':'AV','letters':'\uA738\uA73A'}, + {'base':'AY','letters':'\uA73C'}, + {'base':'B', 'letters':'\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'}, + {'base':'C', 'letters':'\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'}, + {'base':'D', 'letters':'\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779'}, + {'base':'DZ','letters':'\u01F1\u01C4'}, + {'base':'Dz','letters':'\u01F2\u01C5'}, + {'base':'E', 'letters':'\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'}, + {'base':'F', 'letters':'\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'}, + {'base':'G', 'letters':'\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'}, + {'base':'H', 'letters':'\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'}, + {'base':'I', 'letters':'\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'}, + {'base':'J', 'letters':'\u004A\u24BF\uFF2A\u0134\u0248'}, + {'base':'K', 'letters':'\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'}, + {'base':'L', 'letters':'\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'}, + {'base':'LJ','letters':'\u01C7'}, + {'base':'Lj','letters':'\u01C8'}, + {'base':'M', 'letters':'\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'}, + {'base':'N', 'letters':'\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'}, + {'base':'NJ','letters':'\u01CA'}, + {'base':'Nj','letters':'\u01CB'}, + {'base':'O', 'letters':'\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'}, + {'base':'OI','letters':'\u01A2'}, + {'base':'OO','letters':'\uA74E'}, + {'base':'OU','letters':'\u0222'}, + {'base':'OE','letters':'\u008C\u0152'}, + {'base':'oe','letters':'\u009C\u0153'}, + {'base':'P', 'letters':'\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'}, + {'base':'Q', 'letters':'\u0051\u24C6\uFF31\uA756\uA758\u024A'}, + {'base':'R', 'letters':'\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'}, + {'base':'S', 'letters':'\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'}, + {'base':'T', 'letters':'\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'}, + {'base':'TZ','letters':'\uA728'}, + {'base':'U', 'letters':'\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'}, + {'base':'V', 'letters':'\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'}, + {'base':'VY','letters':'\uA760'}, + {'base':'W', 'letters':'\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'}, + {'base':'X', 'letters':'\u0058\u24CD\uFF38\u1E8A\u1E8C'}, + {'base':'Y', 'letters':'\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'}, + {'base':'Z', 'letters':'\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'}, + {'base':'a', 'letters':'\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'}, + {'base':'aa','letters':'\uA733'}, + {'base':'ae','letters':'\u00E6\u01FD\u01E3'}, + {'base':'ao','letters':'\uA735'}, + {'base':'au','letters':'\uA737'}, + {'base':'av','letters':'\uA739\uA73B'}, + {'base':'ay','letters':'\uA73D'}, + {'base':'b', 'letters':'\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'}, + {'base':'c', 'letters':'\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'}, + {'base':'d', 'letters':'\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'}, + {'base':'dz','letters':'\u01F3\u01C6'}, + {'base':'e', 'letters':'\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'}, + {'base':'f', 'letters':'\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'}, + {'base':'g', 'letters':'\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'}, + {'base':'h', 'letters':'\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'}, + {'base':'hv','letters':'\u0195'}, + {'base':'i', 'letters':'\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'}, + {'base':'j', 'letters':'\u006A\u24D9\uFF4A\u0135\u01F0\u0249'}, + {'base':'k', 'letters':'\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'}, + {'base':'l', 'letters':'\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'}, + {'base':'lj','letters':'\u01C9'}, + {'base':'m', 'letters':'\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'}, + {'base':'n', 'letters':'\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'}, + {'base':'nj','letters':'\u01CC'}, + {'base':'o', 'letters':'\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'}, + {'base':'oi','letters':'\u01A3'}, + {'base':'ou','letters':'\u0223'}, + {'base':'oo','letters':'\uA74F'}, + {'base':'p','letters':'\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'}, + {'base':'q','letters':'\u0071\u24E0\uFF51\u024B\uA757\uA759'}, + {'base':'r','letters':'\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'}, + {'base':'s','letters':'\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'}, + {'base':'t','letters':'\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'}, + {'base':'tz','letters':'\uA729'}, + {'base':'u','letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'}, + {'base':'v','letters':'\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'}, + {'base':'vy','letters':'\uA761'}, + {'base':'w','letters':'\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'}, + {'base':'x','letters':'\u0078\u24E7\uFF58\u1E8B\u1E8D'}, + {'base':'y','letters':'\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'}, + {'base':'z','letters':'\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'} + ]; + + var diacriticsMap = {}; + for (var i=0; i < defaultDiacriticsRemovalap.length; i++){ + var letters = defaultDiacriticsRemovalap[i].letters; + for (var j=0; j < letters.length ; j++){ + diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base; + } + } + + return str.replace(/[^\u0000-\u007E]/g, function(a){ + return diacriticsMap[a] || a; + }); +} + +modules.export = removeDiacritics; \ No newline at end of file diff --git a/src/js/helpers.js b/src/js/helpers.js new file mode 100644 index 0000000..e534d42 --- /dev/null +++ b/src/js/helpers.js @@ -0,0 +1,256 @@ +function ready(fn) { + if (document.readyState != 'loading'){ + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } +} + +// Set Marked.js settings +marked.setOptions({ + gfm: true, + tables: true, + breaks: true, + sanitize: true +}); + +// Get Keycode based on key name +function keyCodeFor(keyName) { + if (keyName == "backspace") return 8; + else if (keyName == "tab") return 9; + else if (keyName == "ctrlEnter") return 10; + else if (keyName == "enter") return 13; + else if (keyName == "shift") return 16; + else if (keyName == "ctrl") return 17; + else if (keyName == "alt") return 18; + else if (keyName == "pausebreak") return 19; + else if (keyName == "capslock") return 20; + else if (keyName == "escape") return 27; + else if (keyName == "space") return 32; + else if (keyName == "pageup") return 33; + else if (keyName == "pagedown") return 34; + else if (keyName == "end") return 35; + else if (keyName == "home") return 36; + else if (keyName == "left") return 37; + else if (keyName == "up") return 38; + else if (keyName == "right") return 39; + else if (keyName == "down") return 40; + else if (keyName == "insert") return 45; + else if (keyName == "del") return 46; + else if (keyName == "zero") return 48; + else if (keyName == "one") return 49; + else if (keyName == "two") return 50; + else if (keyName == "three") return 51; + else if (keyName == "four") return 52; + else if (keyName == "five") return 53; + else if (keyName == "six") return 54; + else if (keyName == "seven") return 55; + else if (keyName == "eight") return 56; + else if (keyName == "nine") return 57; + else if (keyName == "a") return 65; + else if (keyName == "b") return 66; + else if (keyName == "c") return 67; + else if (keyName == "d") return 68; + else if (keyName == "e") return 69; + else if (keyName == "f") return 70; + else if (keyName == "g") return 71; + else if (keyName == "h") return 72; + else if (keyName == "i") return 73; + else if (keyName == "j") return 74; + else if (keyName == "k") return 75; + else if (keyName == "l") return 76; + else if (keyName == "m") return 77; + else if (keyName == "n") return 78; + else if (keyName == "o") return 79; + else if (keyName == "p") return 80; + else if (keyName == "q") return 81; + else if (keyName == "r") return 82; + else if (keyName == "s") return 83; + else if (keyName == "t") return 84; + else if (keyName == "u") return 85; + else if (keyName == "v") return 86; + else if (keyName == "w") return 87; + else if (keyName == "x") return 88; + else if (keyName == "y") return 89; + else if (keyName == "z") return 90; + else if (keyName == "leftwinkey") return 91; + else if (keyName == "rightwinkey") return 92; + else if (keyName == "selectkey") return 93; + else if (keyName == "numpad_0") return 96; + else if (keyName == "numpad_1") return 97; + else if (keyName == "numpad_2") return 98; + else if (keyName == "numpad_3") return 99; + else if (keyName == "numpad_4") return 100; + else if (keyName == "numpad_5") return 101; + else if (keyName == "numpad_6") return 102; + else if (keyName == "numpad_7") return 103; + else if (keyName == "numpad_8") return 104; + else if (keyName == "numpad_9") return 105; + else if (keyName == "numpad_asterisk") return 106; + else if (keyName == "numpad_plus") return 107; + else if (keyName == "numpad_dash") return 109; + else if (keyName == "numpad_period") return 110; + else if (keyName == "numpad_slash") return 111; + else if (keyName == "f1") return 112; + else if (keyName == "f2") return 113; + else if (keyName == "f3") return 114; + else if (keyName == "f4") return 115; + else if (keyName == "f5") return 116; + else if (keyName == "f6") return 117; + else if (keyName == "f7") return 118; + else if (keyName == "f8") return 119; + else if (keyName == "f9") return 120; + else if (keyName == "f10") return 121; + else if (keyName == "f11") return 122; + else if (keyName == "f12") return 123; + else if (keyName == "numlock") return 144; + else if (keyName == "scrolllock") return 145; + else if (keyName == "semicolon") return 186; + else if (keyName == "equal") return 187; + else if (keyName == "comma") return 188; + else if (keyName == "dash") return 189; + else if (keyName == "period") return 190; + else if (keyName == "slash") return 191; + else if (keyName == "grave") return 192; + else if (keyName == "openbracket") return 219; + else if (keyName == "backslash") return 220; + else if (keyName == "closebraket") return 221; + else if (keyName == "quote") return 222; + else return false; +} + +function getInputSelection(el) { +// Retrieved from http://stackoverflow.com/a/4207763 + var start = 0, end = 0, normalizedValue, range, + textInputRange, len, endRange; + el.focus(); + if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") { + start = el.selectionStart; + end = el.selectionEnd; + } else { + range = document.selection.createRange(); + + if (range && range.parentElement() == el) { + len = el.value.length; + normalizedValue = el.value.replace(/\r\n/g, "\n"); + + // Create a working TextRange that lives only in the input + textInputRange = el.createTextRange(); + textInputRange.moveToBookmark(range.getBookmark()); + + // Check if the start and end of the selection are at the very end + // of the input, since moveStart/moveEnd doesn't return what we want + // in those cases + endRange = el.createTextRange(); + endRange.collapse(false); + + if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { + start = end = len; + } else { + start = -textInputRange.moveStart("character", -len); + start += normalizedValue.slice(0, start).split("\n").length - 1; + + if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { + end = len; + } else { + end = -textInputRange.moveEnd("character", -len); + end += normalizedValue.slice(0, end).split("\n").length - 1; + } + } + } + } + + return { + start: start, + end: end + }; +} + +function setSelectionRange(input, selectionStart, selectionEnd) { +// Retrieved from http://stackoverflow.com/a/17858641/3508346 + if (input.setSelectionRange) { + input.focus(); + input.setSelectionRange(selectionStart, selectionEnd); + } + else if (input.createTextRange) { + var range = input.createTextRange(); + range.collapse(true); + range.moveEnd('character', selectionEnd); + range.moveStart('character', selectionStart); + range.select(); + } +} + +function SaveScroll() { + var doc = document.documentElement; + var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0); + var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0); + + savedScroll.x = left; + savedScroll.y = top; +} + +function htmlEntities(string) { + return String(string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\\/g, '\').replace(/\n/g, '
'); +} + +function htmlEntitiesParse(string) { + return String(string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/\/g, '\\').replace(/
/g, '\n'); +} + +function htmlEntitiesParseForMarkdown(string) { + return String(string).replace(/"/g, '"').replace(/'/g, "'").replace(/\/g, '\\').replace(/
/g, '\n'); +} + +function stripHtmlEntities(string) { + // This is for the export name. + return String(string).replace(/&/g, '').replace(/</g, '').replace(/>/g, '').replace(/"/g, '').replace(/'/g, "").replace(/\/g, '').replace(/
/g, ''); +} + +function htmlEntitiesParseForSearchEntry(string) { + return String(string).replace(/"/g, '%%%%').replace(/'/g, "````"); +} + +function htmlEntitiesParseForSearch(string) { + return String(string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '%%%%').replace(/'/g, "````"); +} + +function regexParseForSearch(string) { + return String(string).replace(/([\[\\\^\$\.\|\?\*\+\(\)\{\}\]])/g, "\\$1"); +} + +function dynamicSort(propertiesArray) { + /* Retrieved from http://stackoverflow.com/a/30446887/3508346 + Usage: theArray.sort(dynamicSort(['propertyAscending', '-propertyDescending']));*/ + return function (a, b) { + return propertiesArray + .map(function (o) { + var dir = 1; + if (o[0] === '-') { + dir = -1; + o=o.substring(1); + } + 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) { + return p ? p : n; + }, 0); + }; +} + +function download(filename, text) { + /* Retrieved from http://stackoverflow.com/a/18197341/3508346 + Usage: download('test.txt', 'Hello world!');*/ + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +} \ No newline at end of file diff --git a/src/js/publicView.js b/src/js/publicView.js new file mode 100644 index 0000000..2fa68d3 --- /dev/null +++ b/src/js/publicView.js @@ -0,0 +1,194 @@ +function IsValidPublicDicitonary() { + return typeof publicDictionary !== 'string'; +} + +function ShowPublicDictionary(ignoreFilters) { + ignoreFilters = (typeof ignoreFilters !== 'undefined') ? ignoreFilters : false; + + if (IsValidPublicDicitonary()) { + var filters = (ignoreFilters) ? [] : GetSelectedFilters(); + + var searchResults = []; + 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) { + search = search.toLowerCase(); + //searchDictionaryJSON = searchDictionaryJSON.toLowerCase(); + } + if (searchIgnoreDiacritics) { + search = removeDiacritics(search); + searchDictionaryJSON = removeDiacritics(searchDictionaryJSON); + } + if (searchByWord) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'name' : 'translate(name, "", "")') +', "'+ search +'")'); + } + if (searchBySimple) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'simpleDefinition' : 'translate(simpleDefinition, "", "")') +', "'+ search +'")'); + } + if (searchByLong) { + xpath.push('contains('+ ((searchIgnoreCase) ? 'longDefinition' : 'translate(longDefinition, "", "")') +', "'+ search +'")'); + } + var searchDictionary = JSON.parse(searchDictionaryJSON); + searchResults = JSON.search(searchDictionary, '//words['+ xpath.join(' or ') +']/wordId'); + } + + var dictionaryNameArea = document.getElementById("dictionaryName"); + dictionaryNameArea.innerHTML = publicDictionary.name + " Dictionary"; + + var dictionaryByArea = document.getElementById("dictionaryBy"); + dictionaryByArea.innerHTML = "created by " + publicDictionary.createdBy; + + var dictionaryIncompleteArea = document.getElementById("incompleteNotice"); + if (!publicDictionary.settings.isComplete) { + dictionaryIncompleteArea.innerHTML = "Note: This dictionary is not yet complete and is likely to change."; + } + + var dictionaryDescriptionArea = document.getElementById("dictionaryDescription"); + dictionaryDescriptionArea.innerHTML = marked(htmlEntitiesParseForMarkdown(publicDictionary.description)); + + var dictionaryArea = document.getElementById("theDictionary"); + var dictionaryText = ""; + var numberOfWordsDisplayed = 0; + + if (publicDictionary.words.length > 0) { + for (var i = 0; i < publicDictionary.words.length; i++) { + if (filters.length == 0 || (filters.length > 0 && filters.indexOf(publicDictionary.words[i].partOfSpeech) > -1)) { + if (search == "" || (search != "" && (searchByWord || searchBySimple || searchByLong) && searchResults.indexOf(publicDictionary.words[i].wordId) >= 0)) { + if (!publicDictionary.words[i].hasOwnProperty("pronunciation")) { + publicDictionary.words[i].pronunciation = ""; //Account for new property + } + if (!publicDictionary.words[i].hasOwnProperty("wordId")) { + publicDictionary.words[i].wordId = i + 1; //Account for new property + } + dictionaryText += PublicDictionaryEntry(i, ignoreFilters); + numberOfWordsDisplayed++; + } + } + } + } else { + dictionaryText = "There are no entries in the dictionary." + } + dictionaryArea.innerHTML = dictionaryText; + if (!ignoreFilters) { + ShowFilterWordCount(numberOfWordsDisplayed); + } + } else { + document.getElementById("dictionaryContent").innerHTML = publicDictionary; + } +} + +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" : "")); + + var wordName = wordPronunciation = wordPartOfSpeech = wordSimpleDefinition = wordLongDefinition = ""; + + if (searchTerm != "" && searchByWord) { + wordName += htmlEntities(htmlEntitiesParse(publicDictionary.words[itemIndex].name).replace(searchRegEx, "$1")).replace(/<(\/?)searchterm>/g, '<$1searchterm>'); + } else { + wordName += publicDictionary.words[itemIndex].name.toString(); // Use toString() to prevent using a reference instead of the value. + } + + if (publicDictionary.words[itemIndex].pronunciation != "") { + wordPronunciation += marked(htmlEntitiesParseForMarkdown(publicDictionary.words[itemIndex].pronunciation)).replace(/<\/?p>/g,""); + } + + if (publicDictionary.words[itemIndex].partOfSpeech != " " && publicDictionary.words[itemIndex].partOfSpeech != "") { + wordPartOfSpeech += publicDictionary.words[itemIndex].partOfSpeech.toString(); + } + + if (publicDictionary.words[itemIndex].simpleDefinition != "") { + if (searchTerm != "" && searchBySimple) { + wordSimpleDefinition += htmlEntities(htmlEntitiesParse(publicDictionary.words[itemIndex].simpleDefinition).replace(searchRegEx, "$1")).replace(/<(\/?)searchterm>/g, '<$1searchterm>'); + } else { + wordSimpleDefinition += publicDictionary.words[itemIndex].simpleDefinition.toString(); + } + } + + if (publicDictionary.words[itemIndex].longDefinition != "") { + if (searchTerm != "" && searchByLong) { + wordLongDefinition += marked(htmlEntitiesParseForMarkdown(htmlEntities(htmlEntitiesParse(publicDictionary.words[itemIndex].longDefinition).replace(searchRegEx, "$1")))).replace(/<(\/?)searchterm>\;/g, '<$1searchterm>'); + } else { + wordLongDefinition += marked(htmlEntitiesParseForMarkdown(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 = "➦"; + + entryText += "" + wordObject.name + ""; + + if (wordObject.pronunciation != "") { + entryText += "" + wordObject.pronunciation + ""; + } + + if (wordObject.partOfSpeech != "") { + entryText += "" + wordObject.partOfSpeech + ""; + } + + entryText += "
"; + + if (wordObject.simpleDefinition != "") { + entryText += "" + wordObject.simpleDefinition + ""; + } + + if (wordObject.longDefinition != "") { + entryText += "" + wordObject.longDefinition + ""; + } + + if (managementIndex !== false) { + entryText += ManagementArea(managementIndex); + } + + entryText += "
"; + + return entryText; +} + +function SetPublicPartsOfSpeech () { + var wordFilterOptions = document.getElementById("filterOptions"); + + var newPartsOfSpeech = htmlEntitiesParse(publicDictionary.settings.partsOfSpeech).trim().split(","); + for (var j = 0; j < newPartsOfSpeech.length; j++) { + var thePartOfSpeech = newPartsOfSpeech[j].trim(); + + var wordFilterLabel = document.createElement('label'); + wordFilterLabel.appendChild(document.createTextNode(thePartOfSpeech + " ")); + wordFilterLabel['part-of-speech'] = thePartOfSpeech; + wordFilterLabel.className = 'filterOption'; + var wordFilterCheckbox = document.createElement('input'); + wordFilterCheckbox.type = 'checkbox'; + wordFilterCheckbox.onchange = function(){ShowPublicDictionary()}; + wordFilterLabel.appendChild(wordFilterCheckbox); + wordFilterOptions.appendChild(wordFilterLabel); + } +} \ No newline at end of file diff --git a/src/js/ui.js b/src/js/ui.js new file mode 100644 index 0000000..a16ace0 --- /dev/null +++ b/src/js/ui.js @@ -0,0 +1,714 @@ +function Initialize() { + LoadDictionary(); + 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("/EXPORT.form", "exportForm", false); + GetTextFile("/IMPORT.form", "importForm", false); + + SetKeyboardShortcuts(); + SetWindowListeners(); +} + +function SetKeyboardShortcuts() { + document.addEventListener("keydown", function(e) { + var keyCode = (e.which ? e.which : e.keyCode); + + if (keyCode == keyCodeFor("escape")) { + if (document.getElementById("infoScreen").style.display == "block") { + HideInfo(); + } + else if (document.getElementById("fullScreenTextboxScreen").style.display == "block") { + HideFullScreenTextbox(); + } + else if (document.getElementById("settingsScreen").style.display == "block") { + HideSettings(); + } + else if (document.getElementById("accountSettingsScreen") && document.getElementById("accountSettingsScreen").style.display == "block") { + HideAccountSettings(); + } + } + else if (e.ctrlKey) { + // Only allow shortcuts if not currently using fullscreen textbox + if (document.getElementById("fullScreenTextboxScreen").style.display == "none") { + if (keyCode == keyCodeFor("m")) { + if (document.activeElement.id.indexOf("longDefinition") >= 0) { + e.preventDefault(); + ShowFullScreenTextbox(document.activeElement.id, 'Explanation/Long Definition'); + } + else if (document.activeElement.id == "dictionaryDescriptionEdit") { + e.preventDefault(); + ShowFullScreenTextbox('dictionaryDescriptionEdit', 'Dictionary Details'); + } + else if (document.activeElement.id == "fullScreenTextbox") { + e.preventDefault(); + HideFullScreenTextbox(); + } + } + else if (keyCode == keyCodeFor("u")) { + e.preventDefault(); + ToggleWordFormLock(); + } + else if (keyCode == keyCodeFor("d")) { + e.preventDefault(); + ToggleDescription(); + } + else if (keyCode == keyCodeFor("s")) { + e.preventDefault(); + //ToggleSearchFilter(); + var searchFilterToggle = document.getElementById("searchFilterToggle"); + var searchFilterArea = document.getElementById("searchFilterArea"); + + if (searchFilterArea.style.display == "none") { + searchFilterArea.style.display = "block"; + searchFilterToggle.innerHTML = "Hide Search/Filter Options"; + } + document.getElementById("searchBox").focus(); + } + else if (keyCode == keyCodeFor("h")) { + e.preventDefault(); + ShowInfo('aboutText'); + } + } + else { //If the fullscreen editor *is* open, just prevent the others for consistent behavior. + if (keyCode == keyCodeFor("m")) { + e.preventDefault(); + HideFullScreenTextbox(); + } + else if (keyCode == keyCodeFor("u")) { + e.preventDefault(); + } + else if (keyCode == keyCodeFor("d")) { + e.preventDefault(); + } + else if (keyCode == keyCodeFor("s")) { + e.preventDefault(); + } + else if (keyCode == keyCodeFor("h")) { + e.preventDefault(); + } + } + } + else if (e.altKey) { + // Only toggle screens if not currently using fullscreen textbox + if (document.getElementById("fullScreenTextboxScreen").style.display == "none") { + if (keyCode == keyCodeFor("s")) { + e.preventDefault(); + ToggleSettingsScreen(true); + } + else if (keyCode == keyCodeFor("a")) { + e.preventDefault(); + ToggleAccountSettings(); + } + } + } + }, false); +} + +function SetWindowListeners() { + window.addEventListener("scroll", function() { + var doc = document.documentElement; + var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0); + var dictionaryColumn = document.getElementById("dictionaryColumn"); + var wordPullout = document.getElementById("mobileWordFormPullout"); + + if (top > dictionaryColumn.offsetTop) { + wordPullout.style.display = "block"; + } else { + wordPullout.style.display = "none"; + if (wordPullout.innerHTML != "+") { + LockWordForm(); + wordPullout.innerHTML = "+"; + } + } + }); +} + +function SubmitWordOnCtrlEnter(keypress) { + var keyCode = (event.which ? event.which : event.keyCode); + + if (keyCode === keyCodeFor("ctrlEnter") || (keyCode == keyCodeFor("enter") && event.ctrlKey)) { //Windows and Linux Chrome accept ctrl+enter as keyCode 10. + event.preventDefault(); + + if (/\d/.test(document.activeElement.id)) { // If there IS a number in the ID, then it is a word being edited. + EditWord(document.activeElement.id.match(/\d+/)[0]); // .match(/\d+/) returns an array of digits in a string. + } else { // Otherwise, it's a new word. + AddWord(); + } + } +} + +function LoadUserDictionaries() { + var getDictionariesRequest = new XMLHttpRequest(); + var userDictionariesSelect = document.getElementById("userDictionaries"); + if (userDictionariesSelect != null) { + getDictionariesRequest.open('GET', "/php/ajax_dictionarymanagement.php?action=getall"); + getDictionariesRequest.onreadystatechange = function() { + if (getDictionariesRequest.readyState == 4 && getDictionariesRequest.status == 200) { + ParseUserDictionariesIntoSelect(userDictionariesSelect, getDictionariesRequest.responseText); + } + } + getDictionariesRequest.send(); + } +} + +function ParseUserDictionariesIntoSelect(selectToPopulate, dicitonaryList) { + if (selectToPopulate.options.length > 0) { + for (var i = selectToPopulate.options.length - 1; i >= 0; i--) { + selectToPopulate.removeChild(selectToPopulate.options[i]); + } + } + + var dictionaries = dicitonaryList.split("_DICTIONARYSEPARATOR_"); + for (var j = 0; j < dictionaries.length - 1; j++) { + var dictionaryOption = document.createElement('option'); + var dictionaryValues = dictionaries[j].split("_IDNAMESEPARATOR_"); + dictionaryOption.appendChild(document.createTextNode(htmlEntitiesParse(dictionaryValues[1]))); + dictionaryOption.value = dictionaryValues[0]; + selectToPopulate.appendChild(dictionaryOption); + } + selectToPopulate.value = (currentDictionary.externalID > 0) ? currentDictionary.externalID : ""; +} + +function GetTextFile(filename, variableName, parseMarkdown) { + parseMarkdown = (typeof parseMarkdown !== 'undefined') ? parseMarkdown : false; + var readmeFileRequest = new XMLHttpRequest(); + readmeFileRequest.open('GET', filename); + readmeFileRequest.onreadystatechange = function() { + if (readmeFileRequest.readyState == 4 && readmeFileRequest.status == 200) { + window[variableName] = (parseMarkdown) ? marked(readmeFileRequest.responseText, {sanitize: false}) : readmeFileRequest.responseText; + } + } + readmeFileRequest.send(); +} + +function ValidateLogin() { + var errorMessage = document.getElementById("loginError"); + var emailValue = document.getElementById("loginEmailField").value; + var passwordValue = document.getElementById("loginPasswordField").value; + + if (emailValue == "") { + errorMessage.innerHTML = "Email cannot be blank!"; + return false; + } else if (!(/[^\s@]+@[^\s@]+\.[^\s@]+/.test(emailValue))) { + errorMessage.innerHTML = "Your email address looks fake. Email addresses look like this: name@email.com." + return false; + } else if (passwordValue == "") { + errorMessage.innerHTML = "Password cannot be blank!"; + return false; + } else { + document.getElementById("loginForm").submit(); + } +} + +function ValidateCreateAccount() { + var errorMessage = document.getElementById("createAccountError"); + var emailValue = document.getElementById("createAccountEmailField").value; + var passwordValue = document.getElementById("createAccountPasswordField").value; + var passwordConfirmValue = document.getElementById("createAccountPasswordConfirmField").value; + var publicNameValue = document.getElementById("createAccountPublicNameField").value; + + if (emailValue == "") { + errorMessage.innerHTML = "Email cannot be blank!"; + return false; + } else if (!(/[^\s@]+@[^\s@]+\.[^\s@]+/.test(emailValue))) { + errorMessage.innerHTML = "Your email address looks fake. Email addresses look like this: name@email.com." + return false; + } else if (passwordValue == "") { + errorMessage.innerHTML = "Password cannot be blank!"; + return false; + } else if (passwordValue != passwordConfirmValue) { + errorMessage.innerHTML = "Passwords do not match!"; + return false; + } else if (publicNameValue == "") { + errorMessage.innerHTML = "Public Name cannot be blank!"; + return false; + } else { + var emailCheck = new XMLHttpRequest(); + emailCheck.open('GET', "/php/ajax_createaccountemailcheck.php?email=" + emailValue); + emailCheck.onreadystatechange = function() { + if (emailCheck.readyState == 4 && emailCheck.status == 200) { + if (emailCheck.responseText != "ok") { + errorMessage.innerHTML = "The email address entered is already being used. Try logging in or using a different email address instead."; + return false; + } else { + document.getElementById("createAccountForm").submit(); + } + } + } + emailCheck.send(); + } +} + +function ValidateAccountSettings() { + var errorMessage = document.getElementById("accountSettingsError"); + var emailValue = document.getElementById("accountSettingsEmailField").value; + var publicNameValue = document.getElementById("accountSettingsPublicNameField").value; + + if (emailValue == "") { + errorMessage.innerHTML = "Email cannot be blank!"; + return false; + } else if (!(/[^\s@]+@[^\s@]+\.[^\s@]+/.test(emailValue))) { + errorMessage.innerHTML = "Your email address looks fake. Email addresses look like this: name@email.com." + return false; + } else if (publicNameValue == "") { + errorMessage.innerHTML = "Public Name cannot be blank!"; + return false; + } else { + document.getElementById("createAccountForm").submit(); + } +} + +function ValidateForgotPassword() { + var errorMessage = document.getElementById("forgotError"); + var emailValue = document.getElementById("forgotEmailField").value; + + if (emailValue == "") { + errorMessage.innerHTML = "Email cannot be blank!"; + return false; + } else if (!(/[^\s@]+@[^\s@]+\.[^\s@]+/.test(emailValue))) { + errorMessage.innerHTML = "Your email address looks fake. Email addresses look like this: name@email.com." + return false; + } else { + var emailCheck = new XMLHttpRequest(); + emailCheck.open('GET', "/php/ajax_passwordresetemailcheck.php?email=" + emailValue); + emailCheck.onreadystatechange = function() { + if (emailCheck.readyState == 4 && emailCheck.status == 200) { + if (emailCheck.responseText != "email exists") { + errorMessage.innerHTML = "The email address entered is not in use and therefore can't have its password reset. Try creating an account instead!"; + return false; + } else { + document.getElementById("forgotForm").submit(); + } + } + } + emailCheck.send(); + } +} + +function ValidateResetPassword() { + var errorMessage = document.getElementById("resetPasswordError"); + var passwordValue = document.getElementById("newPasswordField").value; + var passwordConfirmValue = document.getElementById("newPasswordConfirmField").value; + + if (passwordValue == "") { + errorMessage.innerHTML = "Password cannot be blank!"; + return false; + } else if (passwordValue != passwordConfirmValue) { + errorMessage.innerHTML = "Passwords do not match!"; + return false; + } else { + document.getElementById("resetPasswordForm").submit(); + } +} + +function WarnEmailChange() { + var emailChangeWarning = document.getElementById("accountSettingsEmailChangeWarning"); + var emailValue = document.getElementById("accountSettingsEmailField").value; + var originalEmailValue = document.getElementById("accountSettingsPreviousEmailField").value; + + if (emailValue != originalEmailValue) { + emailChangeWarning.style.display = "block"; + } else { + emailChangeWarning.style.display = "none"; + } +} + +function LoggedInResetPassword() { + var resetPasswordRequest = new XMLHttpRequest(); + resetPasswordRequest.open('GET', "/php/ajax_setnewpassword.php"); + resetPasswordRequest.onreadystatechange = function() { + if (resetPasswordRequest.readyState == 4 && resetPasswordRequest.status == 200) { + if (resetPasswordRequest.responseText != "done") { + console.log(resetPasswordRequest.responseText); + alert("Error resetting password.\n\nTry again later."); + return false; + } else { + window.location = "./"; + } + } + } + resetPasswordRequest.send(); +} + +function ExplainPublicName() { + alert("This is the name we greet you with. It's also the name displayed if you ever decide to share any of your dictionaries.\n\nNote: this is not a username, and as such is not guaranteed to be unique. Use something people will recognize you as to differentiate from other people who might use the same name!"); +} + +function ExplainAllowEmails() { + alert("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, but you may need to mark emails from lexicon.ga as not spam to receive them.\nNOTE: Password reset emails will be sent regardless of your choice."); +} + +function wordFormIsLocked() { + return document.getElementById("formLockButton").innerHTML == "\uD83D\uDD12"; +} + +function MobileToggleWordForm() { + var pullout = document.getElementById("mobileWordFormPullout"); + ToggleWordFormLock("7%"); + if (pullout.innerHTML == "+") { + pullout.innerHTML = "✕"; + } else { + pullout.innerHTML = "+"; + } +} + +function ToggleWordFormLock(topValue) { + if (wordFormIsLocked()) { //If it is already locked, change it to Unlocked and get everything working as it needs to. + UnlockWordForm(topValue); + } else { + LockWordForm(); + } +} + +function UnlockWordForm(topValue) { + var lockButton = document.getElementById("formLockButton"); + var leftColumn = document.getElementById("leftColumn"); + var wordForm = document.getElementById("wordEntryForm"); + var wordFormWidth = wordForm.offsetWidth; + var leftColumnWidth = leftColumn.offsetWidth; + var leftColumnHeight = leftColumn.offsetHeight; + + lockButton.innerHTML = "🔓"; // Change to the "Unlocked lock" icon. + + wordForm.style.position = "fixed"; + wordForm.style.top = (typeof topValue !== 'undefined') ? topValue : document.getElementById("dictionaryColumn").offsetTop.toString() + "px"; + wordForm.style.width = wordFormWidth.toString() + "px"; + + leftColumn.style.width = leftColumnWidth.toString() + "px"; + leftColumn.style.height = leftColumnHeight.toString() + "px"; +} + +function LockWordForm() { + var lockButton = document.getElementById("formLockButton"); + var leftColumn = document.getElementById("leftColumn"); + var wordForm = document.getElementById("wordEntryForm"); + + lockButton.innerHTML = "🔒"; // Change to the "locked" icon. + leftColumn.removeAttribute('style'); + wordForm.removeAttribute('style'); +} + +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" + wordIndexString).style.display = "none"; + EnableForm(wordIndexString); +} + +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(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() { + if (document.getElementById("wordEntryForm")) { + document.getElementById("word").value = ""; + document.getElementById("pronunciation").value = ""; + document.getElementById("partOfSpeech").value = ""; + document.getElementById("simpleDefinition").value = ""; + document.getElementById("longDefinition").value = ""; + document.getElementById("editIndex").value = ""; + + document.getElementById("newWordButtonArea").style.display = "block"; + document.getElementById("editWordButtonArea").style.display = "none"; + document.getElementById("errorMessage").innerHTML = ""; + document.getElementById("updateConflict").style.display = "none"; + EnableForm(""); + } +} + +function ToggleDescription() { + var descriptionToggle = document.getElementById("descriptionToggle"); + var descriptionArea = document.getElementById("dictionaryDescription"); + + if (descriptionArea.style.display == "none") { + descriptionArea.style.display = "block"; + descriptionToggle.innerHTML = "Hide Description"; + } else { + descriptionArea.style.display = "none"; + descriptionToggle.innerHTML = "Show Description"; + } +} + +function ToggleSearchFilter() { + var searchFilterToggle = document.getElementById("searchFilterToggle"); + var searchFilterArea = document.getElementById("searchFilterArea"); + + if (searchFilterArea.style.display == "none") { + searchFilterArea.style.display = "block"; + searchFilterToggle.innerHTML = "Hide Search/Filter Options"; + } else { + searchFilterArea.style.display = "none"; + searchFilterToggle.innerHTML = "Search/Filter Options"; + } +} + +function ShowInfo(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 export it before logging in so you don't lose anything!"; + } + } +} + +function ShowInfoWithText(text) { + document.getElementById("infoText").innerHTML = text; + document.getElementById("infoScreen").style.display = "block"; + document.getElementById("infoPage").scrollTop = 0; + HideAccountSettings(); +} + +function HideInfo() { + document.getElementById("infoScreen").style.display = "none"; +} + +function ToggleAccountSettings() { + if (document.getElementById("accountSettingsScreen")) { + var accountScreen = document.getElementById("accountSettingsScreen"); + + if (accountScreen.style.display == "block") { + HideAccountSettings(); + } else { + ShowAccountSettings(); + } + } +} + +function ShowAccountSettings(variableName) { + if (document.getElementById("accountSettingsScreen")) + document.getElementById("accountSettingsScreen").style.display = "block"; + + HideInfo(); +} + +function HideAccountSettings() { + if (document.getElementById("accountSettingsScreen")) + document.getElementById("accountSettingsScreen").style.display = "none"; +} + +function ToggleSettingsScreen(doSave) { + var settingsScreen = document.getElementById("settingsScreen"); + + if (settingsScreen.style.display == "block") { + if (doSave) { + SaveSettings(); + } + HideSettings(); + } else { + ShowSettings(); + } +} + +function ShowSettings() { + document.getElementById("settingsScreen").style.display = "block"; + document.getElementById("dictionaryNameEdit").value = htmlEntitiesParse(currentDictionary.name); + document.getElementById("dictionaryDescriptionEdit").value = htmlEntitiesParse(currentDictionary.description); + document.getElementById("dictionaryPartsOfSpeechEdit").value = htmlEntitiesParse(currentDictionary.settings.partsOfSpeech); + document.getElementById("dictionaryAllowDuplicates").checked = currentDictionary.settings.allowDuplicates; + document.getElementById("dictionaryCaseSensitive").checked = currentDictionary.settings.caseSensitive; + document.getElementById("dictionarySortByEquivalent").checked = currentDictionary.settings.sortByEquivalent; + document.getElementById("dictionaryIsComplete").checked = currentDictionary.settings.isComplete; + if (document.getElementById("dictionaryIsPublic")) { + document.getElementById("dictionaryIsPublic").checked = currentDictionary.settings.isPublic; + TogglePublicLink(); + } + document.getElementById("numberOfWordsInDictionary").innerHTML = currentDictionary.words.length.toString(); +} + +function HideSettings() { + document.getElementById("settingsScreen").style.display = "none"; + if (currentDictionary.settings.isComplete) { + LockWordForm(); + document.getElementById("wordEntryForm").style.display = "none"; + } else { + document.getElementById("wordEntryForm").style.display = "block"; + } + +} + +function HideSettingsWhenComplete() { + if (document.getElementById("settingsScreen")) { + if (currentDictionary.settings.isComplete) { + document.getElementById("hideIfComplete").style.display = "none"; + } else { + document.getElementById("hideIfComplete").style.display = "block"; + } + } +} + +function ShowFullScreenTextbox(textboxToExpandId, labelText) { + var sourceTextboxElement = document.getElementById(textboxToExpandId); + var targetTextboxElement = document.getElementById("fullScreenTextbox"); + document.getElementById("fullScreenTextboxLabel").innerHTML = labelText; + var selection = getInputSelection(sourceTextboxElement); + + document.getElementById("expandedTextboxId").innerHTML = textboxToExpandId; + targetTextboxElement.value = sourceTextboxElement.value; + document.getElementById("fullScreenTextboxScreen").style.display = "block"; + + setSelectionRange(targetTextboxElement, selection.start, selection.end); +} + +function HideFullScreenTextbox() { + var expandedTextboxId = document.getElementById("expandedTextboxId").innerHTML; + var sourceTextboxElement = document.getElementById("fullScreenTextbox"); + var targetTextboxElement = document.getElementById(expandedTextboxId); + var selection = getInputSelection(sourceTextboxElement); + + targetTextboxElement.value = sourceTextboxElement.value; + document.getElementById("fullScreenTextboxScreen").style.display = "none"; + + setSelectionRange(targetTextboxElement, selection.start, selection.end); +} + +function ShowDictionaryDeleteMenu(dictionaryList) { + document.getElementById('loadAfterDeleteScreen').style.display = 'block'; + //Parse response into the list that forces you to load one and reload select in settings. + ParseUserDictionariesIntoSelect(document.getElementById("loadAfterDelete"), dictionaryList); + ParseUserDictionariesIntoSelect(document.getElementById("userDictionaries"), dictionaryList); +} + +function ToggleCaseSensitiveOption() { + if (document.getElementById("dictionaryAllowDuplicates").checked) { + document.getElementById("dictionaryCaseSensitive").disabled = true; + } else { + document.getElementById("dictionaryCaseSensitive").disabled = false; + } +} + +function TogglePublicLink() { + if (document.getElementById("dictionaryIsPublic").checked) { + var publicLink = "http://lexicon.ga/" + currentDictionary.externalID; + document.getElementById("publicLink").innerHTML = "Public Link:
" + publicLink; + } else { + document.getElementById("publicLink").innerHTML = ""; + } +} + +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. + 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(","); + for (var j = 0; j < newPartsOfSpeech.length; j++) { + var thePartOfSpeech = newPartsOfSpeech[j].trim(); + + var partOfSpeechOption = document.createElement('option'); + partOfSpeechOption.appendChild(document.createTextNode(thePartOfSpeech)); + partOfSpeechOption.value = thePartOfSpeech; + partsOfSpeechSelect.appendChild(partOfSpeechOption); + + var wordFilterLabel = document.createElement('label'); + wordFilterLabel.appendChild(document.createTextNode(thePartOfSpeech + " ")); + wordFilterLabel['part-of-speech'] = thePartOfSpeech; + wordFilterLabel.className = 'filterOption'; + var wordFilterCheckbox = document.createElement('input'); + wordFilterCheckbox.type = 'checkbox'; + wordFilterCheckbox.onchange = function(){ShowDictionary()}; + if (wordFiltersSelected.indexOf(thePartOfSpeech) > -1) wordFilterCheckbox.checked = true; + 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() { + var wordFilterOptions = document.getElementById("filterOptions"); + var wordFiltersSelected = []; + + for (var i = 0; i < wordFilterOptions.children.length; i++) { + var filterOption = wordFilterOptions.children[i]; + if (filterOption.children[0].checked) { + wordFiltersSelected.push(filterOption['part-of-speech']); + } + } + + return wordFiltersSelected; +} + +function ToggleAllFilters(doCheck) { + var wordFilterOptions = document.getElementById("filterOptions"); + + for (var i = 0; i < wordFilterOptions.children.length; i++) { + wordFilterOptions.children[i].children[0].checked = doCheck; + } +} + +function ShowFilterWordCount(numberOfWords) { + var filters = GetSelectedFilters(); + var search = htmlEntitiesParseForSearchEntry(document.getElementById("searchBox").value); + var wordCounter = document.getElementById("filterWordCount"); + + if (filters.length > 0 || search != "") { + wordCounter.innerHTML = "Showing " + numberOfWords.toString() + " result" + ((numberOfWords != 1) ? "s" : ""); + } else { + wordCounter.innerHTML = ""; + } +} + +function NewWordNotification(word) { + var wordId = currentDictionary.nextWordId - 1; + NewNotification("New Word Added: " + word + ""); +} + +function NewNotification(message) { + var notificationArea = document.getElementById("notificationArea"); + var notificationMessage = document.getElementById("notificationMessage"); + notificationArea.style.display = "block"; + notificationMessage.innerHTML = message; +} + +function FocusAfterAddingNewWord() { + document.getElementById("word").focus(); +} diff --git a/src/sass/lexiconga.scss b/src/sass/lexiconga.scss new file mode 100644 index 0000000..679d8f4 --- /dev/null +++ b/src/sass/lexiconga.scss @@ -0,0 +1,149 @@ +body { + background: #e6cfaa; +} + +header { + background: #eacc9d; +} + +tr, thead { + border-bottom: 1px solid #af8050; +} +td, th { + border-right: 1px solid #af8050; +} + +a { + text-decoration: underline; + color: #a01000; +} + +#siteLogo { + display: block; + text-indent: -9999px; + width: 242px; + height: 48px; + background: url(../images/logo.svg); + background-size: 242px 48px; + float: left; +} + +#aboutButton { +} + +#loginoutArea { + float: right; +} + +#loginoutArea a { + color: #000000; + text-decoration: none; + font-size: 13px; +} + +@media screen +and (min-device-width : 481px) { + #headerPadder { + padding: 1px; + } + + #loginoutArea { + margin: 16px; + } +} + +/* Smartphones (portrait and landscape) ----------- */ +@media only screen +and (max-device-width : 480px) { + #siteLogo { + display: block; + text-indent: -9999px; + width: 150px; + height: 30px; + background: url(../images/logo.svg); + background-size: 150px 30px; + float: left; + } + + #loginoutArea { + margin: 16px 8px; + } +} + +#wordEntryForm { + 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 { + background: #efdfc0; +} + +#announcementArea { + background: #a0c066; +} + +#notificationArea { + background: #c0c088; +} + +#dictionaryColumn { + background: #bd7251; + 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); +} + +#settingsOptions, #infoPage, #loadAfterDeletePage, #accountSettingsPage, #fullScreenTextboxPage { + background: #f2d5b2; +} + +.management { + border-width: 2px; + border: none; +} + +#dictionaryName { + text-shadow: 2px 2px 2px #915337; +} + +#dictionaryShareLink { + text-shadow: none; +} + +#dictionaryDescription { + width: 90%; + background: #f2d5b2; +} + +#loginLink, #logoutLink, #descriptionToggle, #searchFilterToggle, #settingsButton, .deleteCancelButton, .deleteConfirmButton, #settingsScreenCloseButton, #infoScreenCloseButton, .clickable, button { + background: #dcb078; +} + +entry { + background: #d7ad7d; + 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: #86ac41; +} + +.deleteButton { + background: #ba5536; +} + +footer { + 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); +} \ No newline at end of file diff --git a/src/sass/mobile.scss b/src/sass/mobile.scss new file mode 100644 index 0000000..1aea062 --- /dev/null +++ b/src/sass/mobile.scss @@ -0,0 +1,134 @@ +/* Smartphones (portrait and landscape) ----------- */ +@media screen +and (max-width : 910px) { + body { + font-size: 11pt; + } + + header { + height: 70px; + } + + footer { + position: relative; + clear: both; + max-height: 100%; + } + + #announcementArea, #notificationArea { + width: 80%; + } + + #leftColumn { + width: 100%; + margin: 0; + } + + #wordEntryForm { + padding: 8px 0; + width: 100%; + max-width: 450px; + margin: 10px auto; + } + + #wordEntryForm label { + overflow: hidden; + display: flex; + justify-content: center; + font-size: 10pt; + } + + #wordEntryForm label span { + float: left; + width: 30%; + text-align: right; + margin-right: 8px; + } + + #wordEntryForm input, #wordEntryForm select, #wordEntryForm textarea { + float: right; + width: 60%; + margin-right: 8px; + align-self: center; + } + + .longDefinition { + min-width: 200px; + height: 80px; + } + + #wordEntryForm button { + display: block; + width: 50%; + height: 30px; + margin: 0px auto; + } + + #mobileWordFormPullout { + position: fixed; + top: 7%; + left: 0; + width: 32px; + height: 32px; + font-size: 20px; + font-weight: bold; + text-align: center; + padding: 6px; + background: #86ac41; + -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; + cursor: pointer; + } + + #dictionaryColumn { + width: 100%; + margin: 0; + padding: 0; + } + + #dictionaryContent { + margin: 0 auto; + padding: 15px; + } + + #dictionaryDescription { + margin: 0 auto; + } + + #searchFilterArea { + width: 90%; + min-width: 200px; + padding: 10px 10px 3px; + margin: 0 auto; + } + + .fixedFade { + z-index: 5; + } + + .fixedPage { + z-index: 10; + } + + entry { + margin: 0 auto 5px; + } + + #formLockButton { + display: none; + } + + #showFullScreenTextbox { + display: none; + } + + #settingsSaveButtons { + position: relative; + right: 0; + bottom: 0; + clear: both; + width: 100%; + } +} diff --git a/src/sass/styles.scss b/src/sass/styles.scss new file mode 100644 index 0000000..7cc1bcc --- /dev/null +++ b/src/sass/styles.scss @@ -0,0 +1,453 @@ +* { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +html { + width: 100%; +} + +body { + width: 100%; + padding: 0; + margin: 0; + border: none; + font-family: "Helvetica", Arial, sans-serif; +} + +contents { + display: block; + width: 100%; +} + +header { + height: 50px; + width: 100%; + margin: 0 0 10px; + position: relative; + top: 0px; + left: 0px; + right: 0px; + border: none; + padding: 0; + -webkit-box-shadow: 0px 3px 10px -1px rgba(0,0,0,0.75); + -moz-box-shadow: 0px 3px 10px -1px rgba(0,0,0,0.75); + box-shadow: 0px 3px 10px -1px rgba(0,0,0,0.75); +} + +footer { + width: 100%; + text-align: center; + vertical-align: middle; + position:fixed; + bottom: 0px; + left: 0px; + background: #aaaaaa; + padding: 0; + max-height: 32px; /* Update Dictionary Container's bottom margin to account for footer */ +} + +#footer-content { + padding: 8px; +} + +table { + border-collapse: collapse; + width: 100%; +} + +tr, thead { + border-bottom: 1px solid #afafaf; +} +tr:last-child { + border-bottom: none; +} + +td, th { + border-right: 1px solid #afafaf; + padding: 3px 10px; +} +td:last-child, th:last-child { + border-right: none; +} + +.inline { + display: inline !important; +} + +#leftColumn { + float: left; + width: 25%; + margin: 15px 0 15px 15px; +} + +form { + padding: 15px; +} + +#wordEntryForm { + max-width: 400px; + min-width: 260px; +} + +.wbr:after { + content: "\00200B"; +} + +label { + display: block; + margin-bottom: 10px; +} + +label span { + display: block; + font-weight: bold; +} + +label label { + margin-left: 20px; +} + +label span.checkboxlabel { + display: inline; + margin-left: 10px; +} + +input, textarea { + display: block; + padding: 2px 0 2px 5px; + border: none; + margin: 2px 0; +} + +input[type=checkbox] { + display: inline; + margin: 5px; +} + +.longDefinition { + width: 100%; + min-width: 230px; + height: 150px; +} + +#updateConflict { + width: 260px; +} + +#errorMessage, #updateConflictMessage, #settingsErrorMessage { + display: block; + color: maroon; + font-weight: bold; +} + +#dictionaryWarn { + margin-top: 10px; + font-size: 12px; + font-weight: bold; + font-style: italic; +} + +.exportWarnText { + display: inline; + color: red; + cursor: pointer; + text-decoration: underline; +} + +#formLockButton { + float: right; +} + +#createAccountSubmitButton, #accountSettingsSubmitButton { + margin-top: 10px; +} + +#aboutButton { + display: inline; + margin: 0 10px 0 0; +} + +#announcementArea, #notificationArea { + text-align:center; + padding:10px; + margin: 0 auto 5px; + 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); +} + +#dictionaryColumn { + width: 50%; + margin: 15px 0 36px 15px; /* bottom margin must clear footer */ + padding: 0; + float: left; +} + +#dictionaryContent { + width: 100%; + min-width: 260px; + max-width: 800px; + padding: 15px; +} + +#dictionaryName { + 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: none; + margin: 10px; +} + +.clickable, button { + display: inline; + font-weight: bold; + font-size: 13px; + padding: 5px; + border: none; + background: #dddddd; +} + +.clickable, button { + cursor: pointer; +} + +.inline-button { + font-size: 11px; + padding: 2px 4px; +} + +.toggleButton { + display: inline-block; + margin: 8px; + font-weight: bold; + font-size: 12px; +} + +.searchOption, .filterOption { + font-size:12px; + display: inline-block; + margin: 0 8px 0 0; +} + +#wordFilter { + margin: 10px 0; +} + +#filterWordCount { + margin: 10px 10px; + display: block; + font-weight: bold; + font-style: italic; +} + +entry { + display: block; + width: 90%; + min-width: 200px; + padding: 10px 10px 3px; + margin-bottom: 5px; +} + +.wordLink { + text-decoration: none; + float: right; + font-size: 13px; + padding: 2px; + line-height: 10px; +} + +word { + font-weight: bold; + font-size: 20px; +} + +pronunciation { + font-size: 12px; + margin-left:10px; +} + +partofspeech { + font-style: italic; + font-weight: bold; + font-size: 10px; + margin-left:10px; +} + +simpledefinition { + display: block; + font-style: italic; +} + +longdefinition { + display: block; + margin-left: 20px; +} + +longDefinition h1, longDefinition h2, longDefinition h3, longDefinition h4, longDefinition h5, longDefinition h6 { + margin: 5px 0 8px; + font-weight: bold; +} + +longDefinition h1 { + font-size: 22px; +} + +longDefinition h2 { + font-size: 20px; +} + +longDefinition h3 { + font-size: 20px; + font-weight: normal; +} + +longDefinition h4 { + font-size: 18px; +} + +longDefinition h5 { + font-size: 18px; + font-weight: normal; +} + +longDefinition h6 { + font-size: 17px; +} + +longDefinition p { + margin: 3px 0 8px; +} + +searchTerm { + display: inline; + color: #ff0000; + background: #ffff00; + padding: 1px; + text-decoration: underline; + font-style: italic; + font-weight: bold; +} + +.management { + display: block; + right: 5px; + width: 100px; + padding: 3px; + border: inset 3px; + margin: 10px; +} + +.editButton, .deleteButton, .deleteConfirmButton, .deleteCancelButton { + display: inline; + font-size: 10px; + margin: 5px; +} + +.deleteConfirm { + display: block; + font-size: 10px; + margin: 10px; +} + +.fixedFade { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #000000; + opacity: 0.6; +} + +.fixedPage { + position: fixed; + top: 5%; + left: 6%; + right: 6%; + bottom: 10%; + min-width: 260px; + min-height: 260px; + padding: 5px 5% 5%; + overflow-y: auto; + overflow-x: hidden; + background: #ffffff; + opacity: 1; + 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); +} + +.rightButton { + float: right; + font-size: 12px; +} + +#fullScreenTextboxPage { + padding: 5px 3% 4%; + overflow-y: hidden; +} + +#fullScreenTextbox { + position: relative; + width: 100%; + height: 100%; +} + +#settingsForm { + width: 100%; + padding: 0; + margin: 0; +} + +#publicLink { + font-size:12px; + font-style: italic; +} + +#dictionaryDescriptionEdit, #dictionaryPartsOfSpeechEdit { + width: 100%; + max-width: 360px; + min-width: 200px; +} + +#dictionaryDescriptionEdit { + height: 200px; +} + +#settingsErrorMessage { + float: right; + clear: both; +} +#settingsSaveButtons { + position: absolute; + right: 10%; + bottom: 8%; + font-size: 14px; + display: block; + width: 50%; +} + +.settingsCol { + display: block; + float: left; + width: 30%; + min-width: 260px; + max-width: 400px; + margin: 0 30px 0 0; +}