Compare commits

...

10 Commits

Author SHA1 Message Date
58f83c72c2 updates 2024-04-27 22:45:24 -04:00
14c5221ac1 New migrations 2024-04-27 22:41:33 -04:00
b03c08a962 Update creeds 2024-04-27 22:41:05 -04:00
fa42c99f75 add reference table 2024-04-24 08:42:54 -04:00
65611693af Add fixtures 2024-04-24 08:42:37 -04:00
129020f4dd delete unnecessary file 2024-04-24 08:42:21 -04:00
d9acfd43c6 Add date to notes 2024-04-18 07:13:56 -04:00
2869e6f035 Add date field to note table 2024-04-18 07:05:05 -04:00
cbd1204792 add html twig files 2024-04-15 23:45:03 -04:00
aead9915bc add entities and repos 2024-04-15 23:44:36 -04:00
47 changed files with 2741 additions and 221 deletions

View File

@ -42,6 +42,7 @@
"symfony/validator": "6.4.*", "symfony/validator": "6.4.*",
"symfony/web-link": "6.4.*", "symfony/web-link": "6.4.*",
"symfony/yaml": "6.4.*", "symfony/yaml": "6.4.*",
"symfonycasts/verify-email-bundle": "^1.17",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0" "twig/twig": "^2.12|^3.0"
}, },
@ -95,11 +96,12 @@
} }
}, },
"require-dev": { "require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.5",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"symfony/browser-kit": "6.4.*", "symfony/browser-kit": "6.4.*",
"symfony/css-selector": "6.4.*", "symfony/css-selector": "6.4.*",
"symfony/debug-bundle": "6.4.*", "symfony/debug-bundle": "6.4.*",
"symfony/maker-bundle": "^1.0", "symfony/maker-bundle": "^1.58",
"symfony/phpunit-bridge": "^7.0", "symfony/phpunit-bridge": "^7.0",
"symfony/stopwatch": "6.4.*", "symfony/stopwatch": "6.4.*",
"symfony/web-profiler-bundle": "6.4.*" "symfony/web-profiler-bundle": "6.4.*"

View File

@ -13,4 +13,6 @@ return [
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
]; ];

View File

@ -12,6 +12,19 @@ security:
main: main:
lazy: true lazy: true
provider: users_in_memory provider: users_in_memory
custom_authenticator: App\Security\AppAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
# by default, the feature is enabled by checking a checkbox in the
# login form, uncomment the following line to always enable it.
#always_remember_me: true
# activate different ways to authenticate # activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall # https://symfony.com/doc/current/security.html#the-firewall

View File

@ -6,7 +6,13 @@
parameters: parameters:
services: services:
# default configuration for services in *this* file app.user_provider:
class: App\Security\AppAuthenticator
arguments: [
"%kernel.container_params.user_entity_manager",
"%kernel.container_params.password_hasher",
] # default configuration for services in *this* file
_defaults: _defaults:
autowire: true # Automatically injects dependencies in your services. autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
@ -14,11 +20,11 @@ services:
# makes classes in src/ available to be used as services # makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name # this creates a service per class whose id is the fully-qualified class name
App\: App\:
resource: '../src/' resource: "../src/"
exclude: exclude:
- '../src/DependencyInjection/' - "../src/DependencyInjection/"
- '../src/Entity/' - "../src/Entity/"
- '../src/Kernel.php' - "../src/Kernel.php"
# add more service definitions when explicit configuration is needed # add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones # please note that last definitions always *replace* previous ones

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 Version20240418015109 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('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text) SELECT id, speaker_id, series_id, title, text FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text) SELECT id, speaker_id, series_id, title, text FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

View File

@ -0,0 +1,45 @@
<?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 Version20240424081416 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('CREATE TABLE reference (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, type VARCHAR(64) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(10) NOT NULL, ndx INTEGER DEFAULT NULL, content CLOB NOT NULL)');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE reference');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

View File

@ -0,0 +1,45 @@
<?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 Version20240424220326 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('CREATE TABLE bible (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, book VARCHAR(255) NOT NULL, chapter INTEGER NOT NULL, verse INTEGER NOT NULL, content CLOB NOT NULL, book_index INTEGER NOT NULL)');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE bible');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

View File

@ -0,0 +1,49 @@
<?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 Version20240425003903 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 bible ADD COLUMN label VARCHAR(255) DEFAULT NULL');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__bible AS SELECT id, book, chapter, verse, content, book_index FROM bible');
$this->addSql('DROP TABLE bible');
$this->addSql('CREATE TABLE bible (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, book VARCHAR(255) NOT NULL, chapter INTEGER NOT NULL, verse INTEGER NOT NULL, content CLOB NOT NULL, book_index INTEGER NOT NULL)');
$this->addSql('INSERT INTO bible (id, book, chapter, verse, content, book_index) SELECT id, book, chapter, verse, content, book_index FROM __temp__bible');
$this->addSql('DROP TABLE __temp__bible');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

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 Version20240425210626 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('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, passage VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date) SELECT id, speaker_id, series_id, title, text, date FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

View File

@ -0,0 +1,45 @@
<?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 Version20240425231139 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('CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, is_verified BOOLEAN NOT NULL)');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date, passage FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, passage VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id), CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date, passage) SELECT id, speaker_id, series_id, title, text, date, passage FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE user');
$this->addSql('CREATE TEMPORARY TABLE __temp__notes AS SELECT id, speaker_id, series_id, title, text, date, passage FROM notes');
$this->addSql('DROP TABLE notes');
$this->addSql('CREATE TABLE notes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, speaker_id INTEGER NOT NULL, series_id INTEGER DEFAULT NULL, title VARCHAR(255) NOT NULL, text CLOB NOT NULL, date DATE NOT NULL, passage VARCHAR(255) DEFAULT NULL, CONSTRAINT FK_11BA68CD04A0F27 FOREIGN KEY (speaker_id) REFERENCES speaker (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_11BA68C5278319C FOREIGN KEY (series_id) REFERENCES series (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO notes (id, speaker_id, series_id, title, text, date, passage) SELECT id, speaker_id, series_id, title, text, date, passage FROM __temp__notes');
$this->addSql('DROP TABLE __temp__notes');
$this->addSql('CREATE INDEX IDX_11BA68CD04A0F27 ON notes (speaker_id)');
$this->addSql('CREATE INDEX IDX_11BA68C5278319C ON notes (series_id)');
}
}

View File

@ -91,6 +91,72 @@ ul.menu-open {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
} }
#passage {
width: 100px;
}
#newSpeaker {
display: none;
width: 110px;
}
#newSeries {
display: none;
width: 110px;
}
#noteSearch {
display: none;
}
#fields-container {
display: none;
}
#show-hide-btn {
position: absolute;
top: 10px;
right: 20px;
font-size: 16px;
cursor: pointer;
background-color: #4CAF50;
/* green */
color: #fff;
/* white */
border: none;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.6);
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
transition: all 0.3s ease-out;
}
#show-hide-btn:hover {
background-color: #3e8e41;
/* darker green */
}
#show-hide-btn::before {
font-size: 16px;
cursor: pointer;
}
#show-hide-btn::before {
font-size: 16px;
cursor: pointer;
transition: transform 0.5s ease-in-out;
}
#show-hide-btn:hover::before {
transform: translateY(-10px);
}
#fields-container.show {
display: block;
}
.notes { .notes {
width: 55%; width: 55%;
} }
@ -100,6 +166,22 @@ textarea#notes {
height: 100%; height: 100%;
} }
#notePreview {
display: none;
overflow-x: scroll;
}
#note-header-left,
#note-header-right {
display: inline-flex;
flex-direction: row;
width: 49%;
}
#note-header-right {
flex-direction: row-reverse !important;
}
div#refQuery { div#refQuery {
display: none; display: none;
position: absolute; position: absolute;

View File

@ -1 +1 @@
{"version":3,"sources":["style.scss","style.css"],"names":[],"mappings":"AAAA,kCAAA;AACA;EACI,SAAA;ACCJ;;ADEA;EACI,aAAA;EACA,mBAAA;EACA,eAAA;EACA,6BAAA;EACA,oBAAA;EACA,yBAAA;EACA,iBAAA;EACA,iCAAA;EACA,cAAA;ACCJ;;ADEA;EACI,YAAA;EACA,WAAA;ACCJ;;ADEA,6BAAA;AAEA;EACI,aAAA;EACA,8BAAA;EACA,mBAAA;EACA,wBAAA;EACA,uBAAA;EACA,eAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,wCAAA;ACAJ;;ADGA;EACI,YAAA;ACAJ;;ADGA;;EAEI,YAAA;ACAJ;;ADIA;EACI,yBAAA;EACA,yBAAA;EACA,aAAA;EACA,YAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;ACDJ;;ADWA;EACI,WAAA;ACRJ;;ADWA;EACI,aAAA;EACA,2BAAA;EACA,mBAAA;EACA,aAAA;EACA,WAAA;EACA,eAAA;EACA,kBAAA;ACRJ;;ADWA;EACI,SAAA;EACA,UAAA;ACRJ;;ADWA;EACI,gBAAA;EACA,qBAAA;ACRJ;;ADWA;EACI,UAAA;ACRJ;;ADWA;EACI,kBAAA;EACA,WAAA;EACA,YAAA;EACA,uBAAA;EACA,kBAAA;EACA,wCAAA;ACRJ;;ADWA;EACI,UAAA;ACRJ;;ADWA;EACI,WAAA;EACA,YAAA;ACRJ;;ADWA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,oCAAA;ACRJ;;ADWA;EACI,YAAA;EACA,kBAAA;EACA,kBAAA;EACA,eAAA;EACA,gBAAA;EACA,WAAA;EACA,yBAAA;EACA,YAAA;EACA,YAAA;EACA,eAAA;ACRJ","file":"style.css"} {"version":3,"sources":["style.scss","style.css"],"names":[],"mappings":"AAAA,kCAAA;AACA;EACI,SAAA;ACCJ;;ADEA;EACI,aAAA;EACA,mBAAA;EACA,eAAA;EACA,6BAAA;EACA,oBAAA;EACA,yBAAA;EACA,iBAAA;EACA,iCAAA;EACA,cAAA;ACCJ;;ADEA;EACI,YAAA;EACA,WAAA;ACCJ;;ADEA,6BAAA;AAEA;EACI,aAAA;EACA,8BAAA;EACA,mBAAA;EACA,wBAAA;EACA,uBAAA;EACA,eAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,wCAAA;ACAJ;;ADGA;EACI,YAAA;ACAJ;;ADGA;;EAEI,YAAA;ACAJ;;ADIA;EACI,yBAAA;EACA,yBAAA;EACA,aAAA;EACA,YAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;ACDJ;;ADIA;EACI,WAAA;ACDJ;;ADIA;EACI,aAAA;EACA,2BAAA;EACA,mBAAA;EACA,aAAA;EACA,WAAA;EACA,eAAA;EACA,kBAAA;ACDJ;;ADIA;EACI,SAAA;EACA,UAAA;ACDJ;;ADIA;EACI,gBAAA;EACA,qBAAA;ACDJ;;ADIA;EACI,UAAA;ACDJ;;ADIA;EACI,kBAAA;EACA,WAAA;EACA,YAAA;EACA,uBAAA;EACA,kBAAA;EACA,wCAAA;ACDJ;;ADIA;EACI,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;EACA,YAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,aAAA;ACDJ;;ADIA;EACI,kBAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;EACA,eAAA;EACA,yBAAA;EACA,UAAA;EACA,WAAA;EACA,UAAA;EACA,YAAA;EACA,kBAAA;EACA,wCAAA;EACA,kBAAA;EACA,kBAAA;EACA,qBAAA;EACA,qBAAA;EACA,eAAA;EACA,eAAA;EAGA,6BAAA;ACDJ;ADGI;EACI,yBAAA;EACA,iBAAA;ACDR;ADII;EACI,eAAA;EACA,eAAA;ACFR;;ADMA;EACI,eAAA;EACA,eAAA;EACA,sCAAA;ACHJ;;ADMA;EACI,4BAAA;ACHJ;;ADMA;EACI,cAAA;ACHJ;;ADMA;EACI,UAAA;ACHJ;;ADMA;EACI,WAAA;EACA,YAAA;ACHJ;;ADMA;EACI,aAAA;EACA,kBAAA;ACHJ;;ADMA;;EAEI,oBAAA;EACA,mBAAA;EACA,UAAA;ACHJ;;ADMA;EACI,sCAAA;ACHJ;;ADMA;EACI,aAAA;EACA,kBAAA;EACA,YAAA;EACA,oCAAA;ACHJ;;ADMA;EACI,YAAA;EACA,kBAAA;EACA,kBAAA;EACA,eAAA;EACA,gBAAA;EACA,WAAA;EACA,yBAAA;EACA,YAAA;EACA,YAAA;EACA,eAAA;ACHJ","file":"style.css"}

View File

@ -1 +1 @@
body{margin:0}.container{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;align-items:stretch;align-content:flex-start;max-width:1020px;margin:0 auto}.top-tab{height:50px;width:100%}.hamburger{display:flex;justify-content:space-between;align-items:center;margin:15px 0 15px 15px;border:#000 solid 1px;cursor:pointer;border-radius:5px;width:20px;height:20px;padding:5px;box-shadow:0 2px 5px rgba(0,0,0,.3)}.fa-bars:before,.fa-navicon:before{padding:3px}ul.menu-open{display:block !important;background-color:#f9c74d;padding:10px;z-index:100;list-style:none;list-style-type:none;position:fixed}.ref-tab{width:60px}.tab button{display:flex;justify-content:flex-start;align-items:center;height:100px;width:100%;cursor:pointer;text-align:center}.ref-tab ul{margin:0;padding:0}.ref-tab ul li{list-style:none;list-style-type:none}.ref{width:35%}.ref>div#ref{overflow-y:scroll;width:100%;height:100%;border:#000 solid 1px;border-radius:3px;box-shadow:0 2px 5px rgba(0,0,0,.3)}.notes{width:55%}textarea#notes{width:100%;height:100%}div#refQuery{display:none;position:absolute;z-index:100;background-color:rgba(0,0,0,.5)}div#refQuery #search{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}/*# sourceMappingURL=style.min.css.map */ body{margin:0}.container{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-evenly;align-items:stretch;align-content:flex-start;max-width:1020px;margin:0 auto}.top-tab{height:50px;width:100%}.hamburger{display:flex;justify-content:space-between;align-items:center;margin:15px 0 15px 15px;border:#000 solid 1px;cursor:pointer;border-radius:5px;width:20px;height:20px;padding:5px;box-shadow:0 2px 5px rgba(0,0,0,.3)}.fa-check{color:green}.fa-bars:before,.fa-navicon:before{padding:3px}ul.menu-open{display:block !important;background-color:#f9c74d;padding:10px;z-index:100;list-style:none;list-style-type:none;position:fixed}.ref-tab{width:60px}.tab button{display:flex;justify-content:flex-start;align-items:center;height:100px;width:100%;cursor:pointer;text-align:center}.ref-tab ul{margin:0;padding:0}.ref-tab ul li{list-style:none;list-style-type:none}.ref{width:35%}.ref>div#ref{overflow-y:scroll;width:100%;height:100%;border:#000 solid 1px;border-radius:3px;box-shadow:0 2px 5px rgba(0,0,0,.3)}#passage{width:100px}#newSpeaker{display:none;width:110px}#newSeries{display:none;width:110px}#noteSearch{display:none}#fields-container{display:none}#show-hide-btn{position:absolute;top:10px;right:20px;font-size:16px;cursor:pointer;background-color:#4caf50;color:#fff;border:none;border-radius:5px;box-shadow:0 2px 5px rgba(0,0,0,.6);padding:15px 32px;text-align:center;text-decoration:none;display:inline-block;font-size:16px;margin:4px 2px;transition:all .3s ease-out}#show-hide-btn:hover{background-color:#3e8e41}#show-hide-btn::before{font-size:16px;cursor:pointer}#show-hide-btn::before{font-size:16px;cursor:pointer;transition:transform .5s ease-in-out}#show-hide-btn:hover::before{transform:translateY(-10px)}#fields-container.show{display:block}.notes{width:55%}textarea#notes{width:100%;height:100%}#notePreview{display:none;overflow-x:scroll}#note-header-left,#note-header-right{display:inline-flex;flex-direction:row;width:49%}#note-header-right{flex-direction:row-reverse !important}div#refQuery{display:none;position:absolute;z-index:100;background-color:rgba(0,0,0,.5)}div#refQuery #search{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}/*# sourceMappingURL=style.min.css.map */

View File

@ -1 +1 @@
{"version":3,"sources":["style.scss"],"names":[],"mappings":"AACA,KACI,QAAA,CAGJ,WACI,YAAA,CACA,kBAAA,CACA,cAAA,CACA,4BAAA,CACA,mBAAA,CACA,wBAAA,CACA,gBAAA,CAEA,aAAA,CAGJ,SACI,WAAA,CACA,UAAA,CAKJ,WACI,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,uBAAA,CACA,qBAAA,CACA,cAAA,CACA,iBAAA,CACA,UAAA,CACA,WAAA,CACA,WAAA,CACA,mCAAA,CAGJ,mCAEI,WAAA,CAIJ,aACI,wBAAA,CACA,wBAAA,CACA,YAAA,CACA,WAAA,CACA,eAAA,CACA,oBAAA,CACA,cAAA,CAUJ,SACI,UAAA,CAGJ,YACI,YAAA,CACA,0BAAA,CACA,kBAAA,CACA,YAAA,CACA,UAAA,CACA,cAAA,CACA,iBAAA,CAGJ,YACI,QAAA,CACA,SAAA,CAGJ,eACI,eAAA,CACA,oBAAA,CAGJ,KACI,SAAA,CAGJ,aACI,iBAAA,CACA,UAAA,CACA,WAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CAGJ,OACI,SAAA,CAGJ,eACI,UAAA,CACA,WAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,+BAAA,CAGJ,qBACI,WAAA,CACA,iBAAA,CACA,iBAAA,CACA,cAAA,CACA,eAAA,CACA,UAAA,CACA,wBAAA,CACA,WAAA,CACA,WAAA,CACA,cAAA","file":"style.min.css"} {"version":3,"sources":["style.scss"],"names":[],"mappings":"AACA,KACI,QAAA,CAGJ,WACI,YAAA,CACA,kBAAA,CACA,cAAA,CACA,4BAAA,CACA,mBAAA,CACA,wBAAA,CACA,gBAAA,CAEA,aAAA,CAGJ,SACI,WAAA,CACA,UAAA,CAKJ,WACI,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,uBAAA,CACA,qBAAA,CACA,cAAA,CACA,iBAAA,CACA,UAAA,CACA,WAAA,CACA,WAAA,CACA,mCAAA,CAGJ,UACI,WAAA,CAGJ,mCAEI,WAAA,CAIJ,aACI,wBAAA,CACA,wBAAA,CACA,YAAA,CACA,WAAA,CACA,eAAA,CACA,oBAAA,CACA,cAAA,CAGJ,SACI,UAAA,CAGJ,YACI,YAAA,CACA,0BAAA,CACA,kBAAA,CACA,YAAA,CACA,UAAA,CACA,cAAA,CACA,iBAAA,CAGJ,YACI,QAAA,CACA,SAAA,CAGJ,eACI,eAAA,CACA,oBAAA,CAGJ,KACI,SAAA,CAGJ,aACI,iBAAA,CACA,UAAA,CACA,WAAA,CACA,qBAAA,CACA,iBAAA,CACA,mCAAA,CAGJ,SACI,WAAA,CAGJ,YACI,YAAA,CACA,WAAA,CAGJ,WACI,YAAA,CACA,WAAA,CAGJ,YACI,YAAA,CAGJ,kBACI,YAAA,CAGJ,eACI,iBAAA,CACA,QAAA,CACA,UAAA,CACA,cAAA,CACA,cAAA,CACA,wBAAA,CAEA,UAAA,CAEA,WAAA,CACA,iBAAA,CACA,mCAAA,CACA,iBAAA,CACA,iBAAA,CACA,oBAAA,CACA,oBAAA,CACA,cAAA,CACA,cAAA,CAGA,2BAAA,CAEA,qBACI,wBAAA,CAIJ,uBACI,cAAA,CACA,cAAA,CAIR,uBACI,cAAA,CACA,cAAA,CACA,oCAAA,CAGJ,6BACI,2BAAA,CAGJ,uBACI,aAAA,CAGJ,OACI,SAAA,CAGJ,eACI,UAAA,CACA,WAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CAGJ,qCAEI,mBAAA,CACA,kBAAA,CACA,SAAA,CAGJ,mBACI,qCAAA,CAGJ,aACI,YAAA,CACA,iBAAA,CACA,WAAA,CACA,+BAAA,CAGJ,qBACI,WAAA,CACA,iBAAA,CACA,iBAAA,CACA,cAAA,CACA,eAAA,CACA,UAAA,CACA,wBAAA,CACA,WAAA,CACA,WAAA,CACA,cAAA","file":"style.min.css"}

View File

@ -56,13 +56,6 @@ ul.menu-open {
position: fixed; position: fixed;
} }
.ref-tab,
.ref,
.notes {
// float: left;
// padding: 20px;
}
.ref-tab { .ref-tab {
width: 60px; width: 60px;
} }
@ -100,6 +93,76 @@ ul.menu-open {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
} }
#passage {
width: 100px;
}
#newSpeaker {
display: none;
width: 110px;
}
#newSeries {
display: none;
width: 110px;
}
#noteSearch {
display: none;
}
#fields-container {
display: none;
}
#show-hide-btn {
position: absolute;
top: 10px;
right: 20px;
font-size: 16px;
cursor: pointer;
background-color: #4CAF50;
/* green */
color: #fff;
/* white */
border: none;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.6);
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
-webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
&:hover {
background-color: #3e8e41;
/* darker green */
}
&::before {
font-size: 16px;
cursor: pointer;
}
}
#show-hide-btn::before {
font-size: 16px;
cursor: pointer;
transition: transform 0.5s ease-in-out;
}
#show-hide-btn:hover::before {
transform: translateY(-10px);
}
#fields-container.show {
display: block;
}
.notes { .notes {
width: 55% width: 55%
} }
@ -109,6 +172,22 @@ textarea#notes {
height: 100%; height: 100%;
} }
#notePreview {
display: none;
overflow-x: scroll;
}
#note-header-left,
#note-header-right {
display: inline-flex;
flex-direction: row;
width: 49%;
}
#note-header-right {
flex-direction: row-reverse !important;
}
div#refQuery { div#refQuery {
display: none; display: none;
position: absolute; position: absolute;

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

95
public/js/data.js Normal file
View File

@ -0,0 +1,95 @@
var BOOKS = {
"bible": [
"Genesis",
"Exodus",
"Leviticus",
"Numbers",
"Deuteronomy",
"Joshua",
"Judges",
"Ruth",
"1 Samuel",
"2 Samuel",
"1 Kings",
"2 Kings",
"1 Chronicles",
"2 Chronicles",
"Ezra",
"Nehemiah",
"Esther",
"Job",
"Psalms",
"Proverbs",
"Ecclesiastes",
"Song of Solomon",
"Isaiah",
"Jeremiah",
"Lamentations",
"Ezekiel",
"Daniel",
"Hosea",
"Joel",
"Amos",
"Obadiah",
"Jonah",
"Micah",
"Nahum",
"Habakkuk",
"Zephaniah",
"Haggai",
"Zechariah",
"Malachi",
"Matthew",
"Mark",
"Luke",
"John",
"Acts",
"Romans",
"1 Corinthians",
"2 Corinthians",
"Galatians",
"Ephesians",
"Philippians",
"Colossians",
"1 Thessalonians",
"2 Thessalonians",
"1 Timothy",
"2 Timothy",
"Titus",
"Philemon",
"Hebrews",
"James",
"1 Peter",
"2 Peter",
"1 John",
"2 John",
"3 John",
"Jude",
"Revelation"
],
"creed": {
"apc": "Apostle's Creed",
"nc": "Nicene Creed",
"atc": "Athanasian Creed",
"dc": "Definition of Chalcedon",
"fc": "French Confession"
},
"bc": [
1, 37
],
"hc": [
1, 52
],
"cd": [
"1", "2", "3", "5", "Conclusion"
],
"wcf": [
1, 33
],
"wsc": [
1, 107
],
"wlc": [
1, 196
]
};

View File

@ -1,7 +1,9 @@
// Get the link element // Get the link element
const link = document.querySelector('.hamburger'); const link = document.querySelector('.hamburger');
var converter = null; var converter = null;
var markdownit = null;
var references = {}; var references = {};
let saved = false;
// Add an event listener to the link // Add an event listener to the link
if (link) { if (link) {
@ -13,7 +15,13 @@ if (link) {
function setHeight() { function setHeight() {
converter = new showdown.Converter(); converter = new showdown.Converter();
converter.setFlavor('github'); //converter.setFlavor();
markdownit = new markdownit({
html: true,
linkify: true,
breaks: true
});
body = document.querySelector('body'); body = document.querySelector('body');
body.style.height = window.innerHeight + 'px'; body.style.height = window.innerHeight + 'px';
@ -28,9 +36,16 @@ function setHeight() {
ref.style.height = (window.innerHeight - 125) + 'px'; ref.style.height = (window.innerHeight - 125) + 'px';
notes = document.querySelector('.notes'); notes = document.querySelector('.notes');
notes.style.height = (window.innerHeight - 150) + 'px'; notes.style.height = (window.innerHeight - 130) + 'px';
setTimeout(saveNote, 5000); notePreview = document.querySelector('#notePreview');
notePreview.style.height = (window.innerHeight - 150) + 'px';
date = document.querySelector('#noteDate');
dt = new Date();
date.value = dt.getFullYear() + '-' + ((dt.getMonth() < 9) ? '0' + (dt.getMonth() + 1) : (dt.getMonth() + 1)) + '-' + dt.getDate();
setTimeout(saveNote, 10000);
} }
function newNote() { function newNote() {
@ -38,67 +53,91 @@ function newNote() {
notes.textContent = ''; notes.textContent = '';
} }
function openNote() { /**
* Save a note by sending it to the server for storage.
} *
* @param {Event} event - The event object triggering the save action.
* @return {void} No explicit return value.
*/
function saveNote(event) { function saveNote(event) {
if (event) {
event.preventDefault(); event.preventDefault();
}
if(!validateNote()) { if (!validateNote()) {
setTimeout(saveNote, 5000); setTimeout(saveNote, 5000);
return; return;
} }
fetch('/index.php/save-note', {
method: 'POST', var note = {
headers: { id: document.querySelector("#noteId").value,
"Content-Type": 'application/x-www-form-urlencoded' date: document.querySelector('#noteDate').value,
},
body: {
title: document.querySelector('#noteTitle').value, title: document.querySelector('#noteTitle').value,
speaker: document.querySelector('#speaker').value, speaker: document.querySelector('#speaker').value,
series: document.querySelector('#series').value, series: document.querySelector('#series').value,
note: document.querySelector('#notes').textContent passage: document.querySelector('#passage').value,
} note: document.querySelector('#notes').value
.then(response => response.text) };
.then(results => { fetch('/index.php/save-note', {
results = JSON.parse(results); method: 'POST',
alert(results); headers: {
showSave(); "Content-Type": 'application/json'
},
body: JSON.stringify(note)
}) })
}); .then(response => response.json())
setTimeout(saveNote, 5000); .then(data => {
if (data.msg == 'saved' && !saved) {
showSave();
saved = true;
}
})
.catch(error => console.log(error));
setTimeout(saveNote, 10000);
} }
function validateNote() { function validateNote() {
const note = document.querySelector('#notes'); const note = document.querySelector('#notes');
const date = document.querySelector('#noteDate');
const speaker = document.querySelector('#speaker'); const speaker = document.querySelector('#speaker');
const series = document.querySelector('#series'); const series = document.querySelector('#series');
const title = document.querySelector('#noteTitle'); const title = document.querySelector('#noteTitle');
const id = document.querySelector('#noteId');
const psg = document.querySelector('#passage');
if(!title.value.length) {return false;} if (!parseInt(id.value)) { return false; }
if (!title.value.length) { return false; }
if(!speaker.value) {return false;} if (!date.value) { return false; }
if (!parseInt(speaker.value)) { return false; }
if(!series.value) {return false;} if (!parseInt(series.value)) { return false; }
if (!psg.value) { return false; }
if(!note.textContent.length) {return false;} if (!note.value.length) { return false; }
return true; return true;
} }
function showSave() {// Get the element that will display the checkmark /**
* Displays a checkmark animation on the screen.
*
* @param {none} - This function does not take any parameters.
* @return {none} - This function does not return any value.
*/
function showSave() {
if (saved) { return; }
var checkmark = document.getElementById("save-check"); var checkmark = document.getElementById("save-check");
// 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)
setInterval(function() { var si = setInterval(function () {
// Increment the opacity of the checkmark by 0.01 each time // Increment the opacity of the checkmark by 0.01 each time
checkmark.style.opacity += 0.1; op = parseFloat(checkmark.style.opacity);
checkmark.style.opacity = op + 0.1;
// If the opacity is greater than or equal to 1, reset it back to 0 and stop the animation // If the opacity is greater than or equal to 1, reset it back to 0 and stop the animation
if (checkmark.style.opacity >= 1) { if (checkmark.style.opacity >= 1) {
checkmark.style.opacity = 0; checkmark.style.opacity = 0;
clearInterval(setInterval); clearInterval(si);
saved = false;
} }
}, 100); }, 100);
} }
@ -111,11 +150,98 @@ function discardNote() {
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('#notes').value = ''; document.querySelector('#notes').value = '';
fetch('/index.php/discard-note', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'id': document.querySelector('#noteId').value
})
.then(response => response.json())
.then(data => {
if (data.msg == 'deleted') {
alert('Note deleted.');
}
})
});
openRef(); openRef();
} }
function newSpeaker() {
if (document.querySelector('#speaker').value == 'new') {
document.querySelector('#newSpeaker').style.display = 'block';
document.querySelector('#speaker').style.display = 'none';
}
}
function saveSpeaker(event) {
if (event.keyCode == 13) {
fetch('/index.php/save-speaker', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'speakerName': document.querySelector('#newSpeaker').value
})
})
.then(response => response.json())
.then(results => {
var newSpeaker = document.createElement('option');
newSpeaker.text = document.querySelector('#newSpeaker').value;
newSpeaker.value = results.id;
document.querySelector('#speaker').add(newSpeaker);
alert(results.msg);
document.querySelector('#newSpeaker').style.display = 'none';
document.querySelector('#speaker').style.display = 'block';
document.querySelector('#newSpeaker').value = '';
document.querySelector('#speaker').value = results.id;
});
}
}
function newSeries() {
if (document.querySelector('#series').value == 'new') {
document.querySelector('#newSeries').style.display = 'block';
document.querySelector('#series').style.display = 'none';
}
}
function saveSeries(event) {
if (event.keyCode == 13) {
fetch('/index.php/save-series', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'seriesName': document.querySelector('#newSeries').value
})
})
.then(response => response.json())
.then(results => {
var newSeries = document.createElement('option');
newSeries.text = document.querySelector('#newSeries').value;
newSeries.value = results.id;
document.querySelector('#series').add(newSeries);
alert(results.msg);
document.querySelector('#newSeries').style.display = 'none';
document.querySelector('#series').style.display = 'block';
document.querySelector('#newSeries').value = '';
document.querySelector('#series').value = results.id;
});
}
}
function openRef() { function openRef() {
refQuery = document.querySelector('#refQuery'); refQuery = document.querySelector('#refQuery');
if (refQuery.style.display === 'block') { if (refQuery.style.display === 'block') {
@ -130,13 +256,17 @@ function openRef() {
} }
function queryRef() { function queryRef() {
const input = document.querySelector('#refQuery #search'); var input = document.querySelector('#refQuery #search');
var type = document.querySelector('#referenceType');
var book = document.querySelector('#referenceBook');
fetch('/index.php/retrieve-reference', { fetch('/index.php/retrieve-reference', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'plain/text' 'Content-Type': 'plain/text'
}, },
body: JSON.stringify({ body: JSON.stringify({
'type': type.value,
'book': book.value,
'reference': input.value 'reference': input.value
}) })
}) })
@ -167,6 +297,8 @@ function queryRef() {
references[results.title] = results.text; references[results.title] = results.text;
input.value = ''; input.value = '';
document.querySelector('#referenceType').value = 0;
document.querySelector('#referenceBook').value = 0;
openRef(); openRef();
link.click(); link.click();
}); });
@ -215,21 +347,177 @@ function saveTemplate() {
}); });
} }
function retrieveSeries() { function toggleFields() {
const fieldsContainer = document.getElementById('fields-container');
const showHideBtn = document.getElementById('show-hide-btn');
if (fieldsContainer.classList.contains('show')) {
// Hide the fields when the button says "Show Fields"
fieldsContainer.classList.remove('show');
fieldsContainer.style.display = 'none';
showHideBtn.textContent = 'Show';
} else {
// Show the fields when the button says "Hide Fields"
fieldsContainer.classList.add('show');
fieldsContainer.style.display = 'block';
showHideBtn.textContent = 'Hide';
}
setHeight();
} }
function saveSeries() { function retrieveBooks() {
const selectedType = document.querySelector('#referenceType').value;
if (!selectedType) { return; }
var bookList = document.querySelector('#referenceBook');
bookList.style.display = "block";
bookList.innerHTML = '';
if (selectedType == 'bible') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in BOOKS.bible) {
var newBook = document.createElement("option");
newBook.text = BOOKS.bible[x];
bookList.appendChild(newBook);
}
} else if (selectedType == 'creed') {
var none = document.createElement('option');
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in BOOKS.creed) {
var newBook = document.createElement('option');
newBook.value = x;
newBook.text = BOOKS.creed[x];
bookList.appendChild(newBook);
}
} else if (selectedType == 'cd') {
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x in BOOKS.cd) {
var newBook = document.createElement("option");
newBook.text = BOOKS.cd[x];
bookList.appendChild(newBook);
}
} else {
var min = BOOKS[selectedType][0];
var max = BOOKS[selectedType][1];
var none = document.createElement("option");
none.value = '';
none.text = '-- Select --';
bookList.appendChild(none);
for (var x = min; x <= max; x++) {
var newBook = document.createElement("option");
newBook.value = x;
newBook.text = x;
bookList.appendChild(newBook);
}
}
} }
function retrieveSpeaker() { function retrieveReference(el) {
fetch('/index.php/get-reference', {
method: "POST",
header: {
"Content-Type": "application/json"
},
body: JSON.stringify({
file: el.value,
type: el.options[el.selectedIndex].getAttribute('type')
})
})
.then(response => response.json())
.then(results => {
document.querySelector('#reference').value = results.text;
});
} }
function saveSpeaker() { function saveReference() {
var select = document.querySelector('#references');
fetch('/index.php/save-reference', {
method: 'POST',
header: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: select.options[select.selectedIndex].getAttribute('type'),
file: select.value,
text: document.querySelector('#reference').value
})
})
.then(response => response.json())
.then(results => {
alert(results.msg);
document.querySelector('#reference').value = '';
document.querySelector('#references').value = '';
});
} }
function referenceEditor() { function previewNote() {
var noteText = document.querySelector('#notes');
var notePreview = document.querySelector('#notePreview');
var previewButton = document.querySelector('#previewBtn');
//notePreview.innerHTML = converter.makeHtml(noteText.value);
notePreview.innerHTML = markdownit.render(noteText.value);
if (previewButton.value == 'Preview') {
previewButton.value = 'Hide Preview';
noteText.style.display = 'none';
notePreview.style.display = 'block';
} else {
previewButton.value = 'Preview';
noteText.style.display = 'block';
notePreview.style.display = 'none';
}
findLinks();
}
function findLinks() {
var links = document.querySelector('#notePreview').querySelectorAll('a');
alert(links.length);
}
function showSearchNote(event) {
event.preventDefault();
var searchNote = document.querySelector('#noteSearch');
if (searchNote.style.display == 'none') {
searchNote.style.display = 'block';
} else {
searchNote.style.display = 'none';
}
}
function searchNote() {
const search = document.querySelector('#noteSearchQuery');
fetch('/index.php/search-note', {
method: 'POST',
header: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"search": search.value
})
})
.then(response => response.json())
.then(result => {
document.querySelector('#notes').value = result.text;
document.querySelector('#passage').value = result.passage;
document.querySelector('#series').value = result.series.id;
document.querySelector('#speaker').value = result.speaker.id;
document.querySelector('#noteTitle').value = result.title;
document.querySelector('#noteDate').value = result.date;
document.querySelector('#noteId').value = result.id;
document.querySelector('#noteSearch').style.display = 'none';
link.click();
});
} }

View File

@ -0,0 +1,15 @@
# The Apostle's Creed
## Introduction
The Apostle's Creed is so called, not because it was produced by the apostles themselves, but because it contains a concise summary of their teachings. Its chief tenets can be traced to specific New Testament texts, such as Matthew 1:18; 16:16; 28:19; Luke 1:35; 23:43; 1 Corinthians 15:35; 15:20. As has been well said, it sets forth biblical doctrine “in sublime simplicity, in unsurpassable brevity, in the most beautiful order, and with liturgical solemnity.”<sup>1</sup> This creed originated as a baptismal confession, probably in the second century, and developed into its present form by the sixth or seventh century, being the culmination of several centuries of reflection. The creed is Trinitarian in structure and accents Gods operations for our salvation. More than any other creed of Christendom, it may justly be called an ecumenical symbol of faith.
<sup>1</sup>Philip Schaff, History of the Apostolic Church, trans. Edward D. Yeomans (New York: Charles Scribner, 1854), 568.
## The Apostles Creed
I believe in God the Father Almighty, Maker of heaven and earth.
I believe in Jesus Christ, his only begotten Son, our Lord; who was conceived by the Holy Spirit, born of the virgin Mary; suffered under Pontius Pilate; was crucified, dead, and buried; he descended into hell;1 the third day he rose again from the dead; he ascended into heaven, and sits at the right hand of God the Father Almighty; from there he shall come to judge the living and the dead.
I believe in the Holy Spirit; the holy catholic2 church; the communion of saints; the forgiveness of sins; the resurrection of the body; and the life everlasting. Amen.

View File

@ -1,15 +0,0 @@
# The Apostles Creed
## Introduction
The Apostles Creed is so called, not because it was produced by the apostles themselves, but because it contains a concise summary of their teachings. Its chief tenets can be traced to specific New Testament texts, such as Matthew 1:18; 16:16; 28:19; Luke 1:35; 23:43; 1 Corinthians 15:35; 15:20. As has been well said, it sets forth biblical doctrine “in sublime simplicity, in unsurpassable brevity, in the most beautiful order, and with liturgical solemnity.”<sup>1</sup> This creed originated as a baptismal confession, probably in the second century, and developed into its present form by the sixth or seventh century, being the culmination of several centuries of reflection. The creed is Trinitarian in structure and accents Gods operations for our salvation. More than any other creed of Christendom, it may justly be called an ecumenical symbol of faith.
<sup>1</sup>Philip Schaff, History of the Apostolic Church, trans. Edward D. Yeomans (New York: Charles Scribner, 1854), 568.
## The Apostles Creed
I believe in God the Father Almighty, Maker of heaven and earth.
I believe in Jesus Christ, his only begotten Son, our Lord; who was conceived by the Holy Spirit, born of the virgin Mary; suffered under Pontius Pilate; was crucified, dead, and buried; he descended into hell;1 the third day he rose again from the dead; he ascended into heaven, and sits at the right hand of God the Father Almighty; from there he shall come to judge the living and the dead.
I believe in the Holy Spirit; the holy catholic2 church; the communion of saints; the forgiveness of sins; the resurrection of the body; and the life everlasting. Amen.

View File

@ -1,10 +0,0 @@
<?php
$cmd = getopt('f:');
$f = $cmd['f'] ?? null;
if (!$f) {
exit(1);
}
$file = file($f);

View File

@ -0,0 +1,153 @@
<?php
namespace App\Command;
use App\Entity\Reference;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'IngestReference',
aliases: ['app:ingest-ref'],
description: 'Script to use to crawl a directory and ingest references',
)]
class IngestReferenceCommand extends Command
{
/**
* Files found in the directory
*
* @var array
*/
private array $files = [];
/**
* IO
*
* @var SymfonyStyle
*/
private SymfonyStyle $io;
/**
* EntityManager
*
* @var EntityManagerInterface
*/
private EntityManagerInterface $emi;
/**
* IngestReferenceCommand constructor.
*/
public function __construct(
EntityManagerInterface $emi,
private string $dir = '',
private string $name = '',
private string $type = '',
private string $label = ''
) {
parent::__construct();
$this->emi = $emi;
}
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
->addArgument('directory', InputArgument::REQUIRED, 'Directory to crawl')
->addArgument('name', InputArgument::REQUIRED, 'Name of the reference')
->addArgument('type', InputArgument::REQUIRED, 'Type of the reference')
->addArgument('label', InputArgument::REQUIRED, 'Label of the reference')
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->io = new SymfonyStyle($input, $output);
$this->dir = $input->getArgument('directory');
$this->name = $input->getArgument('name');
$this->type = $input->getArgument('type');
$this->label = $input->getArgument('label');
if (!$this->dir || !file_exists($this->dir) ||!is_dir($this->dir)) {
$this->io->error('Directory not specific or does not exist');
return Command::FAILURE;
}
if (!$this->name) {
$this->io->error('No name specified');
return Command::FAILURE;
}
if (!$this->type) {
$this->io->error('No type specified');
return Command::FAILURE;
}
if (!$this->label) {
$this->io->error('No label specified');
return Command::FAILURE;
}
$this->io->note("Crawling {$this->dir} and ingesting {$this->name} as {$this->type}:{$this->label}");
foreach ($this->getFiles() as $file) {
$ref = $this->processFile($file);
$this->emi->persist($ref);
}
$this->emi->flush();
return Command::SUCCESS;
}
public function getFiles(): array
{
$this->files = glob($this->dir . '/*.md');
if(!$this->files || count($this->files) === 0) {
$this->io->warning("No files found in this directory\n{$this->dir}");
$this->files = [];
}
return $this->files;
}
public function processFile(string $file): Reference|bool
{
$this->io->info("Processing {$file}");
$md = trim(file_get_contents($file));
$ref = new Reference();
if (!$md) {
$this->io->warning("File is empty\n{$file}");
return false;
}
$match = [];
$label = str_replace("{\$ndx}", "", $this->label);
if(preg_match("/([\d]+)/", $file, $match)) {
$ndx = ltrim($match[1], "0");
$label = str_replace("{\$ndx}", $ndx, $this->label);
$ref->setNdx($ndx);
} elseif (preg_match("/\(([^\)]+)\)/", $file, $match)) {
$label = $match[1];
}
$ref->setContent($md);
$ref->setName($this->name);
$ref->setType($this->type);
$ref->setLabel($label);
$this->io->success("Ingested {$this->name} as {$this->type}:{$label}");
return $ref;
}
}

View File

@ -2,11 +2,15 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Bible;
use DateTime;
use DateTimeZone;
use App\Entity\Series; use App\Entity\Series;
use App\Entity\Speaker; use App\Entity\Speaker;
use App\Entity\Template; use App\Entity\Template;
use App\Entity\Notes; use App\Entity\Notes;
use App\Entity\Reference;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -85,23 +89,16 @@ class AjaxController extends AbstractController
public function saveSpeaker(Request $req, EntityManagerInterface $emi): Response public function saveSpeaker(Request $req, EntityManagerInterface $emi): Response
{ {
$ret = new Response(); $ret = new Response();
$req = json_decode($req->getContent()); $data = json_decode($req->getContent());
$speaker_id = $req->speaker_id;
$speaker_name = $req->speaker_name;
if ($speaker_id) {
$speaker = $emi->getRepository(Speaker::class)->find($speaker_id);
$speaker->setName($speaker_name);
$emi->persist($speaker);
$emi->flush();
$ret->setContent('updated');
} else {
$speaker = new Speaker(); $speaker = new Speaker();
$speaker->setName($speaker_name); $speaker->setName($data->speakerName);
$emi->persist($speaker); $emi->persist($speaker);
$emi->flush(); $emi->flush();
$ret->setContent('added'); $ret->setContent(json_encode([
} 'id' => $speaker->getId(),
'msg' => $speaker->getName().' added'
]));
return $ret; return $ret;
} }
@ -129,89 +126,186 @@ class AjaxController extends AbstractController
public function saveSeries(Request $req, EntityManagerInterface $emi): Response public function saveSeries(Request $req, EntityManagerInterface $emi): Response
{ {
$ret = new Response(); $ret = new Response();
$req = json_decode($req->getContent()); $data = json_decode($req->getContent());
$series_id = $req->series_id;
$series_name = $req->series_name;
if ($series_id) {
$series = $emi->getRepository(Series::class)->find($series_id);
$series->setName($series_name);
$emi->persist($series);
$emi->flush();
$ret->setContent('updated');
} else {
$series = new Series(); $series = new Series();
$series->setName($series_name); $series->setName($data->seriesName);
$emi->persist($series); $emi->persist($series);
$emi->flush(); $emi->flush();
$ret->setContent('added');
} $ret->setContent(json_encode([
'id' => $series->getId(),
'msg' => $series->getName().' added'
]));
return $ret; return $ret;
} }
#[Route('/autocomplete-reference', name: 'app_autocomplete_reference')]
public function autocompleteReference(Request $req): Response
{
$res = new Response();
return $res;
}
#[Route('/retrieve-reference', name: 'app_retrive_reference')] #[Route('/retrieve-reference', name: 'app_retrive_reference')]
public function retrieveReference(Request $req): Response public function retrieveReference(Request $req, EntityManagerInterface $emi): Response
{ {
$type = null;
$search = null;
$passage = null;
$res = new Response(); $res = new Response();
$ref = json_decode($req->getContent())->reference; $data = json_decode($req->getContent());
if (count(explode(':', $ref)) > 2) { $search = $data->reference;
list($type, $search, $passage) = explode(':', $ref);
} else { $ref = new Reference();
list($type, $search) = explode(':', $ref); $ref->setType($data->type);
if((int) $data->book) {
$ref->setNdx($data->book);
} }
$ret = match(strtolower($type)) { ReferenceController::$emi = $emi;
'bible' => ReferenceController::retrieveBible("{$search}:{$passage}"),
'hc' => ReferenceController::retrieveHC($search), $ret = match(strtolower($data->type)) {
'bc' => ReferenceController::retrieveBC($search), 'bible' => ReferenceController::retrieveBible("{$data->book} {$search}"),
'dc' => ReferenceController::retrieveCD($search), 'hc' => ReferenceController::retrieveHC($ref),
'wcf' => ReferenceController::retrieveWCF($search), 'bc' => ReferenceController::retrieveBC($ref),
'wsc' => ReferenceController::retrieveWSC($search), 'cd' => ReferenceController::retrieveCD($ref),
'wlc' => ReferenceController::retrieveWLC($search), 'wcf' => ReferenceController::retrieveWCF($ref),
'creed' => ReferenceController::retrieveCreed($search) 'wsc' => ReferenceController::retrieveWSC($ref),
'wlc' => ReferenceController::retrieveWLC($ref),
'creed' => ReferenceController::retrieveCreed($data->book)
}; };
$res->setContent(json_encode(['text' => $ret, 'title' => "{$search}"])); $res->setContent(json_encode(['text' => $ret->getContent(), 'title' => "{$ret->getLabel()}"]));
return $res; return $res;
} }
#[Route('/open-note', name: 'app_open_note')] #[Route('/get-reference', name: 'app_get_reference')]
public function getReference(Request $req, EntityManagerInterface $emi): Response
{
$res = new Response();
$data = json_decode($req->getContent());
$ret = match ($data->type) {
'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}");
$res->setContent(json_encode(['text' => $fc]));
return $res;
}
#[Route('/save-reference', name: 'app_save_reference')]
public function saveReference(Request $req, EntityManagerInterface $emi): Response
{
$res = new Response();
$data = json_decode($req->getContent());
$path = match($data->type) {
'creed' => 'Creeds',
'bc' => 'Belgic',
'hc' => 'Heidelberg',
'cd' => 'Dort',
'wcf' => 'Westminster/Confessions',
'wsc' => 'Westminster/Shorter Catechism',
'wlc' => 'Westminster/Larger Catechism'
};
$ret = file_put_contents(dirname(dirname(__DIR__))."/references/{$path}/{$data->file}", $data->text);
if($ret !== false) {
$res->setContent(json_encode(['msg' => 'File Saved']));
} else {
$res->setContent(json_encode(['msg' => 'Failed to save file']));
}
return $res;
}
#[Route('/search-note', name: 'app_open_note')]
public function openNote(Request $req, EntityManagerInterface $emi): Response public function openNote(Request $req, EntityManagerInterface $emi): Response
{ {
$res = new Response(); $res = new Response();
$data = json_decode($req->getContent());
return $res; $note = $emi->getRepository(Notes::class)->findNote($data->search);
}
#[Route('/save-note', name: 'app_save_note')]
public function saveNote(Request $req, EntityManagerInterface $emi): Response
{
$res = new Response();
$note = new Notes();
$note->setTitle($req->get('title'));
$series = $emi->getRepository(Series::class)->find($req->get('series'));
$speaker = $emi->getRepository(Speaker::class)->find($req->get('speaker'));
$note->setSeries($series);
$note->setSpeaker($speaker);
$note->setText($req->get('note'));
$res->setContent(json_encode($note)); $res->setContent(json_encode($note));
return $res; return $res;
} }
#[Route('/save-note', name: 'app_save_note', methods: ['POST'])]
public function saveNote(Request $req, EntityManagerInterface $emi): Response
{
$data = json_decode($req->getContent());
$note = $emi->getRepository(Notes::class)->find($data->id);
if (!$note) {
$note = new Notes();
$note->setId($data->id);
}
$note->setTitle($data->title);
$note->setDate(new DateTime($data->date));
$series = $emi->getRepository(Series::class)->find($data->series);
$speaker = $emi->getRepository(Speaker::class)->find($data->speaker);
$note->setSeries($series);
$note->setSpeaker($speaker);
$note->setText($data->note);
$note->setPassage($data->passage);
$emi->persist($note);
$emi->flush();
$res = new Response();
$res->setContent(json_encode([
'msg' => 'saved',
'id' => $note->getId()
]));
return $res;
}
#[Route('/discard-note', name: 'app_discard_note', methods: ['POST'])]
public function discardNote(Request $req, EntityManagerInterface $emi): Response
{
$data = json_decode($req->getContent());
$note = $emi->getRepository(Notes::class)->find($data->id);
$emi->remove($note);
$emi->flush();
$res = new Response();
$res->setContent(json_encode([
'msg' => 'deleted'
]));
return $res;
}
#[Route('/get-passage/{passage}', name: 'app_get_passage')]
public function getPassage($passage, EntityManagerInterface $emi): Response
{
$passage = str_replace('+', ' ', $passage);
$book = Bible::findBook($passage);
$chapter = Bible::findChapter($passage);
$bible = new Bible();
$bible->setBook($book);
$bible->setChapter($chapter);
$verse = Bible::findVerse($passage);
$ret = $emi->getRepository(Bible::class)->findRange($bible, $verse);
if (is_array($ret)) {
$text = null;
foreach($ret as $b) {
$text .= "{$b->getVerse()}. {$b->getContent()}".PHP_EOL;
}
$bible->setContent($text);
} elseif (is_a($ret, Bible::class)) {
$bible->setContent($ret->getContent());
}
$res = new Response();
$res->setContent($bible->getContent());
return $res;
}
} }

View File

@ -5,6 +5,7 @@ namespace App\Controller;
use App\Entity\Speaker; use App\Entity\Speaker;
use App\Entity\Template; use App\Entity\Template;
use App\Entity\Series; use App\Entity\Series;
use App\Entity\Notes;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -19,12 +20,14 @@ class DefaultController extends AbstractController
$speakers = $emi->getRepository(Speaker::class)->findAll(); $speakers = $emi->getRepository(Speaker::class)->findAll();
$series = $emi->getRepository(Series::class)->findAll(); $series = $emi->getRepository(Series::class)->findAll();
$templates = $emi->getRepository(Template::class)->findAll(); $templates = $emi->getRepository(Template::class)->findAll();
$note = $emi->getRepository(Notes::class)->findLastNote();
return $this->render('default/index.html.twig', [ return $this->render('default/index.html.twig', [
'controller_name' => 'DefaultController', 'controller_name' => 'DefaultController',
'speakers' => $speakers, 'speakers' => $speakers,
'series' => $series, 'series' => $series,
'templates' => $templates 'templates' => $templates,
'noteId' => ($note->getId() + 1)
]); ]);
} }
@ -40,6 +43,32 @@ class DefaultController extends AbstractController
#[Route('/reference-editor', name: 'app_reference_editor')] #[Route('/reference-editor', name: 'app_reference_editor')]
public function referenceEditor(EntityManagerInterface $emi): Response public function referenceEditor(EntityManagerInterface $emi): Response
{ {
return $this->render('default/reference-editor.html.twig', []); $ref_dir = dirname(dirname(__DIR__)).'/references/';
$creeds = $this->stripPath(glob($ref_dir.'Creeds/*.md'));
$belgic = $this->stripPath(glob($ref_dir.'Belgic/*.md'));
$dort = $this->stripPath(glob($ref_dir.'Dort/*.md'));
$heidelberg = $this->stripPath(glob($ref_dir.'Heidelberg/*.md'));
$wcf = $this->stripPath(glob($ref_dir.'Westminster/Confessions/*.md'));
$wsc = $this->stripPath(glob($ref_dir.'Westminster/Shorter Catechism/*.md'));
$wlc = $this->stripPath(glob($ref_dir.'Westminster/Longer Catechism/*.md'));
return $this->render('default/reference-editor.html.twig', [
'creeds' => $creeds,
'belgic' => $belgic,
'heidelberg' => $heidelberg,
'dort' => $dort,
'wcf' => $wcf,
'wsc' => $wsc,
'wlc' => $wlc,
]);
}
private function stripPath(array $files): array
{
$ret = [];
foreach($files as $f) {
$ret[] = basename($f);
}
return $ret;
} }
} }

View File

@ -2,6 +2,9 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Bible;
use App\Entity\Reference;
use Doctrine\ORM\EntityManagerInterface;
use \Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use \Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/** /**
@ -9,26 +12,63 @@ use \Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
*/ */
class ReferenceController extends AbstractController class ReferenceController extends AbstractController
{ {
/**
* @var EntityManagerInterface
*/
public static EntityManagerInterface $emi;
/** /**
* Method to retrieve a Bible reference * Method to retrieve a Bible reference
* *
* @param string $ref * @param string $ref
* *
* @return string * @return Reference
*/ */
public static function retrieveBible($ref): string public static function retrieveBible($ref): Reference
{ {
if(count(explode(' ', $ref)) > 2) { $book = Bible::findBook($ref);
list($index, $book, $chapter, $passage) = preg_split("/:| /", $ref); $chapter = Bible::findChapter($ref);
$book = "{$index}{$book}"; $passage = Bible::findVerse($ref);
} else { $bible = new Bible();
list($book, $chapter, $passage) = preg_split("/:| /", $ref); $bible->setBook($book);
$bible->setChapter($chapter);
$label = null;
if (is_array($passage)) {
$passage_start = $passage[0];
$passage_end = $passage[1];
$bible = self::$emi->getRepository(Bible::class)->findRange($bible, [$passage_start, $passage_end]);
$passage = "{$passage_start}-{$passage_end}";
$label = "{$bible[0]->getLabel()} {$bible[0]->getChapter()}:{$passage}";
} elseif (is_int($passage)) {
$bible = self::$emi->getRepository(Bible::class)->findBy(['book' => $book, 'chapter' => $chapter, 'verse' => $passage]);
$label = "{$bible[0]->getLabel()} {$bible[0]->getChapter()}:{$passage}";
} elseif ($passage === false) {
$bible = self::$emi->getRepository(Bible::class)->findBy(['book' => $book, 'chapter' => $chapter]);
$label = "{$bible[0]->getLabel()} {$bible[0]->getChapter()}";
$passage = null;
} }
$file = glob(dirname(dirname(__DIR__))."/references/Bible/* - {$book}/{$book}{$chapter}.md"); if(is_array($bible)) {
$res = implode("\n", file(current($file))); $text = [];
foreach($bible as $b) {
$text[] = "{$b->getVerse()}. {$b->getContent()}";
}
} else {
$text[] = "{$bible->getVerse()}. {$bible->getContent()}";
}
return $res; $reference = "{$book} {$chapter}".($passage === null ? '' : ":{$passage}");
$ref = new Reference();
$ref->setType('bible');
$ref->setName($reference);
$ref->setLabel($label);
$ref->setContent("# {$reference}\n\n".implode("\n", $text));
return $ref;
} }
/** /**
@ -36,9 +76,9 @@ class ReferenceController extends AbstractController
* *
* @param string * @param string
* *
* @return string * @return Reference
*/ */
public static function retrieveCreed($ref) public static function retrieveCreed($ref): Reference
{ {
$file = match($ref) { $file = match($ref) {
'apc' => "Apostle's Creed.md", 'apc' => "Apostle's Creed.md",
@ -48,58 +88,86 @@ class ReferenceController extends AbstractController
'nc' => 'Nicene Creed.md' 'nc' => 'Nicene Creed.md'
}; };
return implode("\n", file(dirname(dirname(__DIR__))."/references/Creeds/{$file}")); $r = self::$emi->getRepository(Reference::class)->findBy(['label' => $ref]);
$ref = $r[0];
return $ref;
} }
/** /**
* Method to retrieve a Heidelberg Catechism reference * Method to retrieve a Heidelberg Catechism reference
* *
* @param string $ref * @param Reference $ref
* *
* @return string * @return Reference
*/ */
public static function retrieveHC($ref) public static function retrieveHC($ref): Reference
{ {
$ref = strtoupper($ref); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
return implode("\n", file(dirname(dirname(__DIR__))."/references/Heidelberg/{$ref}.md")); return $r[0];
} }
/** /**
* Method to retrieve a Belgian Catechism reference * Method to retrieve a Belgian Catechism reference
* *
* @param string $ref * @param Reference $ref
* *
* @return string * @return Reference
*/ */
public static function retrieveBC($ref) public static function retrieveBC($ref): Reference
{ {
$ref = ucfirst($ref); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
return implode("\n", file(dirname(dirname(__DIR__))."/references/Belgic/{$ref}.md")); return $r[0];
} }
public static function retrieveCD($ref) /**
* Method to retrieve the Canon of Dort reference
*
* @param Reference $ref
*
* @return Reference
*/
public static function retrieveCD($ref): Reference
{ {
$ref = strtoupper($ref); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
return implode("\n", file(dirname(dirname(__DIR__))."/references/Dort/{$ref}.md")); return $r[0];
} }
public static function retrieveWSC($ref) /**
* Method to retrieve a WSC reference
*
* @param Reference $ref
*
* @return Reference
*/
public static function retrieveWSC($ref): Reference
{ {
$art = str_pad($ref, 3, '0', STR_PAD_LEFT); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
$files = glob(dirname(dirname(__DIR__))."/references/Westminster/Shorter Catechism/WSC{$art}.md"); return $r[0];
return implode("\n", file(current($files)));
} }
public static function retrieveWLC($ref) /**
* Method to retrieve a WLC reference
*
* @param Reference $ref
*
* @return Reference
*/
public static function retrieveWLC($ref): Reference
{ {
$art = str_pad($ref, 3, '0', STR_PAD_LEFT); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
$files = glob(dirname(dirname(__DIR__))."/references/Westminster/Larger Catechism/WLC{$art}.md"); return $r[0];
return implode("\n", file(current($files)));
} }
public static function retrieveWCF($ref) /**
* Method to retrieve a WCF reference
*
* @param Reference $ref
*
* @return Reference
*/
public static function retrieveWCF($ref): Reference
{ {
$files = glob(dirname(dirname(__DIR__))."/references/Westminster/Confessions/Chapter {$ref}.md"); $r = self::$emi->getRepository(Reference::class)->findBy(['type' => $ref->getType(), 'ndx' => $ref->getNdx()]);
return implode("\n", file(current($files))); return $r[0];
} }
} }

159
src/Entity/Bible.php Normal file
View File

@ -0,0 +1,159 @@
<?php
namespace App\Entity;
use App\Repository\BibleRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: BibleRepository::class)]
class Bible
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $book = null;
#[ORM\Column]
private ?int $chapter = null;
#[ORM\Column]
private ?int $verse = null;
#[ORM\Column(length: 4096)]
private ?string $content = null;
#[ORM\Column]
private ?int $book_index = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $label = null;
public function getId(): ?int
{
return $this->id;
}
public function getBook(): ?string
{
return $this->book;
}
public function setBook(string $book): static
{
$this->book = $book;
return $this;
}
public function getChapter(): ?int
{
return $this->chapter;
}
public function setChapter(int $chapter): static
{
$this->chapter = $chapter;
return $this;
}
public function getVerse(): ?int
{
return $this->verse;
}
public function setVerse(int $verse): static
{
$this->verse = $verse;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): static
{
$this->content = $content;
return $this;
}
public function getBookIndex(): ?int
{
return $this->book_index;
}
public function setBookIndex(int $book_index): static
{
$this->book_index = $book_index;
return $this;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(?string $label): static
{
$this->label = $label;
return $this;
}
public static function findBook(string $reference): string
{
$book = '';
$tmp = explode(' ', $reference);
$book = "{$tmp[0]}";
if(count($tmp) > 2) {
$book = "{$tmp[0]}{$tmp[1]}";
}
return $book;
}
public static function findChapter(string $reference): string
{
$chapter = '';
$tmp = explode(' ', $reference);
if(count($tmp) > 2) {
$passage = $tmp[2];
} else {
$passage = $tmp[1];
}
$tmp = explode(':', $passage);
$chapter = $tmp[0];
return $chapter;
}
public static function findVerse(string $reference): int|array|bool
{
$verses = null;
$semicolon = strpos($reference, ':');
if ($semicolon === false) {
return false;
}
$tmp = substr($reference, $semicolon + 1);
if(strpos($tmp, '-') !== false) {
$verses = explode('-', $tmp);
} else {
$verses = (int) $tmp;
}
return $verses;
}
}

154
src/Entity/Notes.php Normal file
View File

@ -0,0 +1,154 @@
<?php
namespace App\Entity;
use Doctrine\DBAL\Types\Types;
use JsonSerializable;
use App\Repository\NotesRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: NotesRepository::class)]
class Notes implements JsonSerializable
{
#[ORM\Id()]
#[ORM\Column(type: Types::INTEGER)]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
#[ORM\ManyToOne(inversedBy: 'notes')]
#[ORM\JoinColumn(nullable: false)]
private ?Speaker $speaker = null;
#[ORM\ManyToOne(inversedBy: 'notes')]
private ?Series $series = null;
#[ORM\Column(length: 4096)]
private ?string $text = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $date = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $passage = null;
/**
* Retrieves the ID of the object.
*
* @return int|null The ID of the object, or null if it is not set.
*/
public function getId(): ?int
{
return $this->id;
}
/**
* Sets the ID of the object.
*
* @param int $id The ID to set.
* @return static
*/
public function setId(int $id): static
{
$this->id = $id;
return $this;
}
/**
* Retrieves the title of the object.
*
* @return string|null The title of the object, or null if it is not set.
*/
public function getTitle(): ?string
{
return $this->title;
}
/**
* Sets the title of the object.
*
* @param string $title The title to set.
* @return static
*/
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): static
{
$this->date = $date;
return $this;
}
public function getSpeaker(): ?Speaker
{
return $this->speaker;
}
public function setSpeaker(?Speaker $speaker): static
{
$this->speaker = $speaker;
return $this;
}
public function getSeries(): ?Series
{
return $this->series;
}
public function setSeries(?Series $series): static
{
$this->series = $series;
return $this;
}
public function getText(): ?string
{
return $this->text;
}
public function setText(?string $text): static
{
$this->text = $text;
return $this;
}
public function getPassage(): ?string
{
return $this->passage;
}
public function setPassage(?string $passage): static
{
$this->passage = $passage;
return $this;
}
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'speaker' => $this->speaker,
'series' => $this->series,
'text' => $this->text,
'passage' => $this->passage,
'date' => $this->date->format('Y-m-d'),
];
}
}

180
src/Entity/Reference.php Normal file
View File

@ -0,0 +1,180 @@
<?php
namespace App\Entity;
use JsonSerializable;
use App\Repository\ReferenceRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ReferenceRepository::class)]
class Reference implements JsonSerializable
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 64)]
private ?string $type = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 10)]
private ?string $label = null;
#[ORM\Column(nullable: true)]
private ?int $ndx = null;
#[ORM\Column(length: 65535)]
private ?string $content = null;
/**
* Getter method for id.
*
* @return int
*/
public function getId(): ?int
{
return $this->id;
}
/**
* Getter method for type.
*
* @return string
*/
public function getType(): ?string
{
return $this->type;
}
/**
* Setter method for type.
*
* @param string $type
*
* @return Reference
*/
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
/**
* Getter method for name.
*
* @return string
*/
public function getName(): ?string
{
return $this->name;
}
/**
* Setter method for name.
*
* @param string $name
*
* @return Reference
*/
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/**
* Getter method for label.
*
* @return string
*/
public function getLabel(): ?string
{
return $this->label;
}
/**
* Setter method for label.
*
* @param string $label
*
* @return Reference
*/
public function setLabel(string $label): static
{
$this->label = $label;
return $this;
}
/**
* Getter method for ndx.
*
* @return int
*/
public function getNdx(): ?int
{
return $this->ndx;
}
/**
* Setter method for ndx.
*
* @param int $ndx
*
* @return Reference
*/
public function setNdx(int $ndx): static
{
$this->ndx = $ndx;
return $this;
}
/**
* Getter method for content.
*
* @return string
*/
public function getContent(): ?string
{
return $this->content;
}
/**
* Setter method for content.
*
* @param string $content
*
* @return Reference
*/
public function setContent(string $content): static
{
$this->content = $content;
return $this;
}
/**
* @inheritDoc
*
* @codeCoverageIgnore
*/
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'type' => $this->type,
'name' => $this->name,
'label' => $this->label,
'ndx' => $this->ndx,
'text' => $this->content,
];
}
}

102
src/Entity/Series.php Normal file
View File

@ -0,0 +1,102 @@
<?php
namespace App\Entity;
use JsonSerializable;
use App\Repository\SeriesRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: SeriesRepository::class)]
class Series implements JsonSerializable
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 64)]
private ?string $name = null;
/**
* @var Collection<int, Notes>
*/
#[ORM\OneToMany(targetEntity: Notes::class, mappedBy: 'series')]
private Collection $notes;
#[ORM\ManyToOne(inversedBy: 'series')]
private ?Template $template = null;
public function __construct()
{
$this->notes = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/**
* @return Collection<int, Notes>
*/
public function getNotes(): Collection
{
return $this->notes;
}
public function addNote(Notes $note): static
{
if (!$this->notes->contains($note)) {
$this->notes->add($note);
$note->setSeries($this);
}
return $this;
}
public function removeNote(Notes $note): static
{
if ($this->notes->removeElement($note)) {
// set the owning side to null (unless already changed)
if ($note->getSeries() === $this) {
$note->setSeries(null);
}
}
return $this;
}
public function getTemplate(): ?Template
{
return $this->template;
}
public function setTemplate(?Template $template): static
{
$this->template = $template;
return $this;
}
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}

87
src/Entity/Speaker.php Normal file
View File

@ -0,0 +1,87 @@
<?php
namespace App\Entity;
use JsonSerializable;
use App\Repository\SpeakerRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: SpeakerRepository::class)]
class Speaker implements JsonSerializable
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
/**
* @var Collection<int, Notes>
*/
#[ORM\OneToMany(targetEntity: Notes::class, mappedBy: 'speaker')]
private Collection $notes;
public function __construct()
{
$this->notes = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
/**
* @return Collection<int, Notes>
*/
public function getNotes(): Collection
{
return $this->notes;
}
public function addNote(Notes $note): static
{
if (!$this->notes->contains($note)) {
$this->notes->add($note);
$note->setSpeaker($this);
}
return $this;
}
public function removeNote(Notes $note): static
{
if ($this->notes->removeElement($note)) {
// set the owning side to null (unless already changed)
if ($note->getSpeaker() === $this) {
$note->setSpeaker(null);
}
}
return $this;
}
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}

93
src/Entity/Template.php Normal file
View File

