Compare commits
11 Commits
ab75db9a39
...
54aa0e2667
Author | SHA1 | Date |
---|---|---|
Robbie Antenesse | 54aa0e2667 | |
Robbie Antenesse | a62d444b5b | |
Robbie Antenesse | 3e4db6cb3c | |
Robbie Antenesse | 2e16f5310e | |
Robbie Antenesse | 5b2aca4592 | |
Robbie Antenesse | 5e75735acd | |
Robbie Antenesse | 4dbcb740f4 | |
Robbie Antenesse | abb1854d0f | |
Robbie Antenesse | d3ed1d1e41 | |
Robbie Antenesse | dd428abdee | |
Robbie Antenesse | f52fcb08d5 |
|
@ -3,4 +3,5 @@ node_modules/
|
|||
dist/
|
||||
vendor/
|
||||
|
||||
src/php/api/config.php
|
||||
src/php/api/config.php
|
||||
src/php/api/migrate.php
|
|
@ -25,3 +25,11 @@ It's less useful, but `npm run serve-frontend-only` will bundle and serve _only_
|
|||
## Production
|
||||
|
||||
`npm run bundle` bundles and minifies the frontend stuff and also copies the backend stuff to `dist`. Be sure to run `npm run clear` to delete the contents of `dist` and `.cache` before using `npm run bundle` to make sure you don't get old dev versions of the bundled code included in your upload.
|
||||
|
||||
## Migration
|
||||
|
||||
There is a script called `src/php/api/migrate.php.changeme` that can be used to help with the migration process from a `version1` Lexiconga database into a `master` database. **Note:** Migration is intended only for migrating from an old server to a freshly-installed/empty new database. To use this, copy `src/php/api/migrate.php.changeme` to `migrate.php` somewhere in the `version1` project (probably in `/php`) and copy the same to `/api/migrate.php` in your `master` project, making sure that all the variables for referencing the databases are correct.
|
||||
|
||||
Visit `migrate.php` on your `version1` server with `?outgoing=true` set in order to begin the transfer. The other server's `migrate.php` will receive an "incoming" request multiple times, and your screen will display messages as it works.
|
||||
|
||||
_DELETE THESE `migrate.php` FILES IMMEDIATELY AFTER MIGRATION IS COMPLETE!_.
|
||||
|
|
19
ads.json
19
ads.json
|
@ -1,16 +1,16 @@
|
|||
[
|
||||
{
|
||||
"header": "Do You Like Lexiconga?",
|
||||
"body": "If you enjoy Lexiconga, you can help contribute to keeping it online and adding new features. Your donations are much appreciated!",
|
||||
"cta": "Buy Me a Coffee!",
|
||||
"link": "https://buymeacoffee.com/robbieantenesse",
|
||||
"body": "You can contribute a small amount each month toward keeping Lexiconga online and help us keep working on new features. We appreciate whatever you can offer!",
|
||||
"cta": "Support Lexiconga!",
|
||||
"link": "https://liberapay.com/robbieantenesse/donate",
|
||||
"start": "June 1, 2019",
|
||||
"end": "August 1, 2099",
|
||||
"isPriority": false
|
||||
},
|
||||
{
|
||||
"header": "Support Lexiconga",
|
||||
"body": "If you enjoy Lexiconga, you can help contribute to keeping it online and adding new features. Your donations are much appreciated!",
|
||||
"header": "Support Lexiconga's Developer",
|
||||
"body": "If you enjoy Lexiconga, you can make a one-time donation to the developer toward keeping it online and adding new features. Your donations are much appreciated!",
|
||||
"cta": "Buy Me a Coffee!",
|
||||
"link": "https://buymeacoffee.com/robbieantenesse",
|
||||
"start": "June 1, 2019",
|
||||
|
@ -26,6 +26,15 @@
|
|||
"end": "March 1, 2020",
|
||||
"isPriority": false
|
||||
},
|
||||
{
|
||||
"header": "Protect Your Readers",
|
||||
"body": "RedFlag puts a wall between your readers or followers and content that you want to share. Choose up to 3 different warnings to help them be aware of what they're about to view!",
|
||||
"cta": "Use RedFlag for Free",
|
||||
"link": "https://redflag.ga",
|
||||
"start": "June 1, 2019",
|
||||
"end": "January 1, 2020",
|
||||
"isPriority": false
|
||||
},
|
||||
{
|
||||
"header": "Get Theonite: Planet Adyn free!",
|
||||
"body": "\"This book is the superhero fantasy you didn't know you needed. Magic, Afrofuturism, and heart-pumping suspense - this book has it all!\" - WeReadFantasy.com",
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
</section>
|
||||
</main>
|
||||
<footer id="bottom">
|
||||
<a href="https://buymeacoff.ee/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://liberapay.com/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://blog.lexicon.ga" target="_blank" class="small button">Blog</a>
|
||||
<a href="./" target="_blank" class="small button">Advertise</a>
|
||||
<a href="https://github.com/Alamantus/Lexiconga/issues" target="_blank" class="small button">Issues</a>
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
</main>
|
||||
|
||||
<footer id="bottom">
|
||||
<a href="https://buymeacoff.ee/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://liberapay.com/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://blog.lexicon.ga" target="_blank" class="small button">Blog</a>
|
||||
<a href="./advertising.html" target="_blank" class="small button">Advertise</a>
|
||||
<a href="https://github.com/Alamantus/Lexiconga/issues" target="_blank" class="small button">Issues</a>
|
||||
|
|
|
@ -69,6 +69,15 @@ export function removeTags(html) {
|
|||
return html;
|
||||
}
|
||||
|
||||
export function shuffle(array) {
|
||||
// Fisher-Yates shuffle
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export function slugify(string) {
|
||||
return removeDiacritics(string).replace(/[^a-zA-Z0-9-_]/g, '-');
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ export function performSync(remoteDictionary) {
|
|||
if (success) {
|
||||
renderAll();
|
||||
document.getElementById('accountSettingsChangeDictionary').value = window.currentDictionary.externalID;
|
||||
document.getElementById('publicLinkDisplay').style.display = window.currentDictionary.settings.isPublic ? '' : 'none';
|
||||
} else {
|
||||
console.error('word sync failed');
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { DISPLAY_AD_EVERY } from '../constants.js';
|
||||
import ads from '../../ads.json';
|
||||
import { shuffle } from '../helpers.js';
|
||||
|
||||
export function setupAds() {
|
||||
const shuffle = (a, b) => Math.random() > 0.5 ? 1 : -1;
|
||||
const priority = ads.filter(ad => isActive(ad) && ad.isPriority).sort(shuffle);
|
||||
const regular = ads.filter(ad => isActive(ad) && !ad.isPriority).sort(shuffle);
|
||||
const priority = shuffle(ads.filter(ad => isActive(ad) && ad.isPriority));
|
||||
const regular = shuffle(ads.filter(ad => isActive(ad) && !ad.isPriority));
|
||||
window.ads = [...priority, ...regular];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { fadeOutElement } from "./utilities";
|
||||
import { setCookie, getCookie } from "./StackOverflow/cookie";
|
||||
|
||||
export function isDismissed(announcementId) {
|
||||
let dismissed = getCookie(announcementId);
|
||||
|
||||
return dismissed === 'dismissed';
|
||||
}
|
||||
|
||||
export function dismiss(announcement) {
|
||||
if (announcement.id) {
|
||||
const expireDate = announcement.dataset.expires;
|
||||
const now = new Date();
|
||||
const expire = new Date(expireDate);
|
||||
const timeDiff = Math.abs(now.getTime() - expire.getTime());
|
||||
const dayDifference = Math.ceil(timeDiff / (1000 * 3600 * 24));
|
||||
setCookie(announcement.id, 'dismissed', dayDifference + 1);
|
||||
}
|
||||
fadeOutElement(announcement)
|
||||
}
|
|
@ -304,8 +304,11 @@ export function migrateDictionary() {
|
|||
window.currentDictionary = Object.assign({}, DEFAULT_DICTIONARY, window.currentDictionary);
|
||||
window.currentDictionary.partsOfSpeech = window.currentDictionary.settings.partsOfSpeech.split(',').map(val => val.trim()).filter(val => val !== '');
|
||||
delete window.currentDictionary.settings.partsOfSpeech;
|
||||
delete window.currentDictionary.nextWordId;
|
||||
window.currentDictionary.settings.sortByDefinition = window.currentDictionary.settings.sortByEquivalent;
|
||||
delete window.currentDictionary.settings.sortByEquivalent;
|
||||
window.currentDictionary.settings.theme = 'default';
|
||||
delete window.currentDictionary.settings.isComplete;
|
||||
|
||||
migrated = true;
|
||||
} else if (window.currentDictionary.version !== MIGRATE_VERSION) {
|
||||
|
|
|
@ -11,8 +11,11 @@ import { showSearchModal, clearSearchText, checkAllPartsOfSpeechFilters, uncheck
|
|||
import helpFile from '../markdown/help.md';
|
||||
import termsFile from '../markdown/terms.md';
|
||||
import privacyFile from '../markdown/privacy.md';
|
||||
import { dismiss, isDismissed } from './announcements';
|
||||
import { fadeOutElement } from './utilities';
|
||||
|
||||
export default function setupListeners() {
|
||||
setupAnnouncements();
|
||||
setupDetailsTabs();
|
||||
setupHeaderButtons();
|
||||
setupWordForm();
|
||||
|
@ -34,6 +37,17 @@ export function setupHeaderButtons() {
|
|||
});
|
||||
}
|
||||
|
||||
function setupAnnouncements() {
|
||||
const announcements = document.querySelectorAll('.announcement');
|
||||
Array.from(announcements).forEach(announcement => {
|
||||
if (announcement.id && isDismissed(announcement.id)) {
|
||||
fadeOutElement(announcement);
|
||||
} else {
|
||||
announcement.querySelector('.close-button').addEventListener('click', () => dismiss(announcement));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupDetailsTabs() {
|
||||
const tabs = document.querySelectorAll('#detailsSection nav li');
|
||||
tabs.forEach(tab => {
|
||||
|
|
|
@ -136,31 +136,6 @@ export function getHomonymnNumber(word) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
export function generateRandomWords(numberOfWords) {
|
||||
console.log('Generating', numberOfWords, 'words...');
|
||||
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||
letters.forEach(letter => letters.push(letter.toUpperCase()));
|
||||
const words = [];
|
||||
while (words.length < numberOfWords) {
|
||||
let word = '';
|
||||
while (word === '' || words.includes(word)) {
|
||||
word += letters[Math.floor(Math.random() * letters.length)];
|
||||
}
|
||||
words.push(word);
|
||||
}
|
||||
words.forEach((word, index) => {
|
||||
addWord({
|
||||
name: word,
|
||||
pronunciation: '/' + word + '/',
|
||||
partOfSpeech: Math.random() > 0.5 ? 'Noun' : 'Verb',
|
||||
definition: word,
|
||||
details: word + (index > 0 ? '\n\nRef: {{' + words[index - 1] + '}}' : ''),
|
||||
wordId: getNextId(),
|
||||
}, false);
|
||||
});
|
||||
console.log('done');
|
||||
}
|
||||
|
||||
export function addMessage(messageText, time = 5000, extraClass = false) {
|
||||
const messagingSection = document.getElementById('messagingSection');
|
||||
const element = document.createElement('div');
|
||||
|
@ -174,7 +149,7 @@ export function addMessage(messageText, time = 5000, extraClass = false) {
|
|||
const closeButton = element.querySelector('.close-button');
|
||||
const closeMessage = () => {
|
||||
closeButton.removeEventListener('click', closeMessage);
|
||||
messagingSection.removeChild(element);
|
||||
fadeOutElement(element);
|
||||
};
|
||||
closeButton.addEventListener('click', closeMessage);
|
||||
|
||||
|
@ -183,6 +158,13 @@ export function addMessage(messageText, time = 5000, extraClass = false) {
|
|||
}
|
||||
}
|
||||
|
||||
export function fadeOutElement(element) {
|
||||
element.classList.add('fadeout');
|
||||
setTimeout(() => {
|
||||
element.parentElement.removeChild(element);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
export function hideAllModals() {
|
||||
const permanentModals = ['#searchModal', '#settingsModal', '#editModal'];
|
||||
const hideModals = document.querySelectorAll(permanentModals.join(',')),
|
||||
|
|
|
@ -218,13 +218,13 @@ If you manage to enter your password wrong 10 times, you'll be locked out from l
|
|||
Please report any problems you come across to the [Lexiconga Issues page](https://github.com/Alamantus/Lexiconga/issues). You can also submit enhancement requests to the same place if you have any requests for new features.
|
||||
|
||||
## Update Log
|
||||
You can see all previous updates to Lexiconga on the [Lexiconga Releases page]](https://github.com/Alamantus/Lexiconga/releases).
|
||||
You can see all previous updates to Lexiconga on the [Lexiconga Releases page](https://github.com/Alamantus/Lexiconga/releases).
|
||||
|
||||
## Open Source
|
||||
Lexiconga's source code is fully open and readable on Github here: https://github.com/Alamantus/Lexiconga
|
||||
|
||||
## Thanks!
|
||||
If you like Lexiconga and want to buy me a cup of coffee for the service, you can use **[Buy Me A Coffee](https://buymeacoff.ee/robbieantenesse)** to help keep it online if you want.
|
||||
If you like Lexiconga and want to help contribute to keeping it online and motivate me to keep adding new features, you can use **[Buy Me A Coffee](https://buymeacoff.ee/robbieantenesse)** to give a one-time donation or **[Liberapay](https://liberapay.com/robbieantenesse)** to make a recurring donation.
|
||||
|
||||
I hope you enjoy Lexiconga and that it helps you build some awesome languages.
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
[
|
||||
{
|
||||
"header": "Test",
|
||||
"body": "<p>Test</p>",
|
||||
"expire": "January 1, 2020"
|
||||
"header": "Welcome to Lexiconga 2.0!",
|
||||
"body": "<p>Lexiconga has been rewritten from the ground up!</p><p>Check the <a href=\"https://github.com/Alamantus/Lexiconga/releases\" target=\"_blank\">Updates page</a> for all the new features, or click Help to get a refresher on how to use Lexiconga!</p>",
|
||||
"expire": "January 1, 2020",
|
||||
"dismissId": "welcome"
|
||||
}
|
||||
]
|
|
@ -18,12 +18,12 @@ class User {
|
|||
if ($user) {
|
||||
if ($user['old_password'] !== null) {
|
||||
if ($user['old_password'] === crypt($password, $email)) {
|
||||
if ($this->upgradePassword($password)) {
|
||||
if ($this->upgradePassword($password, $user)) {
|
||||
return $this->logIn($email, $password);
|
||||
}
|
||||
}
|
||||
} else if (password_verify($password, $user['password'])) {
|
||||
$this->db->execute('UPDATE users SET last_login=' . time() . ' WHERE id=' . $user['id']);
|
||||
$this->db->execute('UPDATE users SET last_login=current_timestamp() WHERE id=' . $user['id']);
|
||||
$token = $this->generateUserToken($user['id'], $user['current_dictionary']);
|
||||
return array(
|
||||
'token' => $token,
|
||||
|
@ -42,7 +42,7 @@ class User {
|
|||
|
||||
public function create ($email, $password, $user_data) {
|
||||
$insert_user_query = 'INSERT INTO users (email, password, public_name, allow_email, created_on)
|
||||
VALUES (?, ?, ?, ?, ?)';
|
||||
VALUES (?, ?, ?, ?, current_timestamp())';
|
||||
$password_hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$insert_user = $this->db->execute($insert_user_query, array(
|
||||
|
@ -50,7 +50,6 @@ VALUES (?, ?, ?, ?, ?)';
|
|||
$password_hash,
|
||||
$user_data['publicName'] !== '' ? $user_data['publicName'] : null,
|
||||
$user_data['allowEmail'] ? 1 : 0,
|
||||
time(),
|
||||
));
|
||||
if ($insert_user === true) {
|
||||
$new_user_id = $this->db->lastInsertId();
|
||||
|
@ -346,11 +345,11 @@ VALUES (?, ?, ?, ?, ?)';
|
|||
}
|
||||
|
||||
private function hasMembership ($id) {
|
||||
$current_membership = "SELECT * FROM memberships WHERE user=$id AND start_date>=CURRENT_TIMESTAMP AND CURRENT_TIMESTAMP<expire_date";
|
||||
$current_membership = "SELECT * FROM memberships WHERE user=$id AND start_date>=current_timestamp() AND current_timestamp()<expire_date";
|
||||
return $this->db->query($current_membership)->rowCount() > 0;
|
||||
}
|
||||
|
||||
private function upgradePassword ($password) {
|
||||
private function upgradePassword($password, $user) {
|
||||
$new_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$update_query = 'UPDATE users SET old_password=NULL, password=? WHERE id=' . $user['id'];
|
||||
$stmt = $this->db->query($update_query, array($new_password));
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
<?php
|
||||
$incoming = isset($_POST['incoming']) ? json_decode($_POST['incoming'], true) : false;
|
||||
$outgoing = isset($_GET['outgoing']);
|
||||
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Expires: Sun, 01 Nov 2015 22:46:51 GMT');
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
define("VERSION1_DATABASE_SERVERNAME", "host");
|
||||
define("VERSION1_DATABASE_USERNAME", "username");
|
||||
define("VERSION1_DATABASE_PASSWORD", "password");
|
||||
define("VERSION1_DATABASE_NAME", "database");
|
||||
define("MIGRATE_TO", "remote_url");
|
||||
define("NEW_DATABASE_SERVERNAME", "host");
|
||||
define("NEW_DATABASE_USERNAME", "username");
|
||||
define("NEW_DATABASE_PASSWORD", "password");
|
||||
define("NEW_DATABASE_NAME", "database");
|
||||
|
||||
if ($outgoing) {
|
||||
echo '<pre>' . PHP_EOL;
|
||||
echo 'Starting migration from ' . VERSION1_DATABASE_SERVERNAME . ' db ' . VERSION1_DATABASE_NAME . PHP_EOL . 'To ' . MIGRATE_TO . PHP_EOL . PHP_EOL;
|
||||
|
||||
$dbconnection = new PDO('mysql:host=' . VERSION1_DATABASE_SERVERNAME . ';dbname=' . VERSION1_DATABASE_NAME . ';charset=utf8', VERSION1_DATABASE_USERNAME, VERSION1_DATABASE_PASSWORD);
|
||||
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
// $dbconnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
|
||||
$dbconnection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
try {
|
||||
$users_stmt = $dbconnection->prepare('SELECT * FROM `users`');
|
||||
$users_stmt->execute();
|
||||
if ($users_stmt) {
|
||||
$users = $users_stmt->fetchAll();
|
||||
if ($users !== false) {
|
||||
echo count($users) . ' Users' . PHP_EOL;
|
||||
|
||||
foreach($users as $user) {
|
||||
$send_user_response = send('user', $user);
|
||||
|
||||
if ($send_user_response === "GOT USER") {
|
||||
echo PHP_EOL . 'User ' . $user['id'] . ' sent successfully' . PHP_EOL;
|
||||
|
||||
$dictionaries_stmt = $dbconnection->prepare('SELECT * FROM `dictionaries` WHERE `user`=?');
|
||||
$dictionaries_stmt->execute(array(intval($user['id'])));
|
||||
if ($dictionaries_stmt) {
|
||||
$dictionaries = $dictionaries_stmt->fetchAll();
|
||||
if ($dictionaries !== false) {
|
||||
echo 'User ' . $user['id'] . ' has ' . count($dictionaries) . ' Dictionaries' . PHP_EOL;
|
||||
|
||||
$send_dictionaries_response = send('dictionaries', $dictionaries, array('user' => $user['id']));
|
||||
|
||||
if ($send_dictionaries_response === 'GOT DICTIONARIES') {
|
||||
echo 'Dictionaries sent successfully' . PHP_EOL;
|
||||
|
||||
foreach($dictionaries as $dictionary) {
|
||||
$words_stmt = $dbconnection->prepare('SELECT * FROM `words` WHERE `dictionary`=?');
|
||||
$words_stmt->execute(array(intval($dictionary['id'])));
|
||||
if ($words_stmt) {
|
||||
$words = $words_stmt->fetchAll();
|
||||
if ($words !== false) {
|
||||
$send_words_response = send('words', $words);
|
||||
|
||||
if ($send_words_response === 'GOT WORDS') {
|
||||
echo 'Words for Dictionary ' . $dictionary['id'] . ' sent successfully' . PHP_EOL;
|
||||
} else {
|
||||
echo var_export($send_words_response, true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo '$words_stmt->fetchAll() failed.' . PHP_EOL . var_export($words_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo '$words_stmt failed' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo var_export($send_dictionaries_response, true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo '$dictionaries_stmt->fetchAll() failed.' . PHP_EOL . var_export($dictionaries_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo '$dictionaries_stmt failed' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
var_dump($send_user_response) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo '$users_stmt->fetchAll() failed.' . PHP_EOL . var_export($users_stmt->errorInfo(), true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo '$users_stmt failed' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
catch (PDOException $ex) {
|
||||
echo var_export($ex, true) . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
||||
echo '</pre>';
|
||||
} else if ($incoming !== false) {
|
||||
$type = isset($_POST['type']) ? $_POST['type'] : false;
|
||||
|
||||
if ($type !== false) {
|
||||
$dbconnection = new PDO('mysql:host=' . NEW_DATABASE_SERVERNAME . ';dbname=' . NEW_DATABASE_NAME . ';charset=utf8', NEW_DATABASE_USERNAME, NEW_DATABASE_PASSWORD);
|
||||
$dbconnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
switch($type) {
|
||||
case 'user': {
|
||||
if ($incoming === null) {
|
||||
echo 'Invalid JSON';
|
||||
} else {
|
||||
$user_stmt = $dbconnection->prepare('INSERT INTO `users`(`id`, `email`, `old_password`, `password`, `public_name`, `current_dictionary`, `allow_email`, `last_login`, `password_reset_code`, `password_reset_date`, `created_on`) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
|
||||
$user_stmt->execute(array(
|
||||
intval($incoming['id']),
|
||||
$incoming['email'],
|
||||
$incoming['password'],
|
||||
null,
|
||||
$incoming['public_name'],
|
||||
intval($incoming['current_dictionary']),
|
||||
intval($incoming['allow_email']),
|
||||
$incoming['last_login'],
|
||||
null,
|
||||
null,
|
||||
$incoming['created_on'],
|
||||
));
|
||||
if ($user_stmt) {
|
||||
echo 'GOT USER';
|
||||
} else {
|
||||
var_dump($user_stmt->errorInfo());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'dictionaries': {
|
||||
if ($incoming === null) {
|
||||
echo 'Invalid JSON';
|
||||
} else {
|
||||
if (count($incoming) === 0) {
|
||||
echo 'Need new dictionary for user ' . $_POST['user'] . ': ';
|
||||
|
||||
$new_id = mt_rand(1000, 999999999);
|
||||
|
||||
$user = intval($_POST['user']);
|
||||
$insert_dictionary_query = "INSERT INTO dictionaries (id, user, description, created_on) VALUES (?, ?, ?, ?)";
|
||||
$insert_dictionary_stmt = $dbconnection->prepare($insert_dictionary_query);
|
||||
$insert_dictionary = $insert_dictionary_stmt->execute(array($new_id, $user, 'A new dictionary.', time()));
|
||||
|
||||
if ($insert_dictionary) {
|
||||
$insert_linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, parts_of_speech, exceptions, orthography_notes, grammar_notes) VALUES ($new_id, ?, ?, ?, ?)";
|
||||
$insert_linguistics_stmt = $dbconnection->prepare($insert_linguistics_query);
|
||||
$insert_linguistics = $insert_linguistics_stmt->execute(array('Noun,Adjective,Verb', '', '', ''));
|
||||
|
||||
if ($insert_linguistics === true) {
|
||||
$update_query = 'UPDATE users SET current_dictionary=? WHERE id=?';
|
||||
$update_stmt = $dbconnection->prepare($update_query);
|
||||
$update = $update_stmt->execute(array($new_id, $user));
|
||||
if ($update) {
|
||||
echo 'CREATED DICTIONARY';
|
||||
} else {
|
||||
var_dump($update_stmt);
|
||||
}
|
||||
} else {
|
||||
var_dump($insert_linguistics_stmt->errorInfo());
|
||||
}
|
||||
} else {
|
||||
var_dump($insert_dictionary_stmt->errorInfo());
|
||||
}
|
||||
} else {
|
||||
$dictionaries_query = 'INSERT INTO `dictionaries`(`id`, `user`, `name`, `specification`, `description`, `allow_duplicates`, `case_sensitive`, `sort_by_definition`, `theme`, `is_public`, `last_updated`, `created_on`) VALUES ';
|
||||
$linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, parts_of_speech, exceptions, orthography_notes, grammar_notes) VALUES ";
|
||||
$dictionaries_params = array();
|
||||
$linguistics_params = array();
|
||||
foreach($incoming as $dictionary) {
|
||||
$dictionaries_query .= '(?,?,?,?,?,?,?,?,?,?,?,?), ';
|
||||
// `id`, `user`, `name`, `description`, `words`, `next_word_id`, `allow_duplicates`, `case_sensitive`, `parts_of_speech`, `sort_by_equivalent`, `is_complete`, `is_public`, `last_updated`, `created_on`
|
||||
$dictionaries_params[] = intval($dictionary['id']);
|
||||
$dictionaries_params[] = intval($dictionary['user']);
|
||||
$dictionaries_params[] = $dictionary['name'];
|
||||
$dictionaries_params[] = 'Dictionary';
|
||||
$dictionaries_params[] = fixStupidOldNonsense($dictionary['description']);
|
||||
$dictionaries_params[] = intval($dictionary['allow_duplicates']);
|
||||
$dictionaries_params[] = intval($dictionary['case_sensitive']);
|
||||
$dictionaries_params[] = intval($dictionary['sort_by_equivalent']);
|
||||
$dictionaries_params[] = 'default';
|
||||
$dictionaries_params[] = intval($dictionary['is_public']);
|
||||
$dictionaries_params[] = $dictionary['last_updated'] ? strtotime($dictionary['last_updated']) : null;
|
||||
$dictionaries_params[] = strtotime($dictionary['created_on']);
|
||||
|
||||
$linguistics_query .= '(?, ?, ?, ?, ?), ';
|
||||
$linguistics_params[] = intval($dictionary['id']);
|
||||
$linguistics_params[] = $dictionary['parts_of_speech'];
|
||||
$linguistics_params[] = '';
|
||||
$linguistics_params[] = '';
|
||||
$linguistics_params[] = '';
|
||||
}
|
||||
$dictionaries_stmt = $dbconnection->prepare(trim($dictionaries_query, ', '));
|
||||
$dictionaries_stmt->execute($dictionaries_params);
|
||||
if ($dictionaries_stmt) {
|
||||
$linguistics_stmt = $dbconnection->prepare(trim($linguistics_query, ', '));
|
||||
$linguistics_stmt->execute($linguistics_params);
|
||||
if ($linguistics_stmt) {
|
||||
echo 'GOT DICTIONARIES';
|
||||
} else {
|
||||
var_dump($linguistics_stmt->errorInfo());
|
||||
}
|
||||
} else {
|
||||
var_dump($dictionaries_stmt->errorInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'words': {
|
||||
if ($incoming === null) {
|
||||
echo 'Invalid JSON';
|
||||
} else {
|
||||
if (count($incoming) > 0) {
|
||||
$words_query = 'INSERT INTO `words`(`dictionary`, `word_id`, `name`, `pronunciation`, `part_of_speech`, `definition`, `details`, `last_updated`, `created_on`) VALUES ';
|
||||
$words_params = array();
|
||||
foreach($incoming as $word) {
|
||||
$words_query .= '(?,?,?,?,?,?,?,?,?), ';
|
||||
// `dictionary`, `word_id`, `name`, `pronunciation`, `part_of_speech`, `simple_definition`, `long_definition`, `last_updated`, `created_on`
|
||||
$words_params[] = intval($word['dictionary']);
|
||||
$words_params[] = intval($word['word_id']);
|
||||
$words_params[] = $word['name'];
|
||||
$words_params[] = $word['pronunciation'];
|
||||
$words_params[] = $word['part_of_speech'];
|
||||
$words_params[] = $word['simple_definition'];
|
||||
$words_params[] = fixStupidOldNonsense($word['long_definition']);
|
||||
$words_params[] = $word['last_updated'] ? strtotime($word['last_updated']) : null;
|
||||
$words_params[] = strtotime($word['created_on']);
|
||||
}
|
||||
$words_stmt = $dbconnection->prepare(trim($words_query, ', '));
|
||||
$words_stmt->execute($words_params);
|
||||
if ($words_stmt) {
|
||||
echo 'GOT WORDS';
|
||||
} else {
|
||||
var_dump($words_stmt->errorInfo());
|
||||
}
|
||||
} else {
|
||||
echo 'NO WORDS';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo 'no' . PHP_EOL . PHP_EOL;
|
||||
}
|
||||
|
||||
function send($type, $data, $additional_data = array()) {
|
||||
$send_data = array_merge(array('type' => $type, 'incoming' => json_encode($data)), $additional_data);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, MIGRATE_TO . '/api/migrate.php');
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($send_data));
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$server_output = curl_exec($ch);
|
||||
|
||||
curl_close ($ch);
|
||||
|
||||
return $server_output;
|
||||
}
|
||||
|
||||
function fixStupidOldNonsense($markdown) {
|
||||
$markdown = str_replace('"', '"', $markdown);
|
||||
$markdown = str_replace(''', "'", $markdown);
|
||||
$markdown = str_replace('\', '\\', $markdown);
|
||||
$markdown = str_replace('<br>', '\\n', $markdown);
|
||||
return $markdown;
|
||||
}
|
|
@ -75,8 +75,8 @@ switch ($view) {
|
|||
foreach ($announcements as $announcement) {
|
||||
$expire = strtotime($announcement['expire']);
|
||||
if (time() < $expire) {
|
||||
$announcements_html .= '<article class="announcement">
|
||||
<a class="close-button" title="Close Announcement" onclick="this.parentElement.parentElement.removeChild(this.parentElement);">×︎</a>
|
||||
$announcements_html .= '<article class="announcement"' . (isset($announcement['dismissId']) ? ' id="announcement-' . $announcement['dismissId'] . '"' : '') . ' data-expires="' . $announcement['expire'] . '">
|
||||
<a class="close-button" title="Dismiss Announcement">×︎</a>
|
||||
<h4>' . $announcement['header'] . '</h4>
|
||||
' . $announcement['body'] . '
|
||||
</article>';
|
||||
|
|
|
@ -212,6 +212,25 @@ span .tag {
|
|||
}
|
||||
}
|
||||
|
||||
.fadeout {
|
||||
overflow: hidden;
|
||||
animation-name: shut;
|
||||
animation-duration: 0.3s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: 1;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
@keyframes shut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
max-height: 200px;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
max-height: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
|
|
@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS `dictionaries` (
|
|||
`last_updated` int(11) DEFAULT NULL,
|
||||
`created_on` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=500 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER IF NOT EXISTS `delete_dictionary_parts` AFTER DELETE ON `dictionaries` FOR EACH ROW BEGIN
|
||||
DELETE FROM words WHERE words.dictionary=old.id;
|
||||
|
@ -33,16 +33,16 @@ DELIMITER ;
|
|||
|
||||
CREATE TABLE IF NOT EXISTS `dictionary_linguistics` (
|
||||
`dictionary` int(11) NOT NULL,
|
||||
`parts_of_speech` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'Comma-separated',
|
||||
`consonants` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`vowels` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`blends` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`onset` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`nucleus` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`coda` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`exceptions` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
`orthography_notes` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
`grammar_notes` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
`parts_of_speech` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'Comma-separated',
|
||||
`consonants` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`vowels` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`blends` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Space-separated',
|
||||
`onset` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`nucleus` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`coda` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Comma-separated',
|
||||
`exceptions` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
`orthography_notes` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
`grammar_notes` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'Markdown',
|
||||
UNIQUE KEY `dictionary` (`dictionary`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
@ -62,13 +62,13 @@ CREATE TABLE IF NOT EXISTS `users` (
|
|||
`public_name` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Someone',
|
||||
`current_dictionary` int(11) DEFAULT NULL,
|
||||
`allow_email` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`last_login` int(11) DEFAULT NULL,
|
||||
`last_login` datetime DEFAULT NULL,
|
||||
`password_reset_code` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`password_reset_date` datetime DEFAULT NULL,
|
||||
`created_on` int(11) NOT NULL,
|
||||
`password_reset_date` timestamp NULL DEFAULT NULL,
|
||||
`created_on` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=200 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=500 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER IF NOT EXISTS `Delete_User_Dictionaries` AFTER DELETE ON `users` FOR EACH ROW DELETE FROM dictionaries WHERE dictionaries.user = old.id
|
||||
$$
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
</main>
|
||||
|
||||
<footer id="bottom">
|
||||
<a href="https://buymeacoff.ee/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://liberapay.com/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://blog.lexicon.ga" target="_blank" class="small button">Blog</a>
|
||||
<a href="./advertising.html" target="_blank" class="small button">Advertise</a>
|
||||
<a href="https://github.com/Alamantus/Lexiconga/issues" target="_blank" class="small button">Issues</a>
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Password Reset | Lexiconga</title>
|
||||
<meta property="og:url" content="https://lexicon.ga/advertising.html" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:title" content="Advertising on Lexiconga" />
|
||||
<meta property="og:description" content="Buy advertisement space on Lexiconga" />
|
||||
<!--meta property="og:image" content="http://lexicon.ga/images/logo.svg" /-->
|
||||
<link rel="icon" href="src/images/favicon.png" type="image/x-icon" />
|
||||
<link rel="stylesheet" href="src/main.scss" />
|
||||
<script src="src/js/account/passwordReset.js"></script>
|
||||
|
@ -46,7 +41,7 @@
|
|||
</section>
|
||||
</main>
|
||||
<footer id="bottom">
|
||||
<a href="https://buymeacoff.ee/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://liberapay.com/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://blog.lexicon.ga" target="_blank" class="small button">Blog</a>
|
||||
<a href="./" target="_blank" class="small button">Advertise</a>
|
||||
<a href="https://github.com/Alamantus/Lexiconga/issues" target="_blank" class="small button">Issues</a>
|
||||
|
|
|
@ -101,38 +101,10 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<!-- div id="headerMenu">
|
||||
<a id="settingsButton" class="button">Settings</a>
|
||||
<a id="loginCreateAccountButton" class="button">Log In / Create Account</a>
|
||||
</div -->
|
||||
<div style="clear:both;"></div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!--aside id="sideColumn">
|
||||
<div id="mobileWordFormShow">+</div>
|
||||
<form id="wordForm">
|
||||
<label>Word<span class="red">*</span><br>
|
||||
<input id="wordName" maxlength="200">
|
||||
</label>
|
||||
<label>Pronunciation<a class="label-button ipa-table-button">IPA Chart</a><br>
|
||||
<input id="wordPronunciation" class="ipa-field" maxlength="200"><br>
|
||||
<a class="label-help-button ipa-field-help-button">Field Help</a>
|
||||
</label>
|
||||
<label>Part of Speech<br>
|
||||
<select id="wordPartOfSpeech" class="part-of-speech-select"></select>
|
||||
</label>
|
||||
<label>Definition<span class="red">*</span><br>
|
||||
<input id="wordDefinition" maxlength="2500" placeholder="Equivalent words">
|
||||
</label>
|
||||
<label>Details<span class="red">*</span><a class="label-button maximize-button">Maximize</a><br>
|
||||
<textarea id="wordDetails" placeholder="Markdown formatting allowed"></textarea>
|
||||
</label>
|
||||
<div id="wordErrorMessage"></div>
|
||||
<a class="button" id="addWordButton">Add Word</a>
|
||||
</form>
|
||||
</aside -->
|
||||
|
||||
<section id="mainColumn">
|
||||
<section id="detailsSection">
|
||||
<a id="dictionaryShare" href="./" class="button" title="Link to Dictionary" style="float:right;">➦</a>
|
||||
|
@ -140,7 +112,7 @@
|
|||
<h4>Created by {{public_name}}</h4>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>Description</li><li>Details</li><li>Stats</li><!-- li id="editDictionaryButton">Edit</li -->
|
||||
<li>Description</li><li>Details</li><li>Stats</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article id="detailsPanel" style="display:none;">
|
||||
|
@ -166,7 +138,7 @@
|
|||
</main>
|
||||
|
||||
<footer id="bottom">
|
||||
<a href="https://buymeacoff.ee/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://liberapay.com/robbieantenesse" target="_blank" class="small button">Support Lexiconga</a>
|
||||
<a href="https://blog.lexicon.ga" target="_blank" class="small button">Blog</a>
|
||||
<a href="./advertising.html" target="_blank" class="small button">Advertise</a>
|
||||
<a href="https://github.com/Alamantus/Lexiconga/issues" target="_blank" class="small button">Issues</a>
|
||||
|
@ -177,193 +149,6 @@
|
|||
<a class="button" id="privacyInfoButton">Privacy</a>
|
||||
</footer>
|
||||
|
||||
<!-- section id="settingsModal" class="modal" style="display:none;">
|
||||
<div class="modal-background" onclick="this.parentElement.style.display='none';"></div>
|
||||
<div class="modal-content">
|
||||
<a class="close-button" onclick="this.parentElement.parentElement.style.display='none';">×︎</a>
|
||||
<section>
|
||||
<form class="split two">
|
||||
<div>
|
||||
<h3>General Settings</h3>
|
||||
<label>Use IPA Auto-Fill
|
||||
<input id="settingsUseIPA" type="checkbox" checked><br />
|
||||
<small>Check this to use character combinations to input International Phonetic Alphabet characters into
|
||||
Pronunciation fields.</small>
|
||||
</label>
|
||||
|
||||
<label>Use Hotkeys
|
||||
<input id="settingsUseHotkeys" type="checkbox" checked><br />
|
||||
<small>Check this to enable keyboard combinations to perform different helpful actions.</small>
|
||||
</label>
|
||||
|
||||
<label>Theme
|
||||
<select disabled>
|
||||
<option selected value="default">Default</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="green">Green</option>
|
||||
<option value="royal">Royal</option>
|
||||
</select>
|
||||
</label>
|
||||
<div id="accountSettings"></div>
|
||||
</div>
|
||||
<div id="accountActions"></div>
|
||||
</form>
|
||||
</section>
|
||||
<footer>
|
||||
<a class="button" id="settingsSave">Save</a>
|
||||
<a class="button" id="settingsSaveAndClose">Save & Close</a>
|
||||
<a class="red button" onclick="this.parentElement.parentElement.parentElement.style.display='none';">Close Without Saving</a>
|
||||
</footer>
|
||||
</div>
|
||||
</section -->
|
||||
|
||||
<!-- section id="editModal" class="modal" style="display:none;">
|
||||
<div class="modal-background" onclick="this.parentElement.style.display='none';"></div>
|
||||
<div class="modal-content">
|
||||
<a class="close-button" onclick="this.parentElement.parentElement.style.display='none';">×︎</a>
|
||||
<nav class="tabs">
|
||||
<ul>
|
||||
<li class="active">Description</li><li>Details</li><li>Settings</li><li>Actions</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section id="editDescriptionTab">
|
||||
<label>Name<br>
|
||||
<input id="editName" maxlength="50">
|
||||
</label>
|
||||
<label>Specification<br>
|
||||
<input id="editSpecification" maxlength="50">
|
||||
</label>
|
||||
<label>Description<a class="label-button maximize-button">Maximize</a><br>
|
||||
<textarea id="editDescription"></textarea>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section id="editDetailsTab" style="display:none;">
|
||||
<label>Parts of Speech <small>(Comma Separated List)</small><br>
|
||||
<input id="editPartsOfSpeech" maxlength="2500" placeholder="Noun,Adjective,Verb">
|
||||
</label>
|
||||
<label>Alphabetical Order <small>(Comma Separated List. Include every letter!)</small><br>
|
||||
<input id="editAlphabeticalOrder" disabled value="English Alphabet">
|
||||
</label>
|
||||
<h3>Phonology</h3>
|
||||
<div class="split three">
|
||||
<div>
|
||||
<label>Consonants<br>
|
||||
<small>(Space separated list)</small><br>
|
||||
<input id="editConsonants" class="ipa-field" maxlength="100" placeholder="p b m n t ..."><br>
|
||||
<a class="label-help-button ipa-field-help-button">Field Help</a>
|
||||
<a class="label-button ipa-table-button">IPA Chart</a>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Vowels<br>
|
||||
<small>(Space separated list)</small><br>
|
||||
<input id="editVowels" class="ipa-field" maxlength="100" placeholder="æ u e ɪ ..."><br>
|
||||
<a class="label-help-button ipa-field-help-button">Field Help</a>
|
||||
<a class="label-button ipa-table-button">IPA Chart</a>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Polyphthongs / Blends<br>
|
||||
<small>(Space separated list)</small><br>
|
||||
<input id="editBlends" class="ipa-field" maxlength="100" placeholder="ai ou ue ..."><br>
|
||||
<a class="label-help-button ipa-field-help-button">Field Help</a>
|
||||
<a class="label-button ipa-table-button">IPA Chart</a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Phonotactics</h3>
|
||||
<div class="split three">
|
||||
<div>
|
||||
<label>Onset<br>
|
||||
<small>(Comma separated list)</small><br>
|
||||
<input id="editOnset" maxlength="100" placeholder="Consonants,Vowels">
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Nucleus<br>
|
||||
<small>(Comma separated list)</small><br>
|
||||
<input id="editNucleus" maxlength="100" placeholder="Vowels,Blends">
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Coda<br>
|
||||
<small>(Comma separated list)</small><br>
|
||||
<input id="editCoda" maxlength="100" placeholder="Any">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<label>Exceptions <small>(Markdown-enabled)</small><br>
|
||||
<textarea id="editExceptions"></textarea>
|
||||
</label>
|
||||
<h3>Orthography</h3>
|
||||
<label>Notes <small>(Markdown-enabled)</small><a class="label-button maximize-button">Maximize</a><br>
|
||||
<textarea id="editOrthography"></textarea>
|
||||
</label>
|
||||
<h3>Grammar</h3>
|
||||
<label>Notes <small>(Markdown-enabled)</small><a class="label-button maximize-button">Maximize</a><br>
|
||||
<textarea id="editGrammar"></textarea>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section id="editSettingsTab" style="display:none;">
|
||||
<label>Prevent Duplicate Words
|
||||
<input type="checkbox" id="editPreventDuplicates"><br>
|
||||
<small>Checking this box will prevent the creation of words with the exact same spelling.</small>
|
||||
</label>
|
||||
<label>Words are Case-Sensitive
|
||||
<input type="checkbox" id="editCaseSensitive"><br>
|
||||
<small>Checking this box will allow the creation of words with the exact same spelling if their capitalization is different.</small>
|
||||
</label>
|
||||
<label>Sort by Definition
|
||||
<input type="checkbox" id="editSortByDefinition"><br>
|
||||
<small>Checking this box will sort the words in alphabetical order based on the Definition instead of the Word.</small>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section id="editActionsTab" style="display:none;">
|
||||
<h3>Import / Export</h3>
|
||||
<div class="split two">
|
||||
<div>
|
||||
<p>
|
||||
<label class="button">Import JSON <input type="file" id="importDictionaryFile" accept="application/json, .dict"><br>
|
||||
<small>Import a previously-exported <code>JSON</code> file.</small>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label class="button">Import Words <input type="file" id="importWordsCSV" accept="text/csv, .csv"><br>
|
||||
<small>Import a CSV file of words.</small>
|
||||
</label>
|
||||
<a class="small button" download="Lexiconga_import-template.csv" href="data:text/csv;charset=utf-8,%22word%22,%22pronunciation%22,%22part of speech%22,%22definition%22,%22explanation%22%0A">Download an example file with the correct formatting</a>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<a class="button" id="exportDictionaryButton">Export JSON</a><br>
|
||||
<small>Export your work as a <code>JSON</code> file to re-import later.</small>
|
||||
</p>
|
||||
<p>
|
||||
<a class="button" id="exportWordsButton">Export Words</a><br>
|
||||
<small>Export a CSV file of your words.</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<a class="red button" id="deleteDictionaryButton">Delete Dictionary</a><br>
|
||||
<small>This will permanently delete your current dictionary, and it will not be possible to return it if you have not backed it up!</small>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<a class="button" id="editSave">Save</a>
|
||||
<a class="button" id="editSaveAndClose">Save & Close</a>
|
||||
<a class="red button" onclick="this.parentElement.parentElement.parentElement.style.display='none';">Close Without Saving</a>
|
||||
</footer>
|
||||
</div>
|
||||
</section -->
|
||||
|
||||
<div id="messagingSection"></div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue