Compare commits

...

41 Commits

Author SHA1 Message Date
2c9511ecf4 migrate email to use Util class and method 2024-07-02 01:41:47 -04:00
97d656912c migrate email to use Util class and method 2024-07-02 01:41:33 -04:00
717b9398bc Added credential login check for visiting the profile page 2024-07-02 01:39:11 -04:00
6a070ca4e0 Added shareNote method to share an individual note with an email 2024-07-02 01:38:36 -04:00
fa8ef2ab78 Update styles 2024-07-02 01:33:24 -04:00
20dc1622f2 Fix error with not sending emails 2024-07-02 01:33:14 -04:00
fbf5ac564a To support note deletion 2024-06-24 15:43:03 -04:00
d24c304c97 Updates 2024-06-23 22:41:33 -04:00
752b2a291e Add profile data 2024-06-23 22:40:50 -04:00
87fb461c26 Update database and add new migration 2024-06-23 20:13:25 -04:00
70e9ef508c Style updates 2024-06-23 20:13:02 -04:00
fba8454743 Added formatted cheat sheet html content for help 2024-06-11 21:23:43 -04:00
da5e3b538d Updates to docker build 2024-06-09 20:42:39 -04:00
c2c08db342 Add saveFailCounter
Fix bug with not clearing noteId
Refactor a class removal and additions
Add script.min.js
2024-06-09 20:26:54 -04:00
4d55711190 Adding new reference type retrieval 2024-06-09 20:24:44 -04:00
164ed62a48 add method for retrieving 39 articles 2024-06-09 20:18:54 -04:00
bdc67942ea Add validation for email registration 2024-06-09 20:18:27 -04:00
4a6191e287 Add link to markdown cheat sheet 2024-06-09 20:17:40 -04:00
d809e7eb38 Add new reference types 2024-06-09 20:17:20 -04:00
83709509f2 Move markdown cheat sheet 2024-06-09 20:16:42 -04:00
7bb909dfe4 Add link for recording 2024-05-29 00:37:56 -04:00
1d98940341 removed onload method call since it's now in script.js 2024-05-29 00:37:27 -04:00
14b4ca0545 add moment.js and datatables.js 2024-05-29 00:37:12 -04:00
ea60cf2622 add methods to retrieve new references 2024-05-29 00:35:42 -04:00
53e5c48aa9 Changed reference editor to not pass through data 2024-05-29 00:34:50 -04:00
a1e921063a add getNotes method for open notes table 2024-05-29 00:32:07 -04:00
2552335513 Migrate openNotes table to use DataTables
Added couple helper methods
Fixed not clearing recording link on "New Note"
add retrieveReferenceType method for reference editor
2024-05-29 00:30:42 -04:00
74b24afc75 Style updates 2024-05-29 00:24:05 -04:00
451a61722e New starter dataset 2024-05-29 00:23:48 -04:00
a46253ec7d Add retrieveLBC and retrieveNote for references 2024-05-26 22:46:54 -04:00
45a3398ac7 Fix error with retrieving HC and CD references and add LBC 2024-05-26 22:46:25 -04:00
a20caf1fc8 Added LBC and note reference retrieval
Convert get-reference to retrieve data from database instead of files
Fixed error with saving new note
2024-05-26 22:43:56 -04:00
435402ee41 Add LBC and new reference field 2024-05-26 22:40:45 -04:00
8315970571 Reorg the note fields and add recording link field
Add LBC
2024-05-26 22:33:41 -04:00
d26874d88b Add recording link field 2024-05-26 22:30:53 -04:00
d1ac0578f3 Add recording link field to note 2024-05-26 22:30:39 -04:00
3d10944b6d Style updates 2024-05-26 22:30:20 -04:00
72bf4273f3 increase saveTimeout
add check for note text to see if something has changed
add recording link text field
fix error for check
covert reference buttons to match style of other buttons
2024-05-26 22:30:03 -04:00
77e2777c7a Add LBC 2024-05-26 22:24:51 -04:00
a1f5ce416c Style updates 2024-05-26 22:24:40 -04:00
6af0095470 Merge pull request 'Remerge' (#3) from main into 1.1
Reviewed-on: #3
2024-05-25 08:11:00 -04:00
30 changed files with 1232 additions and 207 deletions

View File

@ -1,4 +1,4 @@
FROM php:8.2-apache FROM php:8.3-apache
RUN apt update && \ RUN apt update && \
apt upgrade -y && \ apt upgrade -y && \
@ -45,10 +45,13 @@ RUN rm -rf /var/www/html/tests
RUN rm -rf /var/www/html/translations RUN rm -rf /var/www/html/translations
RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-scripts --no-dev --optimize-autoloader RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-scripts --no-dev --optimize-autoloader
RUN mv /var/www/html/data/data.db /var/www/html/var/ RUN mkdir /data
RUN chown -R 33:33 /data
RUN chmod -R 755 /data
COPY data/data.db /data/data.db
RUN mkdir /var/www/html/var/cache RUN mkdir /var/www/html/var/cache
RUN mkdir /var/www/html/var/log RUN mkdir /var/www/html/var/log
RUN chown -R www-data:www-data /var/www/html RUN chown -R 33:33 /var/www/html
RUN chmod -R 755 /var/www/html RUN chmod -R 755 /var/www/html

View File

@ -1,3 +1,4 @@
framework: framework:
mailer: mailer:
dsn: '%env(MAILER_DSN)%' dsn: "%env(MAILER_DSN)%"
message_bus: false

Binary file not shown.

View File

@ -5,4 +5,6 @@ services:
container_name: sermon-notes container_name: sermon-notes
image: ryanprather/sermon-notes:latest image: ryanprather/sermon-notes:latest
ports: ports:
- 80:80 - 80:80
volumes:
- ./data:/data

View File

@ -10,8 +10,10 @@ LENGTH=32
SECRET_KEY=$(openssl rand -base64 $LENGTH | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' ') SECRET_KEY=$(openssl rand -base64 $LENGTH | tr -d '=' | tr -d '+' | tr -d '/' | tr -d ' ')
TRIMMED_KEY=$(cut -c1-32 <<< $SECRET_KEY) TRIMMED_KEY=$(cut -c1-32 <<< $SECRET_KEY)
echo "APP_SECRET=$TRIMMED_KEY" >> .env echo "APP_SECRET=$TRIMMED_KEY" >> .env
echo "DATABASE_URL=\"sqlite:///%kernel.project_dir%/var/data.db\"" >> .env echo "DATABASE_URL=\"sqlite:///data/data.db\"" >> .env
echo "MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0" >> .env echo "MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0" >> .env
symfony console doctrine:migrations:migrate --no-interaction
COMPOSER_ALLOW_SUPERUSER=1 composer update COMPOSER_ALLOW_SUPERUSER=1 composer update
symfony console doctrine:migrations:migrate --no-interaction
chown -R www-data:www-data /data

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240527010736 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE note ADD COLUMN recording VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__note AS SELECT id, speaker_id, series_id, user_id, title, date, passage, refs, text FROM note');
$this->addSql('DROP TABLE note');
$this->addSql('CREATE TABLE note (id BLOB NOT NULL --(DC2Type:uuid)
, speaker_id BLOB DEFAULT NULL --(DC2Type:uuid)
, series_id BLOB DEFAULT NULL --(DC2Type:uuid)
, user_id BLOB DEFAULT NULL --(DC2Type:uuid)
, title VARCHAR(255) NOT NULL, date DATE NOT NULL, passage VARCHAR(255) NOT NULL, refs CLOB DEFAULT NULL --(DC2Type:json)
, text CLOB DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_CFBDFA14D04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA145278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CFBDFA14A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO note (id, speaker_id, series_id, user_id, title, date, passage, refs, text) SELECT id, speaker_id, series_id, user_id, title, date, passage, refs, text FROM __temp__note');
$this->addSql('DROP TABLE __temp__note');
$this->addSql('CREATE INDEX IDX_CFBDFA14D04A0F27 ON note (speaker_id)');
$this->addSql('CREATE INDEX IDX_CFBDFA145278319C ON note (series_id)');
$this->addSql('CREATE INDEX IDX_CFBDFA14A76ED395 ON note (user_id)');
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240622233923 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD COLUMN meta_data CLOB DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__user AS SELECT id, email, roles, password, name FROM user');
$this->addSql('DROP TABLE user');
$this->addSql('CREATE TABLE user (id BLOB NOT NULL --(DC2Type:uuid)
, email VARCHAR(180) NOT NULL, roles CLOB NOT NULL --(DC2Type:json)
, password VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('INSERT INTO user (id, email, roles, password, name) SELECT id, email, roles, password, name FROM __temp__user');
$this->addSql('DROP TABLE __temp__user');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON user (email)');
}
}

View File

@ -18,7 +18,7 @@ body {
.ref-tab { .ref-tab {
width: 60px; width: 60px;
padding-top: 75px !important; padding-top: 55px !important;
} }
.ref-tab ul { .ref-tab ul {
@ -43,24 +43,12 @@ body {
height: 80px; height: 80px;
width: 100%; width: 100%;
text-align: center; text-align: center;
background-color: #f56a6a;
color: #fff !important;
border: none;
border-radius: 3px;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.8);
font-size: 14px; font-size: 14px;
margin-bottom: 3px; margin-bottom: 3px;
} }
.tab button:active {
background-color: #7a0016;
}
.activeRef {
background-color: #3e8e41 !important;
}
.ref { .ref {
width: 35%; width: 36%;
} }
.ref > div#ref { .ref > div#ref {
@ -76,7 +64,7 @@ body {
} }
#ref { #ref {
padding: 3px 3px 3px 10px; padding: 3px 3px 3px 3px;
} }
#passage { #passage {
@ -102,7 +90,7 @@ body {
} }
.notes { .notes {
width: 55%; width: 57%;
} }
textarea#notes { textarea#notes {
@ -114,10 +102,18 @@ textarea#notes {
#notePreview { #notePreview {
display: none; display: none;
overflow-x: scroll; overflow-x: scroll;
padding-left: 10px;
}
#notePreview ul,
#notePreview ol {
list-style-position: inside;
} }
#previewBtn.active, #previewBtn.active,
#show-hide-btn.active { #show-hide-btn.active,
.tab button.active,
#openRefBtn.active {
background-color: #f56a6a !important; background-color: #f56a6a !important;
color: white !important; color: white !important;
} }
@ -140,6 +136,8 @@ textarea#notes {
#note-list { #note-list {
display: none; display: none;
height: 100%;
overflow-y: scroll;
} }
#note-list ul { #note-list ul {
@ -205,7 +203,7 @@ div#refQuery #referenceSearch {
#fields-container input, #fields-container input,
#fields-container select { #fields-container select {
width: 19.5%; width: 32.5%;
display: inline-block; display: inline-block;
} }
@ -234,6 +232,65 @@ div#refQuery #referenceSearch {
font-size: 12pt; font-size: 12pt;
} }
#ref ol,
#ref ul {
list-style-position: inside;
}
#referenceBook { #referenceBook {
display: none; display: none;
}
.recording-link {
font-size: 8pt;
color: blue;
text-decoration: none;
}
.fas-trash-alt {
color: red;
cursor: pointer;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000;
opacity: 0.5;
z-index: 1000;
}
.modal-container {
position: absolute;
width: 300px;
/* adjust this to your desired modal width */
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
z-index: 1001;
}
.modal-header {
background-color: #f5f5f5;
padding: 10px;
border-bottom: 1px solid #ddd;
}
.modal-body {
padding: 20px;
}
.modal-footer {
background-color: #f5f5f5;
padding: 10px;
border-top: 1px solid #ddd;
}
.btn-secondary {
color: #337ab7;
}/*# sourceMappingURL=style.css.map */ }/*# sourceMappingURL=style.css.map */

View File

@ -1 +1 @@
{"version":3,"sources":["style.scss","style.css"],"names":[],"mappings":"AAAA,kCAAA;AACA;EACI,SAAA;ACCJ;;ADEA,6BAAA;AAEA;EACI,aAAA;EACA,mBAAA;EACA,eAAA;EACA,6BAAA;EACA,oBAAA;EACA,yBAAA;EACA,iBAAA;EACA,iCAAA;EACA,cAAA;ACAJ;;ADGA;EACI,WAAA;EACA,4BAAA;ACAJ;;ADGA;EACI,SAAA;EACA,UAAA;ACAJ;;ADGA;EACI,gBAAA;EACA,qBAAA;ACAJ;;ADGA;EACI,kBAAA;ACAJ;;ADGA,GAAA;AACA;EACI,aAAA;EACA,uBAAA;EACA,mBAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,yBAAA;EACA,sBAAA;EACA,YAAA;EACA,kBAAA;EACA,wCAAA;EACA,eAAA;EACA,kBAAA;ACAJ;ADEI;EACI,yBAAA;ACAR;;ADIA;EACI,oCAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;EACI,mBAAA;EACA,2BAAA;EACA,yBAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,uBAAA;EACA,kBAAA;EACA,wCAAA;ACDJ;;ADIA;EACI,yBAAA;ACDJ;;ADIA;EACI,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,cAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;EACI,WAAA;EACA,YAAA;EACA,eAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;ACDJ;;ADIA;;EAEI,oCAAA;EACA,uBAAA;ACDJ;;ADIA;EACI,oBAAA;EACA,mBAAA;EACA,UAAA;ACDJ;;ADIA;EACI,oBAAA;EACA,2BAAA;EACA,UAAA;ACDJ;;ADIA;EACI,iBAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,SAAA;EACA,UAAA;EACA,qBAAA;EACA,gBAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,oCAAA;EACA,YAAA;EACA,aAAA;ACDJ;;ADIA;EACI,YAAA;EACA,kBAAA;EACA,kBAAA;EACA,eAAA;EACA,gBAAA;EACA,WAAA;EACA,yBAAA;EACA,YAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,sBAAA;EACA,YAAA;EACA,aAAA;EACA,sBAAA;EACA,kBAAA;EACA,wCAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;ACDJ;;ADIA;EACI,UAAA;EACA,iBAAA;EACA,eAAA;EACA,iBAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;;EAEI,YAAA;EACA,qBAAA;ACDJ;;ADIA;EACI,2BAAA;EACA,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,qBAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ","file":"style.css"} {"version":3,"sources":["style.scss","style.css"],"names":[],"mappings":"AAAA,kCAAA;AACA;EACI,SAAA;ACCJ;;ADEA,6BAAA;AAEA;EACI,aAAA;EACA,mBAAA;EACA,eAAA;EACA,6BAAA;EACA,oBAAA;EACA,yBAAA;EACA,iBAAA;EACA,iCAAA;EACA,cAAA;ACAJ;;ADGA;EACI,WAAA;EACA,4BAAA;ACAJ;;ADGA;EACI,SAAA;EACA,UAAA;ACAJ;;ADGA;EACI,gBAAA;EACA,qBAAA;ACAJ;;ADGA;EACI,kBAAA;ACAJ;;ADGA,GAAA;AACA;EACI,aAAA;EACA,uBAAA;EACA,mBAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,eAAA;EACA,kBAAA;ACAJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;EACI,mBAAA;EACA,2BAAA;EACA,yBAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,uBAAA;EACA,kBAAA;EACA,wCAAA;ACDJ;;ADIA;EACI,wBAAA;ACDJ;;ADIA;EACI,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,cAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;EACI,WAAA;EACA,YAAA;EACA,eAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;EACA,kBAAA;ACDJ;;ADIA;;EAEI,2BAAA;ACDJ;;ADIA;;;;EAII,oCAAA;EACA,uBAAA;ACDJ;;ADIA;EACI,oBAAA;EACA,mBAAA;EACA,UAAA;ACDJ;;ADIA;EACI,oBAAA;EACA,2BAAA;EACA,UAAA;ACDJ;;ADIA;EACI,iBAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;EACA,kBAAA;ACDJ;;ADIA;EACI,SAAA;EACA,UAAA;EACA,qBAAA;EACA,gBAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,oCAAA;EACA,YAAA;EACA,aAAA;ACDJ;;ADIA;EACI,YAAA;EACA,kBAAA;EACA,kBAAA;EACA,eAAA;EACA,gBAAA;EACA,WAAA;EACA,yBAAA;EACA,YAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;ACDJ;;ADIA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,sBAAA;EACA,YAAA;EACA,aAAA;EACA,sBAAA;EACA,kBAAA;EACA,wCAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;ACDJ;;ADIA;EACI,UAAA;EACA,iBAAA;EACA,eAAA;EACA,iBAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;;EAEI,YAAA;EACA,qBAAA;ACDJ;;ADIA;EACI,2BAAA;EACA,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;EACI,qBAAA;ACDJ;;ADIA;EACI,eAAA;ACDJ;;ADIA;;EAEI,2BAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,cAAA;EACA,WAAA;EACA,qBAAA;ACDJ;;ADIA;EACI,UAAA;EACA,eAAA;ACDJ;;ADIA;EACI,eAAA;EACA,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,sBAAA;EACA,YAAA;EACA,aAAA;ACDJ;;ADIA;EACI,kBAAA;EACA,YAAA;EACA,4CAAA;EACA,cAAA;EACA,aAAA;EACA,sBAAA;EACA,sBAAA;EACA,uCAAA;EACA,aAAA;ACDJ;;ADIA;EACI,yBAAA;EACA,aAAA;EACA,6BAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,yBAAA;EACA,aAAA;EACA,0BAAA;ACDJ;;ADIA;EACI,cAAA;ACDJ","file":"style.css"}

View File

@ -1 +1 @@
body{margin:0}.inner{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;align-items:stretch;align-content:flex-start;max-width:1060px;margin:0 auto}.ref-tab{width:60px;padding-top:75px !important}.ref-tab ul{margin:0;padding:0}.ref-tab ul li{list-style:none;list-style-type:none}.tab{margin-bottom:3px}.tab button{display:flex;justify-content:center;align-items:center;height:80px;width:100%;text-align:center;background-color:#f56a6a;color:#fff !important;border:none;border-radius:3px;box-shadow:0 4px 5px rgba(0,0,0,.8);font-size:14px;margin-bottom:3px}.tab button:active{background-color:#7a0016}.activeRef{background-color:#3e8e41 !important}.ref{width:35%}.ref>div#ref{vertical-align:top;justify-content:flex-start;align-content:flex-start;overflow-y:scroll;width:100%;height:100%;border:#000 solid 1px;border-radius:3px;box-shadow:0 2px 5px rgba(0,0,0,.3)}#ref{padding:3px 3px 3px 10px}#passage{width:100px}#newSpeaker{display:none;width:110px}#newSeries{display:none;width:110px}#fields-container{display:none}#fields-container.show{display:block}.notes{width:55%}textarea#notes{width:100%;height:100%;font-size:14pt}#notePreview{display:none;overflow-x:scroll}#previewBtn.active,#show-hide-btn.active{background-color:#f56a6a !important;color:#fff !important}#note-header-left{display:inline-flex;flex-direction:row;width:25%}#note-header-right{display:inline-flex;flex-direction:row-reverse;width:74%}#note-header-left h2.dirty{color:#ff8c00}#note-list{display:none}#note-list ul{margin:0;padding:0;list-style-type:none;list-style:none}div#refQuery{display:none;position:absolute;z-index:100;background-color:rgba(0,0,0,.8);width:400px;height:200px}div#refQuery #referenceSearch{border:none;border-radius:5px;padding:10px 20px;font-size:16px;line-height:1.5;color:#333;background-color:#f4f4f4;width:150px;height:25px;cursor:pointer;display:none}#passage-popup{display:none;position:absolute;z-index:100;background-color:#fff;color:#000;padding:10px;border:1px solid #ccc;border-radius:5px;box-shadow:0 2px 5px rgba(0,0,0,.3);width:300px;height:300px;overflow-x:scroll}#save-check{opacity:0;text-align:right;font-size:20pt;margin-left:15px;color:green}#save-check.saving{color:orange}#save-check.error{color:red}#fields-container input,#fields-container select{width:19.5%;display:inline-block}#old-notes article p:first-child{margin-bottom:0 !important;font-size:10pt}#old-notes article a{font-size:12pt}#old-notes article p:last-child{font-size:12pt}.inner{padding-left:0}.ref h2{display:inline-block}#ref{font-size:12pt}#referenceBook{display:none}/*# sourceMappingURL=style.min.css.map */ body{margin:0}.inner{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;align-items:stretch;align-content:flex-start;max-width:1060px;margin:0 auto}.ref-tab{width:60px;padding-top:55px !important}.ref-tab ul{margin:0;padding:0}.ref-tab ul li{list-style:none;list-style-type:none}.tab{margin-bottom:3px}.tab button{display:flex;justify-content:center;align-items:center;height:80px;width:100%;text-align:center;font-size:14px;margin-bottom:3px}.ref{width:36%}.ref>div#ref{vertical-align:top;justify-content:flex-start;align-content:flex-start;overflow-y:scroll;width:100%;height:100%;border:#000 solid 1px;border-radius:3px;box-shadow:0 2px 5px rgba(0,0,0,.3)}#ref{padding:3px 3px 3px 3px}#passage{width:100px}#newSpeaker{display:none;width:110px}#newSeries{display:none;width:110px}#fields-container{display:none}#fields-container.show{display:block}.notes{width:57%}textarea#notes{width:100%;height:100%;font-size:14pt}#notePreview{display:none;overflow-x:scroll;padding-left:10px}#notePreview ul,#notePreview ol{list-style-position:inside}#previewBtn.active,#show-hide-btn.active,.tab button.active,#openRefBtn.active{background-color:#f56a6a !important;color:#fff !important}#note-header-left{display:inline-flex;flex-direction:row;width:25%}#note-header-right{display:inline-flex;flex-direction:row-reverse;width:74%}#note-header-left h2.dirty{color:#ff8c00}#note-list{display:none;height:100%;overflow-y:scroll}#note-list ul{margin:0;padding:0;list-style-type:none;list-style:none}div#refQuery{display:none;position:absolute;z-index:100;background-color:rgba(0,0,0,.8);width:400px;height:200px}div#refQuery #referenceSearch{border:none;border-radius:5px;padding:10px 20px;font-size:16px;line-height:1.5;color:#333;background-color:#f4f4f4;width:150px;height:25px;cursor:pointer;display:none}#passage-popup{display:none;position:absolute;z-index:100;background-color:#fff;color:#000;padding:10px;border:1px solid #ccc;border-radius:5px;box-shadow:0 2px 5px rgba(0,0,0,.3);width:300px;height:300px;overflow-x:scroll}#save-check{opacity:0;text-align:right;font-size:20pt;margin-left:15px;color:green}#save-check.saving{color:orange}#save-check.error{color:red}#fields-container input,#fields-container select{width:32.5%;display:inline-block}#old-notes article p:first-child{margin-bottom:0 !important;font-size:10pt}#old-notes article a{font-size:12pt}#old-notes article p:last-child{font-size:12pt}.inner{padding-left:0}.ref h2{display:inline-block}#ref{font-size:12pt}#ref ol,#ref ul{list-style-position:inside}#referenceBook{display:none}.recording-link{font-size:8pt;color:blue;text-decoration:none}.fas-trash-alt{color:red;cursor:pointer}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000;opacity:.5;z-index:1000}.modal-container{position:absolute;width:300px;margin:0 auto;padding:20px;border:1px solid #ddd;background-color:#fff;box-shadow:0 0 10px rgba(0,0,0,.2);z-index:1001}.modal-header{background-color:#f5f5f5;padding:10px;border-bottom:1px solid #ddd}.modal-body{padding:20px}.modal-footer{background-color:#f5f5f5;padding:10px;border-top:1px solid #ddd}.btn-secondary{color:#337ab7}/*# sourceMappingURL=style.min.css.map */

View File

@ -1 +1 @@
{"version":3,"sources":["style.scss"],"names":[],"mappings":"AACA,KACI,QAAA,CAKJ,OACI,YAAA,CACA,kBAAA,CACA,cAAA,CACA,4BAAA,CACA,mBAAA,CACA,wBAAA,CACA,gBAAA,CAEA,aAAA,CAGJ,SACI,UAAA,CACA,2BAAA,CAGJ,YACI,QAAA,CACA,SAAA,CAGJ,eACI,eAAA,CACA,oBAAA,CAGJ,KACI,iBAAA,CAIJ,YACI,YAAA,CACA,sBAAA,CACA,kBAAA,CACA,WAAA,CACA,UAAA,CACA,iBAAA,CACA,wBAAA,CACA,qBAAA,CACA,WAAA,CACA,iBAAA,CACA,mCAAA,CACA,cAAA,CACA,iBAAA,CAEA,mBACI,wBAAA,CAIR,WACI,mCAAA,CAGJ,KACI,SAAA,CAGJ,aACI,kBAAA,CACA,0BAAA,CACA,wBAAA,CACA,iBAAA,CACA,UAAA,CACA,WAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CAGJ,KACI,wBAAA,CAGJ,SACI,WAAA,CAGJ,YACI,YAAA,CACA,WAAA,CAGJ,WACI,YAAA,CACA,WAAA,CAGJ,kBACI,YAAA,CAGJ,uBACI,aAAA,CAGJ,OACI,SAAA,CAGJ,eACI,UAAA,CACA,WAAA,CACA,cAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CAGJ,yCAEI,mCAAA,CACA,qBAAA,CAGJ,kBACI,mBAAA,CACA,kBAAA,CACA,SAAA,CAGJ,mBACI,mBAAA,CACA,0BAAA,CACA,SAAA,CAGJ,2BACI,aAAA,CAGJ,WACI,YAAA,CAGJ,cACI,QAAA,CACA,SAAA,CACA,oBAAA,CACA,eAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,+BAAA,CACA,WAAA,CACA,YAAA,CAGJ,8BACI,WAAA,CACA,iBAAA,CACA,iBAAA,CACA,cAAA,CACA,eAAA,CACA,UAAA,CACA,wBAAA,CACA,WAAA,CACA,WAAA,CACA,cAAA,CACA,YAAA,CAGJ,eACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,qBAAA,CACA,UAAA,CACA,YAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CACA,WAAA,CACA,YAAA,CACA,iBAAA,CAGJ,YACI,SAAA,CACA,gBAAA,CACA,cAAA,CACA,gBAAA,CACA,WAAA,CAGJ,mBACI,YAAA,CAGJ,kBACI,SAAA,CAGJ,iDAEI,WAAA,CACA,oBAAA,CAGJ,iCACI,0BAAA,CACA,cAAA,CAGJ,qBACI,cAAA,CAGJ,gCACI,cAAA,CAGJ,OACI,cAAA,CAGJ,QACI,oBAAA,CAGJ,KACI,cAAA,CAGJ,eACI,YAAA","file":"style.min.css"} {"version":3,"sources":["style.scss"],"names":[],"mappings":"AACA,KACI,QAAA,CAKJ,OACI,YAAA,CACA,kBAAA,CACA,cAAA,CACA,4BAAA,CACA,mBAAA,CACA,wBAAA,CACA,gBAAA,CAEA,aAAA,CAGJ,SACI,UAAA,CACA,2BAAA,CAGJ,YACI,QAAA,CACA,SAAA,CAGJ,eACI,eAAA,CACA,oBAAA,CAGJ,KACI,iBAAA,CAIJ,YACI,YAAA,CACA,sBAAA,CACA,kBAAA,CACA,WAAA,CACA,UAAA,CACA,iBAAA,CACA,cAAA,CACA,iBAAA,CAIJ,KACI,SAAA,CAGJ,aACI,kBAAA,CACA,0BAAA,CACA,wBAAA,CACA,iBAAA,CACA,UAAA,CACA,WAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CAGJ,KACI,uBAAA,CAGJ,SACI,WAAA,CAGJ,YACI,YAAA,CACA,WAAA,CAGJ,WACI,YAAA,CACA,WAAA,CAGJ,kBACI,YAAA,CAGJ,uBACI,aAAA,CAGJ,OACI,SAAA,CAGJ,eACI,UAAA,CACA,WAAA,CACA,cAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CACA,iBAAA,CAGJ,gCAEI,0BAAA,CAGJ,+EAII,mCAAA,CACA,qBAAA,CAGJ,kBACI,mBAAA,CACA,kBAAA,CACA,SAAA,CAGJ,mBACI,mBAAA,CACA,0BAAA,CACA,SAAA,CAGJ,2BACI,aAAA,CAGJ,WACI,YAAA,CACA,WAAA,CACA,iBAAA,CAGJ,cACI,QAAA,CACA,SAAA,CACA,oBAAA,CACA,eAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,+BAAA,CACA,WAAA,CACA,YAAA,CAGJ,8BACI,WAAA,CACA,iBAAA,CACA,iBAAA,CACA,cAAA,CACA,eAAA,CACA,UAAA,CACA,wBAAA,CACA,WAAA,CACA,WAAA,CACA,cAAA,CACA,YAAA,CAGJ,eACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,qBAAA,CACA,UAAA,CACA,YAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CACA,WAAA,CACA,YAAA,CACA,iBAAA,CAGJ,YACI,SAAA,CACA,gBAAA,CACA,cAAA,CACA,gBAAA,CACA,WAAA,CAGJ,mBACI,YAAA,CAGJ,kBACI,SAAA,CAGJ,iDAEI,WAAA,CACA,oBAAA,CAGJ,iCACI,0BAAA,CACA,cAAA,CAGJ,qBACI,cAAA,CAGJ,gCACI,cAAA,CAGJ,OACI,cAAA,CAGJ,QACI,oBAAA,CAGJ,KACI,cAAA,CAGJ,gBAEI,0BAAA,CAGJ,eACI,YAAA,CAGJ,gBACI,aAAA,CACA,UAAA,CACA,oBAAA,CAGJ,eACI,SAAA,CACA,cAAA,CAGJ,gBACI,cAAA,CACA,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,qBAAA,CACA,UAAA,CACA,YAAA,CAGJ,iBACI,iBAAA,CACA,WAAA,CAEA,aAAA,CACA,YAAA,CACA,qBAAA,CACA,qBAAA,CACA,kCAAA,CACA,YAAA,CAGJ,cACI,wBAAA,CACA,YAAA,CACA,4BAAA,CAGJ,YACI,YAAA,CAGJ,cACI,wBAAA,CACA,YAAA,CACA,yBAAA,CAGJ,eACI,aAAA","file":"style.min.css"}

View File

@ -19,7 +19,7 @@ body {
.ref-tab { .ref-tab {
width: 60px; width: 60px;
padding-top: 75px !important; padding-top: 55px !important;
} }
.ref-tab ul { .ref-tab ul {
@ -44,25 +44,13 @@ body {
height: 80px; height: 80px;
width: 100%; width: 100%;
text-align: center; text-align: center;
background-color: #f56a6a;
color: #fff !important;
border: none;
border-radius: 3px;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.8);
font-size: 14px; font-size: 14px;
margin-bottom: 3px; margin-bottom: 3px;
&:active {
background-color: #7a0016;
}
} }
.activeRef {
background-color: #3e8e41 !important;
}
.ref { .ref {
width: 35%; width: 36%;
} }
.ref>div#ref { .ref>div#ref {
@ -78,7 +66,7 @@ body {
} }
#ref { #ref {
padding: 3px 3px 3px 10px; padding: 3px 3px 3px 3px;
} }
#passage { #passage {
@ -104,7 +92,7 @@ body {
} }
.notes { .notes {
width: 55% width: 57%
} }
textarea#notes { textarea#notes {
@ -116,10 +104,18 @@ textarea#notes {
#notePreview { #notePreview {
display: none; display: none;
overflow-x: scroll; overflow-x: scroll;
padding-left: 10px;
}
#notePreview ul,
#notePreview ol {
list-style-position: inside;
} }
#previewBtn.active, #previewBtn.active,
#show-hide-btn.active { #show-hide-btn.active,
.tab button.active,
#openRefBtn.active {
background-color: #f56a6a !important; background-color: #f56a6a !important;
color: white !important; color: white !important;
} }
@ -142,6 +138,8 @@ textarea#notes {
#note-list { #note-list {
display: none; display: none;
height: 100%;
overflow-y: scroll;
} }
#note-list ul { #note-list ul {
@ -207,7 +205,7 @@ div#refQuery #referenceSearch {
#fields-container input, #fields-container input,
#fields-container select { #fields-container select {
width: 19.5%; width: 32.5%;
display: inline-block; display: inline-block;
} }
@ -236,6 +234,65 @@ div#refQuery #referenceSearch {
font-size: 12pt; font-size: 12pt;
} }
#ref ol,
#ref ul {
list-style-position: inside;
}
#referenceBook { #referenceBook {
display: none; display: none;
}
.recording-link {
font-size: 8pt;
color: blue;
text-decoration: none;
}
.fas-trash-alt {
color: red;
cursor: pointer;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000;
opacity: 0.5;
z-index: 1000;
}
.modal-container {
position: absolute;
width: 300px;
/* adjust this to your desired modal width */
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
z-index: 1001;
}
.modal-header {
background-color: #f5f5f5;
padding: 10px;
border-bottom: 1px solid #ddd;
}
.modal-body {
padding: 20px;
}
.modal-footer {
background-color: #f5f5f5;
padding: 10px;
border-top: 1px solid #ddd;
}
.btn-secondary {
color: #337ab7;
} }

View File

@ -1354,5 +1354,29 @@
"wlc": [ "wlc": [
1, 1,
196 196
],
"lbc": [
1,
32
],
"39a": [
1,
39
],
"1hc": [
1,
10
],
"2hc": [
1,
30
],
"sd": [
1,
32
],
"agc": [
1,
28
] ]
} }

View File

@ -4,39 +4,64 @@ var references = {};
var tabs = []; var tabs = [];
let saved = false; let saved = false;
let textDirty = false; let textDirty = false;
let saveTimeout = 10000;
var to = null; var to = null;
let controller; let controller;
var BOOKS = {}; var BOOKS = {};
fetch('/js/data.json') $(function () {
.then((res) => { setHeight();
if (!res.ok) { setBooks();
throw new Error('HTTP Error: Status: ${res.status}'); setEventListeners();
$('#note-table').DataTable({
paging: false,
ajax: {
url: '/index.php/get-notes',
type: 'POST'
},
columns: [
{ data: 'link' },
{ data: 'speaker.name' },
{ data: 'passage' },
{
data: 'date.date',
render: DataTable.render.date("L")
},
]
});
});
function setBooks() {
fetch('/js/data.json')
.then((res) => {
if (!res.ok) {
throw new Error('HTTP Error: Status: ${res.status}');
}
return res.json();
})
.then((data) => {
BOOKS = data;
})
.catch((error) => {
console.log(error);
})
}
function setEventListeners() {
document.addEventListener('keyup', function (event) {
if (event.key == "F3") {
openRef(false);
} }
return res.json(); });
})
.then((data) => {
BOOKS = data;
})
.catch((error) => {
console.log(error);
})
document.addEventListener('keyup', function (event) { document.querySelector('#notes').addEventListener('keyup', function (event) {
if (event.key == "F3") { let key = event.keyCode;
openRef(false);
}
});
document.querySelector('#notes').addEventListener('keyup', function (event) { if (key >= 48 && key <= 90 || key >= 96 && key <= 111 || key >= 186 && key <= 222) {
let key = event.keyCode; textDirty = true;
document.querySelector('#note-header-left h2').classList.add('dirty');
if (key >= 48 && key <= 90 || key >= 96 && key <= 111 || key >= 186 && key <= 222) { }
textDirty = true; });
document.querySelector('#note-header-left h2').classList.add('dirty'); }
}
});
function setHeight() { function setHeight() {
md = new markdownit({ md = new markdownit({
@ -78,7 +103,7 @@ function setHeight() {
}); });
} }
if (!to) { if (!to) {
to = setTimeout(saveNote, saveTimeout); to = setTimeout(saveNote, saveInterval);
} }
} }
@ -133,7 +158,8 @@ function newNote() {
document.querySelector('#series').value = 0; document.querySelector('#series').value = 0;
document.querySelector('#template').value = 0; document.querySelector('#template').value = 0;
document.querySelector('#passage').value = ''; document.querySelector('#passage').value = '';
document.querySelector('#noteId').value = uuidv4(); document.querySelector('#recording').value = '';
document.querySelector('#noteId').value = '';
document.querySelector('#ref-list').innerHTML = ''; document.querySelector('#ref-list').innerHTML = '';
document.querySelector('#ref').innerHTML = ''; document.querySelector('#ref').innerHTML = '';
@ -153,11 +179,12 @@ function saveNote(event) {
if (!textDirty || !validateNote()) { if (!textDirty || !validateNote()) {
clearTimeout(to); clearTimeout(to);
to = setTimeout(saveNote, saveTimeout); to = setTimeout(saveNote, saveInterval);
return; return;
} }
let saveCheck = document.querySelector('#save-check'); let saveCheck = document.querySelector('#save-check');
var noteText = document.querySelector('#notes').value;
startSave(); startSave();
@ -169,6 +196,7 @@ function saveNote(event) {
series: document.querySelector('#series').value, series: document.querySelector('#series').value,
passage: document.querySelector('#passage').value, passage: document.querySelector('#passage').value,
note: document.querySelector('#notes').value, note: document.querySelector('#notes').value,
recording: document.querySelector('#recording').value,
refs: references refs: references
}; };
$.ajax({ $.ajax({
@ -177,33 +205,41 @@ function saveNote(event) {
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify(note), data: JSON.stringify(note),
dataType: 'json', dataType: 'json',
timeout: 5000 timeout: saveTimeout
}) })
.done(function (data) { .done(function (data) {
if (data.msg == 'saved' && !saved) { if (data.msg == 'saved' && !saved) {
saveCheck.classList.remove('saving'); saveFailureCount = SAVE_FAILURE_LIMIT;
saveCheck.classList.remove('saving', 'error', 'fa-times-circle', 'fa-save');
showSave(); showSave();
saved = true; if (noteText == document.querySelector('#notes').value) {
textDirty = false; saved = true;
document.querySelector('#note-header-left h2').classList.remove('dirty'); textDirty = false;
document.querySelector('#note-header-left h2').classList.remove('dirty');
}
if (data.new) { if (data.new) {
document.querySelector('#noteId').value = data.id; document.querySelector('#noteId').value = data.id;
} }
} }
}) })
.fail(function (data) { .fail(function (xhr, status, error) {
saveCheck.classList.remove('saving'); saveFailureCount--;
saveCheck.classList.add('error'); saveCheck.classList.remove('saving', 'fa-save');
console.error(data); saveCheck.classList.add('fa-times-circle', 'error');
console.error(error);
}) })
.always(function (xhr, status) { .always(function (xhr, status) {
if (status == 'timeout') { if (status == 'timeout') {
saveCheck.classList.remove('saving'); saveCheck.classList.remove('saving', 'fa-save');
saveCheck.classList.add('error'); saveCheck.classList.add('error', 'fa-times-circle');
} }
clearTimeout(to); clearTimeout(to);
to = setTimeout(saveNote, saveTimeout); if (saveFailureCount > 0) {
to = setTimeout(saveNote, saveInterval);
} else {
saveFailureCount = SAVE_FAILURE_LIMIT;
}
}); });
} }
@ -231,7 +267,8 @@ function isUuidValid(uuid) {
} }
function startSave() { function startSave() {
document.querySelector('#save-check').classList.add('saving'); document.querySelector('#save-check').classList.remove('error', 'fa-times-circle', 'fa-save');
document.querySelector('#save-check').classList.add('saving', 'fa-save');
document.querySelector('#save-check').style.opacity = 1; document.querySelector('#save-check').style.opacity = 1;
} }
@ -245,6 +282,7 @@ function showSave() {
if (saved) { return; } if (saved) { return; }
var checkmark = document.getElementById("save-check"); var checkmark = document.getElementById("save-check");
checkmark.classList.add('fa-save');
// Schedule the animation to run every 1 second (which is equivalent to a 1-second delay between each iteration) // Schedule the animation to run every 1 second (which is equivalent to a 1-second delay between each iteration)
var si = setInterval(function () { var si = setInterval(function () {
@ -264,31 +302,37 @@ function showSave() {
/** /**
* Function to discard the note by clearing all input fields and closing the menu. * Function to discard the note by clearing all input fields and closing the menu.
*/ */
function discardNote() { function deleteNote(noteId, link) {
document.querySelector('#noteTitle').value = ''; document.querySelector('#noteTitle').value = '';
document.querySelector('#speaker').value = 0; document.querySelector('#speaker').value = 0;
document.querySelector('#series').value = 0; document.querySelector('#series').value = 0;
document.querySelector('#template').value = 0; document.querySelector('#template').value = 0;
document.querySelector('#passage').value = ''; document.querySelector('#passage').value = '';
document.querySelector('#notes').value = ''; document.querySelector('#notes').value = '';
document.querySelector('#recording').value = '';
document.querySelector('#noteDate').value = '';
document.querySelector('#noteId').value = '';
fetch('/index.php/discard-note', { var row = link.parentElement.parentElement;
fetch('/index.php/delete-note', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
'id': document.querySelector('#noteId').value 'id': noteId
}) })
.then(response => response.json()) })
.then(data => { .then(response => response.json())
if (data.msg == 'deleted') { .then(data => {
alert('Note deleted.'); if (data.msg != 'deleted') {
} return;
}) }
});
openRef(); alert('Note deleted.');
row.remove();
});
} }
function newSpeaker() { function newSpeaker() {
@ -368,6 +412,8 @@ function saveSeries(event) {
} }
function openRef(closeSidebar = true) { function openRef(closeSidebar = true) {
document.querySelector('#openRefBtn').classList.add('active');
refQuery = document.querySelector('#refQuery'); refQuery = document.querySelector('#refQuery');
refQuery.style.display = 'block'; refQuery.style.display = 'block';
@ -389,6 +435,7 @@ function closeRef() {
document.querySelector('#verse-range').innerText = ''; document.querySelector('#verse-range').innerText = '';
document.querySelector('#refQuery').style.display = 'none'; document.querySelector('#refQuery').style.display = 'none';
document.querySelector('#openRefBtn').classList.remove('active');
} }
function queryRef(type = null, book = null, input = null) { function queryRef(type = null, book = null, input = null) {
@ -438,10 +485,11 @@ function queryRef(type = null, book = null, input = null) {
function makeButton(title) { function makeButton(title) {
var btn = document.createElement('button'); var btn = document.createElement('button');
btn.innerText = title; btn.innerText = title;
btn.class = 'button';
btn.addEventListener('click', function () { btn.addEventListener('click', function () {
removeActiveRef(); removeActiveRef();
document.querySelector('#ref').innerHTML = md.render(references[title]); document.querySelector('#ref').innerHTML = md.render(references[title]);
this.classList.add('activeRef'); this.classList.add('active');
findRefLinks(); findRefLinks();
}); });
@ -456,16 +504,16 @@ function makeButton(title) {
}); });
removeActiveRef(); removeActiveRef();
btn.classList.add('activeRef'); btn.classList.add('active');
return btn; return btn;
} }
function removeActiveRef() { function removeActiveRef() {
tabs = document.querySelectorAll('.activeRef'); tabs = document.querySelectorAll('.active');
for (var t in tabs) { for (var t in tabs) {
if (isFinite(parseInt(t))) { if (isFinite(parseInt(t))) {
tabs[t].classList.remove('activeRef'); tabs[t].classList.remove('active');
} }
} }
} }
@ -573,6 +621,30 @@ function retrieveBooks() {
newBook.text = BOOKS.cd[x]; newBook.text = BOOKS.cd[x];
bookList.appendChild(newBook); bookList.appendChild(newBook);
} }
} else if (selectedType == 'note') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
fetch('/index.php/retrieve-reference', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'type': 'note'
})
})
.then(response => response.json())
.then(results => {
for (var x in results) {
var newBook = document.createElement("option");
newBook.value = results[x].id;
newBook.text = results[x].title;
bookList.appendChild(newBook);
}
});
} else { } else {
var min = BOOKS[selectedType][0]; var min = BOOKS[selectedType][0];
var max = BOOKS[selectedType][1]; var max = BOOKS[selectedType][1];
@ -622,15 +694,42 @@ function filterVerse() {
verseRange.innerText = 'Verse: ' + verse; verseRange.innerText = 'Verse: ' + verse;
} }
function retrieveReferenceType(el) {
fetch('/index.php/reference/' + el.value, {
method: 'GET',
header: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(results => {
document.querySelector('#referenceSeries').innerHTML = '';
var none = document.createElement('option');
none.value = '';
none.text = '-- Select --';
document.querySelector('#referenceSeries').appendChild(none);
for (var x in results) {
var newSeries = document.createElement('option');
newSeries.value = results[x].id;
newSeries.text = results[x].label;
document.querySelector('#referenceSeries').appendChild(newSeries);
}
})
}
function retrieveReference(el) { function retrieveReference(el) {
if (el.value == 'new') {
document.querySelector('#refName').style.display = 'inline-block';
return;
}
fetch('/index.php/get-reference', { fetch('/index.php/get-reference', {
method: "POST", method: "POST",
header: { header: {
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
body: JSON.stringify({ body: JSON.stringify({
file: el.value, id: el.value
type: el.options[el.selectedIndex].getAttribute('type')
}) })
}) })
.then(response => response.json()) .then(response => response.json())

1
public/js/script.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -2233,7 +2233,6 @@ a.image:hover img {
ol { ol {
list-style: decimal; list-style: decimal;
margin: 0 0 2em 0; margin: 0 0 2em 0;
padding-left: 1.5em;
} }
ol li { ol li {
@ -2243,7 +2242,6 @@ ol li {
ul { ul {
list-style: disc; list-style: disc;
margin: 0 0 2em 0; margin: 0 0 2em 0;
padding-left: 1em;
} }
ul.alt { ul.alt {
@ -3088,13 +3086,13 @@ button:disabled,
} }
#main>.inner { #main>.inner {
padding: 0 0.5em 0.1em 0.5em; padding: 0 0.25em 0.1em 0.25em;
margin: 0 auto; margin: 0 auto;
max-width: 110em; max-width: 110em;
} }
#main>.inner>section { #main>.inner>section {
padding: 0.5em 0 0.5em 0; padding: 0.25em 0 0.25em 0;
border-top: solid 2px rgba(210, 215, 217, 0.75); border-top: solid 2px rgba(210, 215, 217, 0.75);
} }
@ -3104,13 +3102,13 @@ button:disabled,
@media screen and (max-width: 1680px) { @media screen and (max-width: 1680px) {
#main>.inner { #main>.inner {
padding: 0 0 0 2em; padding: 0 0 0 0;
} }
} }
@media screen and (max-width: 1280px) { @media screen and (max-width: 1280px) {
#main>.inner { #main>.inner {
padding: 0 0 0 2em; padding: 0 0 0 0;
} }
} }
@ -3229,9 +3227,9 @@ button:disabled,
-webkit-tap-highlight-color: rgba(255, 255, 255, 0); -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
border: 0; border: 0;
display: block; display: block;
height: 7.5em; height: 4.5em;
left: 26em; left: 26em;
line-height: 7.5em; line-height: 4.5em;
outline: 0; outline: 0;
overflow: hidden; overflow: hidden;
position: absolute; position: absolute;
@ -3289,11 +3287,13 @@ button:disabled,
} }
#sidebar .toggle { #sidebar .toggle {
height: 6.25em; height: 4.5em;
left: 24em; left: 24em;
line-height: 6.25em; line-height: 4.5em;
text-indent: 5em; text-indent: 5em;
width: 5em; width: 5em;
background-color: #fff;
margin-left: 1em;
} }
#sidebar .toggle:before { #sidebar .toggle:before {
@ -3338,7 +3338,7 @@ button:disabled,
#sidebar .toggle { #sidebar .toggle {
text-indent: 6em; text-indent: 6em;
width: 6em; width: 4.5em;
} }
#sidebar .toggle:before { #sidebar .toggle:before {