@ -0,0 +1,93 @@
<?php
namespace App\Entity;
use App\Repository\TemplateRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: TemplateRepository::class)]
class Template
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 2049)]
private ?string $value = null;
/**
* @var Collection<int, Series>
*/
#[ORM\OneToMany(targetEntity: Series::class, mappedBy: 'template')]
private Collection $series;
public function __construct()
{
$this->series = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getValue(): ?string
{
return $this->value;
}
public function setValue(string $value): static
{
$this->value = $value;
return $this;
}
/**
* @return Collection<int, Series>
*/
public function getSeries(): Collection
{
return $this->series;
}
public function addSeries(Series $series): static
{
if (!$this->series->contains($series)) {
$this->series->add($series);
$series->setTemplate($this);
}
return $this;
}
public function removeSeries(Series $series): static
{
if ($this->series->removeElement($series)) {
// set the owning side to null (unless already changed)
if ($series->getTemplate() === $this) {
$series->setTemplate(null);
}
}
return $this;
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace App\Repository;
use App\Entity\Bible;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\EntityManager;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Bible>
*
* @method Bible|null find($id, $lockMode = null, $lockVersion = null)
* @method Bible|null findOneBy(array $criteria, array $orderBy = null)
* @method Bible[] findAll()
* @method Bible[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class BibleRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Bible::class);
}
public function findRange(Bible $bible, array $passage): array
{
return $this->createQueryBuilder('b')
->andWhere('b.book = :book')
->andWhere('b.chapter = :chapter')
->andWhere('b.verse BETWEEN :verseStart AND :verseEnd')
->setParameter('book', $bible->getBook())
->setParameter('chapter', $bible->getChapter())
->setParameter('verseStart', $passage[0])
->setParameter('verseEnd', $passage[1])
->getQuery()
->getResult();
}
// /**
// * @return Bible[] Returns an array of Bible objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('b.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Bible
// {
// return $this->createQueryBuilder('b')
// ->andWhere('b.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\Repository;
use App\Entity\Notes;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Notes>
*
* @method Notes|null find($id, $lockMode = null, $lockVersion = null)
* @method Notes|null findOneBy(array $criteria, array $orderBy = null)
* @method Notes[] findAll()
* @method Notes[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class NotesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Notes::class);
}
/**
* @return Notes
*/
public function findLastNote(): Notes
{
$qb = $this->createQueryBuilder('n')
->orderBy('n.id', 'DESC')
->setMaxResults(1);
$query = $qb->getQuery();
$note = $query->getOneOrNullResult();
if (!$note) {
$note = new Notes();
$note->setId(0);
}
return $note;
}
public function findNote($data): Notes
{
$qb = $this->createQueryBuilder('notes');
$qb->select('n')
->from('\App\Entity\Notes', 'n')
->where("n.title LIKE ?1")
->orWhere('n.passage LIKE ?1')
->orWhere('n.text LIKE ?1')
->setParameter(1, "%{$data}%")
->setMaxResults(1);
$query = $qb->getQuery();
$res = $query->getSingleResult();
return $res;
}
// /**
// * @return Notes[] Returns an array of Notes objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('n')
// ->andWhere('n.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('n.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Notes
// {
// return $this->createQueryBuilder('n')
// ->andWhere('n.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Repository;
use App\Entity\Reference;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Reference>
*
* @method Reference|null find($id, $lockMode = null, $lockVersion = null)
* @method Reference|null findOneBy(array $criteria, array $orderBy = null)
* @method Reference[] findAll()
* @method Reference[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ReferenceRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Reference::class);
}
// /**
// * @return Reference[] Returns an array of Reference objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('r')
// ->andWhere('r.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('r.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Reference
// {
// return $this->createQueryBuilder('r')
// ->andWhere('r.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Repository;
use App\Entity\Series;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Series>
*
* @method Series|null find($id, $lockMode = null, $lockVersion = null)
* @method Series|null findOneBy(array $criteria, array $orderBy = null)
* @method Series[] findAll()
* @method Series[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class SeriesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Series::class);
}
public function findAll(): array
{
return $this->findBy([], ['name' => 'ASC']);
}
// /**
// * @return Series[] Returns an array of Series objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('s.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Series
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Repository;
use App\Entity\Speaker;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Speaker>
*
* @method Speaker|null find($id, $lockMode = null, $lockVersion = null)
* @method Speaker|null findOneBy(array $criteria, array $orderBy = null)
* @method Speaker[] findAll()
* @method Speaker[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class SpeakerRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Speaker::class);
}
public function findAll(): array
{
return $this->findBy([], ['name' => 'ASC']);
}
// /**
// * @return Speaker[] Returns an array of Speaker objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('s.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Speaker
// {
// return $this->createQueryBuilder('s')
// ->andWhere('s.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Repository;
use App\Entity\Template;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Template>
*
* @method Template|null find($id, $lockMode = null, $lockVersion = null)
* @method Template|null findOneBy(array $criteria, array $orderBy = null)
* @method Template[] findAll()
* @method Template[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class TemplateRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Template::class);
}
// /**
// * @return Template[] Returns an array of Template objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('t')
// ->andWhere('t.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('t.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Template
// {
// return $this->createQueryBuilder('t')
// ->andWhere('t.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -3,15 +3,14 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title> <title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>"> <!--<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">-->
{% block stylesheets %} {% block stylesheets %}
{% endblock %} {% endblock %}
</head>
<body onload='setHeight()' onresize='setHeight()'>
{% block body %}{% endblock %}
{% block javascripts %} {% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %} {% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %} {% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body> </body>
</html> </html>

View File

@ -0,0 +1,108 @@
{% extends 'base.html.twig' %}
{% block title %}Notes{% endblock %}
{% block stylesheets %}
<link href='/css/style.css' rel='stylesheet' />
{% endblock %}
{% block javascripts %}
<script src='/js/data.js'></script>
<script src='/js/script.js'></script>
<script src="https://kit.fontawesome.com/f15a79324f.js" crossorigin="anonymous"></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='https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js'></script>
{% endblock %}
{% block body %}
<main class="container">
<section class="top-tab">
<i class="fa fa-bars hamburger" aria-hidden="true"></i>
<ul class="hamburger-list" style="display: none">
<li><a href="#">New Note</a></li>
<li><a href="#" onclick='showSearchNote(event)'>Open Note</a></li>
<li><a href="#" onclick="saveNote();link.click();">Save Note</a></li>
<li><a href='#' onclick='discardNote()'>Discard Note</a></li>
<li><hr/></li>
<li><a href='/index.php/reference-editor'>Reference Editor</a></li>
<li><a href='#' onclick="openRef()">Open Reference</a></li>
<li><hr/></li>
<li><a href='/index.php/template-editor'>Template Editor</a></li>
</ul>&nbsp;&nbsp;
<i id='save-check' class='fa fa-check' style='opacity:0;'></i>
<div id='res'></div>
</section>
<section class="ref-tab">
<ul id='ref-list'>
</ul>
</section>
<section class="ref">
<h2>Reference</h2>
<div id="ref"></div>
</section>
<section class="notes">
<div id='note-header-left'>
<h2>Notes</h2>
<button id='show-hide-btn' onclick='toggleFields()'>Show</button>
</div>
<div id='note-header-right'>
<select id='template' onchange="retrieveTemplate('template','notes')">
<option value=0>-- Template --</option>
{% for t in templates %}
<option value="{{ t.id }}">{{ t.name }}</option>
{% endfor %}
</select>
<input type="button" id="previewBtn" value="Preview" onclick='previewNote()'><br />
</div>
<div id='fields-container'>
<input type="hidden" id="noteId" value="{{ noteId }}" />
<input type="text" id="noteTitle" placeholder="Title..." />
<input type='date' id='noteDate' />
<input type='text' id='newSpeaker' placeholder='Name...' onkeyup='saveSpeaker(event)' />
<select id="speaker" onchange='newSpeaker()'>
<option value=0>-- Speaker --</option>
<option value='new'>New Speaker</option>
{% for s in speakers %}
<option value='{{ s.id }}'>{{ s.name }}</option>
{% endfor %}
</select>
<input type='text' id='newSeries' placeholder='Series...' onkeyup='saveSeries(event)' />
<select id="series" onchange='newSeries()'>
<option value=0>-- Series --</option>
<option value='new'>New Series</option>
{% for s in series %}
<option value='{{ s.id }}'>{{ s.name }}</option>
{% endfor %}
</select>
<input type='text' id='passage' placeholder='Passage...' />
</div>
<textarea id="notes" wrap="hard"></textarea>
<div id='notePreview'></div>
</section>
</main>
<div id="refQuery">
<select id='referenceType' onchange='retrieveBooks()'>
<option>-- Select --</option>
<option value='bible'>Bible</option>
<option value='creed'>Creed</option>
<option value='bc'>Belgic</option>
<option value='hc'>Heidelberg</option>
<option value='cd'>Canons of Dort</option>
<option value='wcf'>Westminster CF</option>
<option value='wsc'>Shorter Catechism</option>
<option value='wlc'>Larger Catechism</option>
</select>
<select id='referenceBook' style='display:none;'>
</select><br/>
<input type="text" id="search" placeholder="Search"><br />
<button id="searchBtn" onclick="queryRef()">Search</button>
</div>
<div id='noteSearch'>
<input type='text' id='noteSearchQuery' placeholder='Search...' /><br/>
<button id='noteSearchButton' onclick='searchNote()'>Search</button>
</div>
{% endblock %}

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Reference Editor</title>
</head>
<body>
<select id='references' style='height:50px;' size='20' onchange='retrieveReference(this)'>
<option value=''>-- Select Reference --</option>
<optgroup id='creeds' label='Creeds'>
{% for c in creeds %}
<option type='creed'>{{ c }}</option>
{% endfor %}
</optgroup>
<optgroup id='belgic' label='Belgic Confession'>
{% for c in belgic %}
<option type='bc'>{{ c }}</option>
{% endfor %}
</optgroup>
<optgroup id='heidelberg' label='Heidelberg Catechism'>
{% for c in heidelberg %}
<option type='hc'>{{ c }}</option>
{% endfor %}
</optgroup>
<optgroup id='dort' label='Canons of Dort'>
{% for c in dort %}
<option type='cd'>{{ c }}</option>
{% 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>
<a href='/index.php/'>Back</a><br />
<textarea id='reference' name='reference' rows=50 cols=50></textarea>
<script src='/js/script.js'></script>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Series Editor</title>
</head>
<body>
<select id='series' onchange='retrieveSeries()'>
<option value='0'>-- Series --</option>
{% for s in series %}
<option value='{{ s.id }}'>{{ s.name }}</option>
{% endfor %}
</select>&nbsp;&nbsp;
<input type='text' name='series_name' id='series_name' />&nbsp;&nbsp;
<input type='button' name='save' value='Save' onclick='saveSeries()' />&nbsp;&nbsp;
<a href='/index.php/'>Back</a>
<script src='/js/script.js'></script>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Speaker Editor</title>
</head>
<body>
<select name='speaker_id' id='speaker_id' onchange='retrieveSpeaker()'>
<option value='0'>-- Speaker --</option>
{% for s in speakers %}
<option value='{{ s.id }}'>{{ s.name }}</option>
{% endfor %}
</select>&nbsp;&nbsp;
<input type='text' name='speaker_name' id='speaker_name' />&nbsp;&nbsp;
<input type='button' name='save' value='Save' onclick='saveSpeaker()' />&nbsp;&nbsp;
<a href='/index.php/'>Back</a>
<script src='/js/script.js'></script>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>Template Editor</title>
</head>
<body>
<form>
<select id='template_id' name='template_id' onchange="retrieveTemplate('template_id','template_value')">
<option value='0'>-- Templates --</option>
{% for t in templates %}
<option value='{{ t.id }}'>{{ t.name }}</option>
{% endfor %}
</select>&nbsp;&nbsp;
<input type='text' name='name' id='template_name' />&nbsp;&nbsp;
<input type='button' name='submit' value='Save' onclick='saveTemplate()' />&nbsp;&nbsp;
<a href='/index.php/'>Back</a>
<br />
<textarea id='template_value' name='template' wrap='hard' cols=100 rows=50></textarea>
</form>
<script src='/js/script.js'></script>
</body>
</html>