View File

@ -4,6 +4,7 @@ namespace App\Controller;
use DateTime; use DateTime;
use Parsedown;
use App\Entity\Reference; use App\Entity\Reference;
use App\Entity\Template; use App\Entity\Template;
use App\Entity\User; use App\Entity\User;
@ -11,10 +12,14 @@ use App\Entity\Bible;
use App\Entity\Speaker; use App\Entity\Speaker;
use App\Entity\Series; use App\Entity\Series;
use App\Entity\Note; use App\Entity\Note;
use App\Entity\NoteShares;
use App\Utils\Utils;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
class AjaxController extends AbstractController class AjaxController extends AbstractController
@ -166,6 +171,7 @@ class AjaxController extends AbstractController
} }
ReferenceController::$emi = $emi; ReferenceController::$emi = $emi;
$user = $this->getUser();
$ret = match(strtolower($data->type)) { $ret = match(strtolower($data->type)) {
'bible' => ReferenceController::retrieveBible("{$data->book} {$search}"), 'bible' => ReferenceController::retrieveBible("{$data->book} {$search}"),
@ -175,7 +181,14 @@ class AjaxController extends AbstractController
'wcf' => ReferenceController::retrieveWCF($ref), 'wcf' => ReferenceController::retrieveWCF($ref),
'wsc' => ReferenceController::retrieveWSC($ref), 'wsc' => ReferenceController::retrieveWSC($ref),
'wlc' => ReferenceController::retrieveWLC($ref), 'wlc' => ReferenceController::retrieveWLC($ref),
'creed' => ReferenceController::retrieveCreed($data->book) 'lbc' => ReferenceController::retrieveLBC($ref),
'creed' => ReferenceController::retrieveCreed($data->book),
'39a' => ReferenceController::retrieve39a($ref),
'1hc' => ReferenceController::retrieve1HC($ref),
'2hc' => ReferenceController::retrieve2HC($ref),
'sd' => ReferenceController::retrieveSD($ref),
'agc' => ReferenceController::retrieveAGC($ref),
'note' => ReferenceController::retrieveNote($user)
}; };
if (!is_a($ret, Reference::class)) { if (!is_a($ret, Reference::class)) {
@ -195,19 +208,12 @@ class AjaxController extends AbstractController
{ {
$res = new Response(); $res = new Response();
$data = json_decode($req->getContent()); $data = json_decode($req->getContent());
$ret = match ($data->type) { $ref = $emi->getRepository(Reference::class)->find($data->id);
'creed' => '/Creeds/',
'bc' => '/Belgic/',
'hc' => '/Heidelberg/',
'cd' => '/Dort/',
'wcf' => '/Westminster/Confessions/',
'wsc' => '/Westminster/Shorter Catechism/',
'wlc' => '/Westminster/Larger Catechism/'
};
$fc = file_get_contents(dirname(dirname(__DIR__))."/references{$ret}{$data->file}"); if (!is_a($ref, Reference::class)) {
$ref = new Reference();
$res->setContent(json_encode(['text' => $fc])); }
$res->setContent(json_encode(['text' => $ref->getContent()]));
return $res; return $res;
} }
@ -224,7 +230,13 @@ class AjaxController extends AbstractController
'cd' => 'Dort', 'cd' => 'Dort',
'wcf' => 'Westminster/Confessions', 'wcf' => 'Westminster/Confessions',
'wsc' => 'Westminster/Shorter Catechism', 'wsc' => 'Westminster/Shorter Catechism',
'wlc' => 'Westminster/Larger Catechism' 'wlc' => 'Westminster/Larger Catechism',
'lbc' => 'London',
'39a' => '39 Articles',
'1hc' => '1 Helvetic Catechism',
'2hc' => '2 Helvetic Catechism',
'sd' => 'Savor Declaration',
'agc' => 'Augsburg Confession'
}; };
$ret = file_put_contents(dirname(dirname(__DIR__))."/references/{$path}/{$data->file}", $data->text); $ret = file_put_contents(dirname(dirname(__DIR__))."/references/{$path}/{$data->file}", $data->text);
@ -251,6 +263,18 @@ class AjaxController extends AbstractController
return $res; return $res;
} }
#[Route('/get-notes', name: 'app_get_notes')]
public function getNotes(EntityManagerInterface $emi): Response
{
/** @var User $user */
$user = $this->getUser();
$notes = $emi->getRepository(Note::class)->reverseNoteSort($user);
$res = new Response();
$res->setContent(json_encode(['data'=> $notes]));
return $res;
}
#[Route('/get-note', name: 'app_get_note')] #[Route('/get-note', name: 'app_get_note')]
public function getNote(Request $req, EntityManagerInterface $emi): Response public function getNote(Request $req, EntityManagerInterface $emi): Response
{ {
@ -274,6 +298,10 @@ class AjaxController extends AbstractController
if (is_array($note) && count($note) > 0) { if (is_array($note) && count($note) > 0) {
/** @var Note $note */ /** @var Note $note */
$note = $note[0]; $note = $note[0];
} else {
$note = new Note();
$newNote = true;
$note->setUser($this->getUser());
} }
} else { } else {
$note = new Note(); $note = new Note();
@ -293,6 +321,7 @@ class AjaxController extends AbstractController
->setSpeaker($speaker) ->setSpeaker($speaker)
->setText($data->note) ->setText($data->note)
->setPassage($data->passage) ->setPassage($data->passage)
->setRecording($data->recording)
->setRefs($refs); ->setRefs($refs);
$emi->persist($note); $emi->persist($note);
@ -308,7 +337,7 @@ class AjaxController extends AbstractController
return $res; return $res;
} }
#[Route('/discard-note', name: 'app_discard_note', methods: ['POST'])] #[Route('/delete-note', name: 'app_discard_note', methods: ['POST'])]
public function discardNote(Request $req, EntityManagerInterface $emi): Response public function discardNote(Request $req, EntityManagerInterface $emi): Response
{ {
$data = json_decode($req->getContent()); $data = json_decode($req->getContent());
@ -323,6 +352,61 @@ class AjaxController extends AbstractController
return $res; return $res;
} }
#[Route('/share-note', name: 'app_share_note', methods: ['POST'])]
public function shareNote(Request $req, EntityManagerInterface $emi, MailerInterface $mailer): Response
{
$data = json_decode($req->getContent());
$note = $emi->getRepository(Note::class)->find($data->id);
/** @var User $user */
$user = $this->getUser();
$shared = $emi->getRepository(User::class)->findBy(['email' => $data->email]);
$email = $data->email;
$isRegistered = false;
if (!$note) {
$res = new Response();
$res->setContent(json_encode([
'msg' => 'Note Not Found'
]));
}
if (is_array($shared) && count($shared) > 0) {
$ns = new NoteShares();
$ns->setNote($note)
->setOwner($user)
->setShare($shared[0]);
$emi->persist($ns);
$emi->flush();
$email = $shared[0]->getEmail();
$isRegistered = true;
}
$Parsedown = new Parsedown();
$util = new Utils();
$util->sendEmail(
$mailer,
new Address('ryan@rkprather.com', 'Sermon Notes'),
new Address($email),
'Note Shared',
$this->renderView('emails/note-shared.html.twig', [
'note' => $note,
'owner' => $user,
'isRegistered' => $isRegistered,
'formattedText' => $Parsedown->text($note->getText()),
'domain' => $_ENV['DOMAIN'],
])
);
$res = new Response();
$res->setContent(json_encode([
'msg' => 'shared'
]));
return $res;
}
#[Route('/get-passage/{passage}', name: 'app_get_passage')] #[Route('/get-passage/{passage}', name: 'app_get_passage')]
public function getPassage($passage, EntityManagerInterface $emi): Response public function getPassage($passage, EntityManagerInterface $emi): Response
{ {
@ -363,4 +447,52 @@ class AjaxController extends AbstractController
return $res; return $res;
} }
#[Route('/save-settings', name: 'app_save_settings', methods: ['POST'])]
public function saveSettings(Request $req, EntityManagerInterface $emi): Response
{
$data = json_decode($req->getContent());
/** @var User $user */
$user = $this->getUser();
if (!$user) {
return new Response(json_encode([
'msg' => 'No User'
]));
}
if (!$data->saveInterval) {
$data->saveInterval = 15;
}
if (!$data->saveReferences) {
$data->saveReferences = true;
}
if (!$data->noteTextSize) {
$data->noteTextSize = 12;
}
if (!$data->trackSaveSize) {
$data->trackSaveSize = false;
}
$meta = $user->getMetaData();
$meta['saveInterval'] = $data->saveInterval;
$meta['saveReferences'] = $data->saveReferences;
$meta['noteTextSize'] = $data->noteTextSize;
$meta['trackSaveSize'] = $data->trackSaveSize;
$meta['saveTimeout'] = $data->saveTimeout;
$meta['save-failure-count'] = $data->saveFailureCount;
$user->setMetaData($meta);
$emi->persist($user);
$emi->flush();
$res = new Response();
$res->setContent(json_encode([
'msg' => 'Settings Saved'
]));
return $res;
}
} }

View File

@ -3,7 +3,6 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Note; use App\Entity\Note;
use App\Entity\Reference;
use App\Entity\User; use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -11,13 +10,15 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser; use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Uid\Uuid;
class DefaultController extends AbstractController class DefaultController extends AbstractController
{ {
#[Route('/', name: 'app_index')] #[Route('/', name: 'app_index')]
public function index(): Response public function index(): Response
{ {
if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirect('/index.php/home');
}
return $this->render('default/index.html.twig'); return $this->render('default/index.html.twig');
} }
@ -27,11 +28,47 @@ class DefaultController extends AbstractController
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
$last4Notes = $emi->getRepository(Note::class)->getLast4Notes($user); $last4Notes = $emi->getRepository(Note::class)->getLast4Notes($user);
$openNotes = $emi->getRepository(Note::class)->reverseNoteSort($user); $openNotes = $emi->getRepository(Note::class)->reverseNoteSort($user);
$meta = $user->getMetaData();
return $this->render('default/home.html.twig', [ return $this->render('default/home.html.twig', [
'last4Notes' => $last4Notes, 'last4Notes' => $last4Notes,
'reverseNoteSort' => $openNotes, 'reverseNoteSort' => $openNotes,
'isAdmin' => $this->isGranted('ROLE_ADMIN'), 'isAdmin' => $this->isGranted('ROLE_ADMIN'),
'meta' => $meta,
]);
}
#[Route('/cheat-sheet', name: 'app_cheat_sheet')]
public function cheatSheet(): Response
{
return $this->render('default/cheat-sheet.html.twig');
}
#[Route('/profile', name: 'app_profile')]
public function profile(): Response
{
/** @var User $user */
$user = $this->getUser();
if (!$user) {
return $this->redirectToRoute('app_login');
}
$meta = $user->getMetaData();
if (!$meta) {
$meta = [
'saveInterval' => 15,
'saveReferences' => 'checked',
'noteTextSize' => 12,
'trackSaveSize' => null,
'saveFailureCount' => 3,
'saveTimeout' => 5,
];
} else {
$meta['saveReferences'] = $meta['saveReferences'] ? 'checked' : null;
$meta['trackSaveSize'] = $meta['trackSaveSize'] ? 'checked' : null;
}
return $this->render('default/profile.html.twig', [
'meta' => $meta,
]); ]);
} }
@ -40,23 +77,7 @@ class DefaultController extends AbstractController
{ {
$this->denyAccessUnlessGranted('ROLE_ADMIN'); $this->denyAccessUnlessGranted('ROLE_ADMIN');
$creeds = $emi->getRepository(Reference::class)->findByType('creed'); return $this->render('editors/reference-editor.html.twig');
$belgic = $emi->getRepository(Reference::class)->findByType('belgic');
$heidelberg = $emi->getRepository(Reference::class)->findByType('heidelberg');
$dort = $emi->getRepository(Reference::class)->findByType('dort');
$wcf = $emi->getRepository(Reference::class)->findByType('wcf');
$wsc = $emi->getRepository(Reference::class)->findByType('wsc');
$wlc = $emi->getRepository(Reference::class)->findByType('wlc');
return $this->render('editors/reference-editor.html.twig', [
'creeds' => $creeds,
'belgic' => $belgic,
'heidelberg' => $heidelberg,
'dort' => $dort,
'wcf' => $wcf,
'wsc' => $wsc,
'wlc' => $wlc
]);
} }
#[Route('/template-editor', name: 'app_template_editor')] #[Route('/template-editor', name: 'app_template_editor')]

View File

@ -3,7 +3,9 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Bible; use App\Entity\Bible;
use App\Entity\Note;
use App\Entity\Reference; use App\Entity\Reference;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -144,6 +146,9 @@ class ReferenceController extends AbstractController
public static function retrieveWSC($ref): Reference public static function retrieveWSC($ref): Reference
{ {
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0]; return $r[0];
} }
@ -157,6 +162,9 @@ class ReferenceController extends AbstractController
public static function retrieveWLC($ref): Reference public static function retrieveWLC($ref): Reference
{ {
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0]; return $r[0];
} }
@ -170,6 +178,79 @@ class ReferenceController extends AbstractController
public static function retrieveWCF($ref): Reference public static function retrieveWCF($ref): Reference
{ {
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0]; return $r[0];
} }
public static function retrieveLBC($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => 'lbc', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieveAGC($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => 'agc', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieve39a($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => '39a', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieve1HC($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => '1hc', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieve2HC($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => '2hc', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieveSD($ref): Reference
{
$r = self::$emi->getRepository(Reference::class)->findBy(['type' => 'sd', 'ndx' => $ref->getNdx()]);
if (!$r) {
return new Reference();
}
return $r[0];
}
public static function retrieveNote(?User $user): array
{
$notes = self::$emi->getRepository(Note::class)->findBy(['user' => $user], ['date' => 'DESC']);
return $notes;
}
#[Route('/reference/{type}', name: 'app_reference_by_type', methods: ['GET'])]
public function retrieveReferenceByType(string $type, EntityManagerInterface $emi): Response
{
$res = new Response();
$data = $emi->getRepository(Reference::class)->findByType($type);
$res->setContent(json_encode($data));
return $res;
}
} }

View File

@ -4,18 +4,25 @@ namespace App\Controller;
use App\Entity\User; use App\Entity\User;
use App\Form\RegistrationFormType; use App\Form\RegistrationFormType;
use App\Utils\Utils;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
class RegistrationController extends AbstractController class RegistrationController extends AbstractController
{ {
#[Route('/register', name: 'app_register')] #[Route('/register', name: 'app_register')]
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response public function register(
{ Request $request,
UserPasswordHasherInterface $userPasswordHasher,
EntityManagerInterface $entityManager,
MailerInterface $mailer
): Response {
$user = new User(); $user = new User();
$form = $this->createForm(RegistrationFormType::class, $user); $form = $this->createForm(RegistrationFormType::class, $user);
@ -39,6 +46,8 @@ class RegistrationController extends AbstractController
$entityManager->persist($user); $entityManager->persist($user);
$entityManager->flush(); $entityManager->flush();
$this->sendEmail($user, $mailer);
return $this->redirectToRoute('app_home'); return $this->redirectToRoute('app_home');
} }
@ -46,4 +55,18 @@ class RegistrationController extends AbstractController
'registrationForm' => $form, 'registrationForm' => $form,
]); ]);
} }
private function sendEmail(User $user, MailerInterface $mailer): void
{
$util = new Utils();
$util->sendEmail(
$mailer,
new Address('ryan@rkprather.com'),
new Address('ryan@rkprather.com'),
'New Account',
$this->renderView('emails/registration.html.twig', [
'user' => $user
])
);
}
} }

View File

@ -42,6 +42,9 @@ class Note implements JsonSerializable
#[ORM\ManyToOne(inversedBy: 'notes')] #[ORM\ManyToOne(inversedBy: 'notes')]
private ?User $user = null; private ?User $user = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $recording = null;
public function getId(): ?Uuid public function getId(): ?Uuid
{ {
return $this->id; return $this->id;
@ -166,12 +169,21 @@ class Note implements JsonSerializable
{ {
return "<a href='#' onclick=\"retrieveNote('{$this->id}')\">". return "<a href='#' onclick=\"retrieveNote('{$this->id}')\">".
$this->title. $this->title.
"</a>"; "</a>&nbsp;".
"<a href='#' onclick=\"deleteNote('{$this->id}', this)\">".
"<i class='fas fa-trash-alt'></i>".
"</a>".
(
$this->recording ? "<br/>".
"<a href='{$this->recording}' target='_blank' class='recording-link'>".
"<i class='fa fa-play-circle'></i>".
"</a>" : null
);
} }
public function toTableRow(): string public function toTableRow(): string
{ {
return "<tr>". return "<tr data-id='row-{$this->id->toHex()}'>".
"<td>{$this->toLink()}</td>". "<td>{$this->toLink()}</td>".
"<td>{$this->speaker->getName()}</td>". "<td>{$this->speaker->getName()}</td>".
"<td>{$this->passage}</td>". "<td>{$this->passage}</td>".
@ -183,6 +195,7 @@ class Note implements JsonSerializable
{ {
return [ return [
'id' => $this->getId(), 'id' => $this->getId(),
'link' => $this->toLink(),
'title' => $this->getTitle(), 'title' => $this->getTitle(),
'date' => $this->getDate(), 'date' => $this->getDate(),
'passage' => $this->getPassage(), 'passage' => $this->getPassage(),
@ -193,4 +206,16 @@ class Note implements JsonSerializable
'user' => $this->getUser(), 'user' => $this->getUser(),
]; ];
} }
public function getRecording(): ?string
{
return $this->recording;
}
public function setRecording(?string $recording): static
{
$this->recording = $recording;
return $this;
}
} }

View File

@ -11,6 +11,7 @@ use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])] #[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
@ -23,6 +24,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
private ?Uuid $id = null; private ?Uuid $id = null;
#[ORM\Column(length: 180)] #[ORM\Column(length: 180)]
#[Assert\Email(
message: 'The email {{ value }} is not a valid email.',
)]
private ?string $email = null; private ?string $email = null;
/** /**
@ -64,12 +68,22 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
#[ORM\OneToMany(targetEntity: Note::class, mappedBy: 'user')] #[ORM\OneToMany(targetEntity: Note::class, mappedBy: 'user')]
private Collection $notes; private Collection $notes;
/**
* @var Collection<int, NoteShares>
*/
#[ORM\OneToMany(targetEntity: NoteShares::class, mappedBy: 'ownerId', orphanRemoval: true)]
private Collection $noteShares;
#[ORM\Column(nullable: true)]
private ?array $metaData = null;
public function __construct() public function __construct()
{ {
$this->series = new ArrayCollection(); $this->series = new ArrayCollection();
$this->speakers = new ArrayCollection(); $this->speakers = new ArrayCollection();
$this->templates = new ArrayCollection(); $this->templates = new ArrayCollection();
$this->notes = new ArrayCollection(); $this->notes = new ArrayCollection();
$this->noteShares = new ArrayCollection();
} }
public function getId(): ?Uuid public function getId(): ?Uuid
@ -77,6 +91,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
return $this->id; return $this->id;
} }
public function getHexId(): string
{
return $this->id->toHex();
}
public function setId(?Uuid $id): static public function setId(?Uuid $id): static
{ {
$this->id = $id; $this->id = $id;
@ -299,4 +318,46 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, JsonSer
'name' => $this->name, 'name' => $this->name,
]; ];
} }
/**
* @return Collection<int, NoteShares>
*/
public function getNoteShares(): Collection
{
return $this->noteShares;
}
public function addNoteShare(NoteShares $noteShare): static
{
if (!$this->noteShares->contains($noteShare)) {
$this->noteShares->add($noteShare);
$noteShare->setOwner($this);
}
return $this;
}
public function removeNoteShare(NoteShares $noteShare): static
{
if ($this->noteShares->removeElement($noteShare)) {
// set the owning side to null (unless already changed)
if ($noteShare->getOwner() === $this) {
$noteShare->setOwner(null);
}
}
return $this;
}
public function getMetaData(): ?array
{
return $this->metaData;
}
public function setMetaData(?array $metaData): static
{
$this->metaData = $metaData;
return $this;
}
} }

35
src/Utils/Utils.php Normal file
View File

@ -0,0 +1,35 @@
<?php
namespace App\Utils;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
class Utils
{
public function sendEmail(MailerInterface $mailer, Address $from, Address $to, string $subject, string $content)
{
//$dsn = "smtp://{$_ENV['MAIL_USER']}:{$_ENV['MAIL_PWD']}@{$_ENV['MAIL_SERVER']}:{$_ENV['MAIL_PORT']}";
//dump($_ENV['MAILER_DSN']);
//$_ENV['MAILER_DSN'] = $dsn;
//dump($_ENV['MAILER_DSN']);
//die;
$mail = (new Email())
->from($from)
->to($to)
->subject($subject)
->replyTo($from)
->html($content);
try {
$mailer->send($mail);
} catch (TransportExceptionInterface $e) {
die($e->getMessage());
// some error prevented the email sending; display an
// error message or try to resend the message
}
}
}

View File

@ -12,7 +12,7 @@
<title>{% block title %}Welcome!{% endblock %}</title> <title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %} {% block stylesheets %}{% endblock %}
</head> </head>
<body class='is-preload' onload='setHeight()' onresize='setHeight()'> <body class='is-preload' onresize='setHeight()'>
{% block body %}{% endblock %} {% block body %}{% endblock %}
{% block javascripts %}{% endblock %} {% block javascripts %}{% endblock %}
</body> </body>

View File

@ -0,0 +1,163 @@
{% extends 'base.html.twig' %}
{% block title %}Markdown Cheat Sheet{% endblock %}
{% block stylesheets %}
<link href="/theme/assets/css/main.css" rel="stylesheet" />
<link href='/theme/assets/css/jquery-ui.theme.css' rel='stylesheet' />
<link href='/theme/assets/css/jquery-ui.structure.css' rel='stylesheet' />
<link href='/css/style.css' rel='stylesheet' />
<link href='//cdn.datatables.net/2.0.8/css/dataTables.dataTables.min.css' rel='stylesheet' />
{% endblock %}
{% block javascripts %}
<script src="/theme/assets/js/jquery.min.js"></script>
<script src='/theme/assets/js/jquery-ui.js'></script>
<script src="/theme/assets/js/browser.min.js"></script>
<script src="/theme/assets/js/breakpoints.min.js"></script>
<script src="/theme/assets/js/util.js"></script>
<script src="/theme/assets/js/main.js"></script>
<script src='//momentjs.com/downloads/moment-with-locales.js'></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" integrity="sha512-ohlWmsCxOu0bph1om5eDL0jm/83eH09fvqLDhiEdiqfDeJbEvz4FSbeY0gLJSVJwQAp0laRhTXbUQG+ZUuifUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src='//cdn.datatables.net/2.0.8/js/dataTables.min.js'></script>
<script src='/js/script.js'></script>
{% endblock %}
{% block body %}
<div style='padding-left:5px;'>
<h1>Markdown Cheat Sheet</h1>
<p>The following was provided by <a href='https://www.markdownguide.com'>The Markdown Guid</a></p>
<p> This Markdown cheat sheet provides a quick overview of all the Markdown syntax elements. It can't cover every edge case, so if you need more information about any of these elements, refere to the reference guides for <a href='//www.markdownguide.org/basic-syntax/'>basic syntax</a> and </a href='//www.markdownguide.org/extended-syntax/'>extended syntax</a>.</p>
<h2>Basic Syntax</h2>
<p>These are the elements outlined in John Gruberal's original design document. All Markdown applications support these elements. The quoted text is what is needed to render what is displayed right below</p>
<h3>Headings</h3>
"# H1"<br/>
<h1># H1</h1>
"## H2"<br/>
<h2>## H2</h2>
"### H3"<br/>
<h3>### H3</h3>
<h3>Bold</h3>
"**bold text**"<br/>
<strong>bold text</strong>
<h3>Italic</h3>
"*italicized text*"<br/>
<i>italicized text</i>
<h3>Blockquote</h3>
"> blockquote"<br/>
<blockquote>blockquote</blockquote>
<h3>Ordered List</h3>
"1. First item"<br/>
"2. Second item"<br/>
"3. Third item"<br/>
<br/>
<ol style='list-style-position:inside;'>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ol>
<h3>Unordered List</h3>
"- First item"<br/>
"- Second item"<br/>
"- Third item"<br/>
<br/>
<ul style='list-style-position:inside;'>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ul>
<h3>Code</h3>
"`code`"<br/>
<code>code</code><br/>
<h3>Horizontal Rule</h3>
"---"<br/>
<hr/>
<h3>Link</h3>
"[Markdown Guide](https://www.markdownguide.org)"<br/>
<a href='//www.markdownguide.org'>Markdown Guide</a><br/>
<h3>Image</h3>
"![alt text](https://www.markdownguide.org/assets/images/tux.png)"<br/>
<img src='//www.markdownguide.org/assets/images/tux.png' alt='alt text' /><br/>
<h2>Extended Syntax</h2>
<p>These elements extend the basic syntax by adding additional features. Not all Markdown applications support these elements.</p>
<h3>Table</h3>
| Syntax | Description |<br/>
| ----------- | ----------- |<br/>
| Header | Title |<br/>
| Paragraph | Text |<br/>
<br/>
<table>
<thead>
<th>Syntax</th>
<th>Description</th>
</thead>
<tbody>
<tr>
<td>Header</td>
<td>Title</td>
</tr>
<tr>
<td>Paragraph</td>
<td>Text</td>
</tr>
</tbody>
</table>
<h3>Fenced Code Block</h3>
<p>Specifying the language after the first 3 backticks may help with text formatting and highlighting based on the language entered, may or may not be supported in a given Markdown tools implementation</p>
```json<br/>
{<br/>
&nbsp;&nbsp;"firstName": "John",<br/>
&nbsp;&nbsp;"lastName": "Smith",<br/>
&nbsp;&nbsp;"age": 25,<br/>
}<br/>
```<br/>
<pre>
{
"firstName": "John",
"lastName": "Smith",
"age": 25
}
</pre>
</div>
{% endblock %}

View File

@ -7,17 +7,32 @@
<link href='/theme/assets/css/jquery-ui.theme.css' rel='stylesheet' /> <link href='/theme/assets/css/jquery-ui.theme.css' rel='stylesheet' />
<link href='/theme/assets/css/jquery-ui.structure.css' rel='stylesheet' /> <link href='/theme/assets/css/jquery-ui.structure.css' rel='stylesheet' />
<link href='/css/style.css' rel='stylesheet' /> <link href='/css/style.css' rel='stylesheet' />
<link href='//cdn.datatables.net/2.0.8/css/dataTables.dataTables.min.css' rel='stylesheet' />
<style>
#notes,
#notePreview {
font-size: {{ meta.noteTextSize }}pt;
}
</style>
{% endblock %} {% endblock %}
{% block javascripts %} {% block javascripts %}
<script src='/js/script.js'></script>
<script src="/theme/assets/js/jquery.min.js"></script> <script src="/theme/assets/js/jquery.min.js"></script>
<script src='/theme/assets/js/jquery-ui.js'></script> <script src='/theme/assets/js/jquery-ui.js'></script>
<script src="/theme/assets/js/browser.min.js"></script> <script src="/theme/assets/js/browser.min.js"></script>
<script src="/theme/assets/js/breakpoints.min.js"></script> <script src="/theme/assets/js/breakpoints.min.js"></script>
<script src="/theme/assets/js/util.js"></script> <script src="/theme/assets/js/util.js"></script>
<script src="/theme/assets/js/main.js"></script> <script src="/theme/assets/js/main.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" integrity="sha512-ohlWmsCxOu0bph1om5eDL0jm/83eH09fvqLDhiEdiqfDeJbEvz4FSbeY0gLJSVJwQAp0laRhTXbUQG+ZUuifUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src='//momentjs.com/downloads/moment-with-locales.js'></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.2/markdown-it.min.js" integrity="sha512-ohlWmsCxOu0bph1om5eDL0jm/83eH09fvqLDhiEdiqfDeJbEvz4FSbeY0gLJSVJwQAp0laRhTXbUQG+ZUuifUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src='//cdn.datatables.net/2.0.8/js/dataTables.min.js'></script>
<script>
let saveInterval = ({{ meta.saveInterval }} * 1000);
let saveTimeout = ({{ meta.saveTimeout }} * 1000);
const SAVE_FAILURE_LIMIT = {{ meta.saveFailureCount }};
let saveFailureCount = {{ meta.saveFailureCount }};
</script>
<script src='/js/script.js'></script>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
@ -34,11 +49,11 @@
<div style='display:inline-block'> <div style='display:inline-block'>
<button onclick='increaseFont()'><i class='fa fa-plus'></i></button>&nbsp; <button onclick='increaseFont()'><i class='fa fa-plus'></i></button>&nbsp;
<button onclick='decreaseFont()'><i class='fa fa-minus'></i></button>&nbsp; <button onclick='decreaseFont()'><i class='fa fa-minus'></i></button>&nbsp;
<button onclick='openRef(false)'><i class='fa fa-book'></i></button> <button id='openRefBtn' class='button' onclick='openRef(false)'><i class='fa fa-book'></i></button>
</div> </div>
<div id="ref" style='font-size:12pt;'></div> <div id="ref" style='font-size:12pt;'></div>
<div id='note-list'> <div id='note-list'>
<table> <table id='note-table' data-order='[[ 3, "desc" ]]'>
<thead> <thead>
<tr> <tr>
<th>Title</th> <th>Title</th>
@ -47,11 +62,6 @@
<th>Date</th> <th>Date</th>
</tr> </tr>
</thead> </thead>
<tbody>
{% for n in reverseNoteSort %}
{{ n.toTableRow()|raw }}
{% endfor %}
</tbody>
</table> </table>
</div> </div>
</section> </section>
@ -59,10 +69,10 @@
<section class="notes"> <section class="notes">
<div id='note-header-left'> <div id='note-header-left'>
<h2>Notes</h2> <h2>Notes</h2>
<i id='save-check' class='fa fa-check'></i> <i id='save-check' class='fa fa-save'></i>
</div> </div>
<div id='note-header-right'> <div id='note-header-right'>
<select id='template' onchange="retrieveTemplate('template','notes')"> <select id='template' onchange="retrieveTemplate('template','notes')" style='width:200px;'>
<option value=0>-- Template --</option> <option value=0>-- Template --</option>
{% for t in app.user.templates %} {% for t in app.user.templates %}
<option value="{{ t.id }}">{{ t.name }}</option> <option value="{{ t.id }}">{{ t.name }}</option>
@ -80,7 +90,10 @@
<div id='fields-container'> <div id='fields-container'>
<input type="hidden" id="noteId" value="" /> <input type="hidden" id="noteId" value="" />
<input type="text" id="noteTitle" placeholder="Title..." /> <input type="text" id="noteTitle" placeholder="Title..." />
<input type='text' id='noteDate' onchange='textDirty=true;saved=false;' /> <input type='text' id='noteDate' placeholder='Date...' onchange='textDirty=true;saved=false;' />
<input type='text' id='passage' placeholder='Passage...' onchange='saved=false;textDirty=true;' />
<br />
<input type='text' id='recording' name='recording' placeholder='Recording link...' />
<input type='text' id='newSpeaker' placeholder='Name...' onkeyup='saveSpeaker(event)' style='display:none;' /> <input type='text' id='newSpeaker' placeholder='Name...' onkeyup='saveSpeaker(event)' style='display:none;' />
<select id="speaker" onchange='newSpeaker()'> <select id="speaker" onchange='newSpeaker()'>
<option value=0>-- Speaker --</option> <option value=0>-- Speaker --</option>
@ -97,7 +110,6 @@
<option value='{{ s.id }}'>{{ s.name }}</option> <option value='{{ s.id }}'>{{ s.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<input type='text' id='passage' placeholder='Passage...' onchange='saved=false;textDirty=true;' />
</div> </div>
<textarea id="notes" wrap="hard"></textarea> <textarea id="notes" wrap="hard"></textarea>
@ -121,6 +133,12 @@
<option value='wcf'>Westminster Confession of Faith</option> <option value='wcf'>Westminster Confession of Faith</option>
<option value='wsc'>Westminster Shorter Catechism</option> <option value='wsc'>Westminster Shorter Catechism</option>
<option value='wlc'>Westminster Larger Catechism</option> <option value='wlc'>Westminster Larger Catechism</option>
<option value='lbc'>London Baptist Confession</option>
<option value='39a'>Thirty-Nine Articles</option>
<option value='1hc'>First Helvetic Confession</option>
<option value='2hc'>Second Helvetic Confession</option>
<option value='sd'>Savoy Declaration</option>
<option value='agc'>Augsburg Confession</option>
</select> </select>
<select id='referenceBook' onchange='filterBooks()'> <select id='referenceBook' onchange='filterBooks()'>
</select> </select>

View File

@ -0,0 +1,156 @@
{% extends 'base.html.twig' %}
{% block title %}Profile | Sermon Notes{% endblock %}
{% block stylesheets %}
<link href="/theme/assets/css/main.css" rel="stylesheet" />
<link href='/theme/assets/css/jquery-ui.theme.css' rel='stylesheet' />
<link href='/theme/assets/css/jquery-ui.structure.css' rel='stylesheet' />
<link href='/css/style.css' rel='stylesheet' />
<link href='//cdn.datatables.net/2.0.8/css/dataTables.dataTables.min.css' rel='stylesheet' />
<style>
.flex-container {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: normal;
align-items: normal;
align-content: normal;
}
.user-flex {
display: block;
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
align-self: auto;
order: 0;
border: solid 1px black;
}
.settings-flex {
display: block;
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
align-self: auto;
order: 0;
}
.notes-flex {
display: block;
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
align-self: auto;
order: 0;
}
label,
input[type="number"],
input[type="email"],
input[type="text"] {
display: inline !important;
}
input[type="checkbox"] {
appearance: auto;
opacity: 1;
margin: 0;
width: 20px;
height: 20px;
}
</style>
{% endblock %}
{% block javascripts %}
<script src="/theme/assets/js/jquery.min.js"></script>
<script src='/theme/assets/js/jquery-ui.js'></script>
<script src="/theme/assets/js/browser.min.js"></script>
<script src="/theme/assets/js/breakpoints.min.js"></script>
<script src="/theme/assets/js/util.js"></script>
<script src="/theme/assets/js/main.js"></script>
<script src='//momentjs.com/downloads/moment-with-locales.js'></script>
<script src='//cdn.datatables.net/2.0.8/js/dataTables.min.js'></script>
<script type='text/javascript'>
$(function() {
});
function saveSettings() {
var saveInterval = $('#save-interval');
var saveReferences = $('#save-references');
var noteTextSize = $('#note-text-size');
var trackSaveSize = $('#track-save-size');
var saveTimeout = $('#save-timeout');
var saveFailureCount = $('#save-failure-count');
fetch('/index.php/save-settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'saveInterval': saveInterval.val(),
'saveReferences': saveReferences.is(':checked'),
'noteTextSize': noteTextSize.val(),
'trackSaveSize': trackSaveSize.is(':checked'),
'saveTimeout': saveTimeout.val(),
'saveFailureCount': saveFailureCount.val()
})
})
.then(response => response.json())
.then(results => {
alert(results.msg);
});
}
</script>
{% endblock %}
{% block body %}
<div class="flex-container">
<div class="user-flex">
<label for='name'>Name: </label>
<input type='text' id='name' name='name' value='{{ app.user.name }}' /><br />
<label for='email'>Email: </label>
<input type='email' id='email' name='email' value='{{ app.user.email }}' /><br />
<label for='password'>Password: </label>
<input type='password' id='password' name='password' /><br/>
<label for='new-password'>New Password: </label>
<input type='password' id='new-password' name='new-password' /><br />
<label for='conf-password'>Confirm Password: </label>
<input type='password' id='conf-password' name='conf-password' /><br />
</div>
<div class="settings-flex">
<label for='save-interval'>Save Interval (seconds)?</label>
<input type='number' id='save-interval' value='{{ meta.saveInterval }}' title='What is the interval to trigger an autosave, in seconds?' /><br/>
<label for='save-references'>Save References?</label>
<input type='checkbox' id='save-references' {{ meta.saveReferences }} title='Do you want to also save reference content' /><br />
<label for='note-text-size'>Note Text Size? (points)</label>
<input type='number' id='note-text-size' value='{{ meta.noteTextSize }}' title='Font size of the note preview, in points' /><br />
<label for='track-save-size'>Track Save Size?</label>
<input type='checkbox' id='track-save-size' {{ meta.noteTextSize }} title='Do you want to track the size of saves, useful if teathering to mobile device?' /><br />
<label for='save-timeout'>Save Timeout? (seconds)</label>
<input type='number' id='save-timeout' value='{{ meta.saveTimeout }}' title='How long does it wait to before cancelling the save and trying again later?' /><br />
<label for='save-failure-count'>Save Failure Count? </label>
<input type='number' id='save-failure-count' value='{{ meta.saveFailureCount }}' title='How many times do you want to attempt to auto save before it stops and waits for a manual attempt' /><br />
<button id='save-settings' onclick='saveSettings()'>Save Settings</button>
<button id='back' onclick='history.go(-1)'>Back</button>
</div>
<div class="notes-fles">
<table id='notes'>
<thead>
</table>
</div>
</div>
{% endblock %}

View File

@ -13,7 +13,7 @@
<nav id="menu"> <nav id="menu">
<header class="major"> <header class="major">
{% if app.user %} {% if app.user %}
<h3>Welcome {{ app.user.name }}</h3> <h3>Welcome <a href='/index.php/profile' style='text-decoration:underline;'>{{ app.user.name }}</a></h3>
<a href='/index.php/logout'>Logout</a> <a href='/index.php/logout'>Logout</a>
{% endif %} {% endif %}
</header> </header>
@ -29,6 +29,7 @@
{% endif %} {% endif %}
<li><a href='#' onclick="openRef()">Open Reference</a></li> <li><a href='#' onclick="openRef()">Open Reference</a></li>
<li><a href='/index.php/template-editor'>Template Editor</a></li> <li><a href='/index.php/template-editor'>Template Editor</a></li>
<li><a href='/index.php/cheat-sheet' target='_blank'>Markdown Cheat Sheet</a></li>
{% else %} {% else %}
<li><a href="/index.php/">Home</a></li> <li><a href="/index.php/">Home</a></li>
<li><a href='/index.php/register'>Register</a></li> <li><a href='/index.php/register'>Register</a></li>

View File

@ -5,44 +5,26 @@
</head> </head>
<body> <body>
<select id='references' onchange='retrieveReference(this)'> <select id='referenceTypes' onchange='retrieveReferenceType(this)'>
<option value=''>-- Select Reference --</option> <option value=''>-- Select Reference --</option>
<optgroup id='creeds' label='Creeds'> <option value='new'>-- Insert New --</option>
{% for c in creeds %} <option value='creed'>Creed</option>
<option type='creed'>{{ c }}</option> <option value='belgic'>Belgic Confession</option>
{% endfor %} <option value='hc'>Heidelberg Catechism</option>
</optgroup> <option value='cd'>Canons of Dort</option>
<optgroup id='belgic' label='Belgic Confession'> <option value='wcf'>Westminster Confession of Faith</option>
{% for c in belgic %} <option value='wsc'>Westminster Shorter Catechism</option>
<option type='bc'>{{ c }}</option> <option value='wlc'>Westminster Larger Catechism</option>
{% endfor %} <option value='agc'>Augsberg Confession</option>
</optgroup> <option value='1hc'>First Helvetic Confession</option>
<optgroup id='heidelberg' label='Heidelberg Catechism'> <option value='2hc'>Second Helvetic Confession</option>
{% for c in heidelberg %} <option value='sd'>Savoy Declaration</option>
<option type='hc'>{{ c }}</option> <option value='39a'>Thirty-Nine Articles</option>
{% endfor %} <option value='lbc'>London Baptist Confession</option>
</optgroup> </select>&nbsp;&nbsp;
<optgroup id='dort' label='Canons of Dort'> <select id='referenceSeries' onchange='retrieveReference(this)'>
{% for c in dort %} </select>&nbsp;&nbsp;
<option type='cd'>{{ c }}</option> <input type='text' name='name' id='refName' style='display:none;' />&nbsp;&nbsp;
{% endfor %}
</optgroup>
<optgroup id='wcf' label='Westminster Confession of Faith'>
{% for c in wcf %}
<option type='wcf'>{{ c }}</option>
{% endfor %}
</optgroup>
<optgroup id='wsc' label='Westminster Short Catechism'>
{% for c in wsc %}
<option type='wsc'>{{ c }}</option>
{% endfor %}
</optgroup>
<optgroup id='wlc' label='Westminster Larger Catechism'>
{% for c in wlc %}
<option type='wlc'>{{ c }}</option>
{% endfor %}
</optgroup>
</select>
<button id='save' name='save' onclick='saveReference()'>Save</button> <button id='save' name='save' onclick='saveReference()'>Save</button>
<a href='/index.php/home'>Back</a><br /> <a href='/index.php/home'>Back</a><br />