mirror of
https://github.com/standardebooks/web.git
synced 2025-07-05 06:10:36 -04:00
Completely type hint template functions and switch to named arguments
This commit is contained in:
parent
6108b5e53d
commit
124e8343fc
125 changed files with 542 additions and 450 deletions
|
@ -9,10 +9,6 @@ parameters:
|
||||||
checkInternalClassCaseSensitivity: true
|
checkInternalClassCaseSensitivity: true
|
||||||
checkTooWideReturnTypesInProtectedAndPublicMethods: true
|
checkTooWideReturnTypesInProtectedAndPublicMethods: true
|
||||||
|
|
||||||
ignoreErrors:
|
|
||||||
# Ignore errors caused by `Template` static class reflection.
|
|
||||||
- '#Call to an undefined static method Template::[a-zA-Z0-9\\_]+\(\)\.#'
|
|
||||||
|
|
||||||
bootstrapFiles:
|
bootstrapFiles:
|
||||||
- %rootDir%/../../../lib/Constants.php
|
- %rootDir%/../../../lib/Constants.php
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,9 @@ class AtomFeed extends Feed{
|
||||||
|
|
||||||
protected function GetXmlString(): string{
|
protected function GetXmlString(): string{
|
||||||
if(!isset($this->_XmlString)){
|
if(!isset($this->_XmlString)){
|
||||||
$feed = Template::AtomFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'subtitle' => $this->Subtitle, 'updated' => $this->Updated, 'entries' => $this->Entries]);
|
/** @var array<Ebook> $entries */
|
||||||
|
$entries = $this->Entries;
|
||||||
|
$feed = Template::AtomFeed(id: $this->Id, url: $this->Url, title: $this->Title, subtitle: $this->Subtitle, updated: $this->Updated, entries: $entries);
|
||||||
|
|
||||||
$this->_XmlString = $this->CleanXmlString($feed);
|
$this->_XmlString = $this->CleanXmlString($feed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,8 +98,8 @@ class NewsletterSubscription{
|
||||||
$em->ToName = $this->User->Name;
|
$em->ToName = $this->User->Name;
|
||||||
}
|
}
|
||||||
$em->Subject = 'Action required: confirm your newsletter subscription';
|
$em->Subject = 'Action required: confirm your newsletter subscription';
|
||||||
$em->Body = Template::EmailNewsletterConfirmation(['subscription' => $this, 'isSubscribedToSummary' => $this->IsSubscribedToSummary, 'isSubscribedToNewsletter' => $this->IsSubscribedToNewsletter]);
|
$em->Body = Template::EmailNewsletterConfirmation(subscription: $this, isSubscribedToSummary: $this->IsSubscribedToSummary, isSubscribedToNewsletter: $this->IsSubscribedToNewsletter);
|
||||||
$em->TextBody = Template::EmailNewsletterConfirmationText(['subscription' => $this, 'isSubscribedToSummary' => $this->IsSubscribedToSummary, 'isSubscribedToNewsletter' => $this->IsSubscribedToNewsletter]);
|
$em->TextBody = Template::EmailNewsletterConfirmationText(subscription: $this, isSubscribedToSummary: $this->IsSubscribedToSummary, isSubscribedToNewsletter: $this->IsSubscribedToNewsletter);
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
<?
|
<?
|
||||||
|
/**
|
||||||
|
* @property array<Ebook> $Entries
|
||||||
|
*/
|
||||||
class OpdsAcquisitionFeed extends OpdsFeed{
|
class OpdsAcquisitionFeed extends OpdsFeed{
|
||||||
public bool $IsCrawlable;
|
public bool $IsCrawlable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<Ebook> $entries
|
||||||
|
*/
|
||||||
public function __construct(string $title, string $subtitle, string $url, string $path, array $entries, ?OpdsNavigationFeed $parent, bool $isCrawlable = false){
|
public function __construct(string $title, string $subtitle, string $url, string $path, array $entries, ?OpdsNavigationFeed $parent, bool $isCrawlable = false){
|
||||||
parent::__construct($title, $subtitle, $url, $path, $entries, $parent);
|
parent::__construct($title, $subtitle, $url, $path, $entries, $parent);
|
||||||
$this->IsCrawlable = $isCrawlable;
|
$this->IsCrawlable = $isCrawlable;
|
||||||
|
@ -13,6 +19,6 @@ class OpdsAcquisitionFeed extends OpdsFeed{
|
||||||
// *******
|
// *******
|
||||||
|
|
||||||
protected function GetXmlString(): string{
|
protected function GetXmlString(): string{
|
||||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsAcquisitionFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'parentUrl' => $this->Parent ? $this->Parent->Url : null, 'updated' => $this->Updated, 'isCrawlable' => $this->IsCrawlable, 'subtitle' => $this->Subtitle, 'entries' => $this->Entries]));
|
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsAcquisitionFeed(id: $this->Id, url: $this->Url, title: $this->Title, parentUrl: $this->Parent->Url ?? '', updated: $this->Updated, isCrawlable: $this->IsCrawlable, subtitle: $this->Subtitle, entries: $this->Entries));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
use function Safe\file_put_contents;
|
use function Safe\file_put_contents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property array<Ebook|OpdsNavigationEntry> $Entries
|
||||||
|
*/
|
||||||
abstract class OpdsFeed extends AtomFeed{
|
abstract class OpdsFeed extends AtomFeed{
|
||||||
public ?OpdsNavigationFeed $Parent = null;
|
public ?OpdsNavigationFeed $Parent = null;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
use function Safe\file_get_contents;
|
use function Safe\file_get_contents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property array<OpdsNavigationEntry> $Entries
|
||||||
|
*/
|
||||||
class OpdsNavigationFeed extends OpdsFeed{
|
class OpdsNavigationFeed extends OpdsFeed{
|
||||||
/**
|
/**
|
||||||
* @param array<OpdsNavigationEntry> $entries
|
* @param array<OpdsNavigationEntry> $entries
|
||||||
|
@ -38,6 +41,6 @@ class OpdsNavigationFeed extends OpdsFeed{
|
||||||
// *******
|
// *******
|
||||||
|
|
||||||
protected function GetXmlString(): string{
|
protected function GetXmlString(): string{
|
||||||
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsNavigationFeed(['id' => $this->Id, 'url' => $this->Url, 'title' => $this->Title, 'parentUrl' => $this->Parent ? $this->Parent->Url : null, 'updated' => $this->Updated, 'subtitle' => $this->Subtitle, 'entries' => $this->Entries]));
|
return $this->_XmlString ??= $this->CleanXmlString(Template::OpdsNavigationFeed(id: $this->Id, url: $this->Url, title: $this->Title, parentUrl: $this->Parent->Url ?? '', updated: $this->Updated, subtitle: $this->Subtitle, entries: $this->Entries));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,8 +83,8 @@ class Patron{
|
||||||
$em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS;
|
$em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS;
|
||||||
$em->FromName = EDITOR_IN_CHIEF_NAME;
|
$em->FromName = EDITOR_IN_CHIEF_NAME;
|
||||||
$em->Subject = 'Thank you for supporting Standard Ebooks!';
|
$em->Subject = 'Thank you for supporting Standard Ebooks!';
|
||||||
$em->Body = Template::EmailPatronsCircleWelcome(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]);
|
$em->Body = Template::EmailPatronsCircleWelcome(isAnonymous: $this->IsAnonymous, isReturning: $isReturning);
|
||||||
$em->TextBody = Template::EmailPatronsCircleWelcomeText(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]);
|
$em->TextBody = Template::EmailPatronsCircleWelcomeText(isAnonymous: $this->IsAnonymous, isReturning: $isReturning);
|
||||||
$em->Send();
|
$em->Send();
|
||||||
|
|
||||||
if(!$isReturning){
|
if(!$isReturning){
|
||||||
|
@ -92,8 +92,8 @@ class Patron{
|
||||||
$em->To = ADMIN_EMAIL_ADDRESS;
|
$em->To = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->Subject = 'New Patrons Circle member';
|
$em->Subject = 'New Patrons Circle member';
|
||||||
$em->Body = Template::EmailAdminNewPatron(['patron' => $this, 'payment' => $this->User->Payments[0]]);
|
$em->Body = Template::EmailAdminNewPatron(patron: $this, payment: $this->User->Payments[0]);
|
||||||
$em->TextBody = Template::EmailAdminNewPatronText(['patron' => $this, 'payment' => $this->User->Payments[0]]);;
|
$em->TextBody = Template::EmailAdminNewPatronText(patron: $this, payment: $this->User->Payments[0]);;
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,8 +134,8 @@ class Patron{
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// Email one time donors who have expired after one year.
|
// Email one time donors who have expired after one year.
|
||||||
$em->Body = Template::EmailPatronsCircleCompleted(['ebooksThisYear' => $ebooksThisYear]);
|
$em->Body = Template::EmailPatronsCircleCompleted(ebooksThisYear: $ebooksThisYear);
|
||||||
$em->TextBody = Template::EmailPatronsCircleCompletedText(['ebooksThisYear' => $ebooksThisYear]);
|
$em->TextBody = Template::EmailPatronsCircleCompletedText(ebooksThisYear: $ebooksThisYear);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->Send();
|
$em->Send();
|
||||||
|
|
|
@ -397,8 +397,8 @@ final class Project{
|
||||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->To = $this->Manager->Email;
|
$em->To = $this->Manager->Email;
|
||||||
$em->Subject = 'New ebook project to manage and review';
|
$em->Subject = 'New ebook project to manage and review';
|
||||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'manage and review', 'user' => $this->Manager]);
|
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'manage and review', user: $this->Manager);
|
||||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'manage and review', 'user' => $this->Manager]);
|
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'manage and review', user: $this->Manager);
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,8 +409,8 @@ final class Project{
|
||||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->To = $this->Manager->Email;
|
$em->To = $this->Manager->Email;
|
||||||
$em->Subject = 'New ebook project to manage';
|
$em->Subject = 'New ebook project to manage';
|
||||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'manage', 'user' => $this->Manager]);
|
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'manage', user: $this->Manager);
|
||||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'manage', 'user' => $this->Manager]);
|
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'manage', user: $this->Manager);
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,8 +420,8 @@ final class Project{
|
||||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->To = $this->Reviewer->Email;
|
$em->To = $this->Reviewer->Email;
|
||||||
$em->Subject = 'New ebook project to review';
|
$em->Subject = 'New ebook project to review';
|
||||||
$em->Body = Template::EmailManagerNewProject(['project' => $this, 'role' => 'review', 'user' => $this->Reviewer]);
|
$em->Body = Template::EmailManagerNewProject(project: $this, role: 'review', user: $this->Reviewer);
|
||||||
$em->TextBody = Template::EmailManagerNewProjectText(['project' => $this, 'role' => 'review', 'user' => $this->Reviewer]);
|
$em->TextBody = Template::EmailManagerNewProjectText(project: $this, role: 'review', user: $this->Reviewer);
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ use function Safe\file_get_contents;
|
||||||
use function Safe\filesize;
|
use function Safe\filesize;
|
||||||
use function Safe\preg_replace;
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property array<Ebook> $Entries
|
||||||
|
*/
|
||||||
class RssFeed extends Feed{
|
class RssFeed extends Feed{
|
||||||
public string $Description;
|
public string $Description;
|
||||||
|
|
||||||
|
@ -21,7 +24,7 @@ class RssFeed extends Feed{
|
||||||
// *******
|
// *******
|
||||||
|
|
||||||
protected function GetXmlString(): string{
|
protected function GetXmlString(): string{
|
||||||
return $this->_XmlString ??= $this->CleanXmlString(Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => NOW]));
|
return $this->_XmlString ??= $this->CleanXmlString(Template::RssFeed(url: $this->Url, description: $this->Description, title: $this->Title, entries: $this->Entries, updated: NOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SaveIfChanged(): bool{
|
public function SaveIfChanged(): bool{
|
||||||
|
|
117
lib/Template.php
117
lib/Template.php
|
@ -1,62 +1,65 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\ob_end_clean;
|
use Safe\DateTimeImmutable;
|
||||||
use function Safe\ob_start;
|
|
||||||
|
|
||||||
class Template{
|
|
||||||
/**
|
|
||||||
* @param array<mixed> $arguments
|
|
||||||
*/
|
|
||||||
protected static function Get(string $templateName, array $arguments = []): string{
|
|
||||||
// Expand the passed variables to make them available to the included template.
|
|
||||||
// We use these funny names so that we can use 'name' and 'value' as template variables if we want to.
|
|
||||||
foreach($arguments as $innerName => $innerValue){
|
|
||||||
$$innerName = $innerValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
include(TEMPLATES_PATH . '/' . $templateName . '.php');
|
|
||||||
$contents = ob_get_contents() ?: '';
|
|
||||||
ob_end_clean();
|
|
||||||
|
|
||||||
return $contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array<mixed> $arguments
|
|
||||||
*/
|
|
||||||
public static function __callStatic(string $function, array $arguments): string{
|
|
||||||
if(isset($arguments[0]) && is_array($arguments[0])){
|
|
||||||
return self::Get($function, $arguments[0]);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return self::Get($function, $arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exit the script while outputting the given HTTP code.
|
|
||||||
*
|
|
||||||
* @param bool $showPage If **`TRUE`**, show a special page given the HTTP code (like a 404 page).
|
|
||||||
*
|
|
||||||
* @return never
|
|
||||||
*/
|
|
||||||
public static function ExitWithCode(Enums\HttpCode $httpCode, bool $showPage = true, Enums\HttpRequestType $requestType = Enums\HttpRequestType::Web): void{
|
|
||||||
http_response_code($httpCode->value);
|
|
||||||
|
|
||||||
if($requestType == Enums\HttpRequestType::Web && $showPage){
|
|
||||||
switch($httpCode){
|
|
||||||
case Enums\HttpCode::Forbidden:
|
|
||||||
include(WEB_ROOT . '/403.php');
|
|
||||||
break;
|
|
||||||
case Enums\HttpCode::NotFound:
|
|
||||||
include(WEB_ROOT . '/404.php');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static string ArtworkForm(Artwork $artwork, $isEditForm = false)
|
||||||
|
* @method static string ArtworkList(array<Artwork> $artworks)
|
||||||
|
* @method static string AtomFeed(string $id, string $url, string $title, ?string $subtitle = null, DateTimeImmutable $updated, array<Ebook> $entries)
|
||||||
|
* @method static string AtomFeedEntry(Ebook $entry)
|
||||||
|
* @method static string BulkDownloadTable(string $label, array<stdClass> $collections)
|
||||||
|
* @method static string CollectionDescriptor(?CollectionMembership $collectionMembership)
|
||||||
|
* @method static string ContributeAlert()
|
||||||
|
* @method static string DonationAlert()
|
||||||
|
* @method static string DonationCounter(bool $autoHide = true, bool $showDonateButton = true)
|
||||||
|
* @method static string DonationProgress(bool $autoHide = true, bool $showDonateButton = true)
|
||||||
|
* @method static string EbookCarousel(array<Ebook> $carousel, bool $isMultiSize = false)
|
||||||
|
* @method static string EbookGrid(array<Ebook> $ebooks, ?Collection $collection = null, Enums\ViewType $view = Enums\ViewType::Grid)
|
||||||
|
* @method static string EbookMetadata(Ebook $ebook, bool $showPlaceholderMetadata = false)
|
||||||
|
* @method static string EbookPlaceholderForm(Ebook $ebook, bool $isEditForm = false, bool $showProjectForm = true)
|
||||||
|
* @method static string EmailAdminNewPatron(Patron $patron, Payment $payment)
|
||||||
|
* @method static string EmailAdminNewPatronText(Patron $patron, Payment $payment)
|
||||||
|
* @method static string EmailAdminUnprocessedDonations()
|
||||||
|
* @method static string EmailAdminUnprocessedDonationsText()
|
||||||
|
* @method static string EmailDonationProcessingFailed(string $exception)
|
||||||
|
* @method static string EmailDonationProcessingFailedText(string $exception)
|
||||||
|
* @method static string EmailDonationThankYou()
|
||||||
|
* @method static string EmailDonationThankYouText()
|
||||||
|
* @method static string EmailFooter(bool $includeLinks = true)
|
||||||
|
* @method static string EmailFooterText()
|
||||||
|
* @method static string EmailHeader(?string $preheader = null, bool $hasLetterhead = false, bool $hasAdminTable = false)
|
||||||
|
* @method static string EmailManagerNewProject(Project $project, string $role, User $user)
|
||||||
|
* @method static string EmailManagerNewProjectText(Project $project, string $role, User $user)
|
||||||
|
* @method static string EmailNewsletterConfirmation(bool $isSubscribedToNewsletter, bool $isSubscribedToSummary, NewsletterSubscription $subscription)
|
||||||
|
* @method static string EmailNewsletterConfirmationText(bool $isSubscribedToNewsletter, bool $isSubscribedToSummary, NewsletterSubscription $subscription)
|
||||||
|
* @method static string EmailPatronsCircleCompleted(int $ebooksThisYear)
|
||||||
|
* @method static string EmailPatronsCircleCompletedText(int $ebooksThisYear)
|
||||||
|
* @method static string EmailPatronsCircleRecurringCompleted()
|
||||||
|
* @method static string EmailPatronsCircleRecurringCompletedText()
|
||||||
|
* @method static string EmailPatronsCircleWelcome(bool $isAnonymous, bool $isReturning)
|
||||||
|
* @method static string EmailPatronsCircleWelcomeText(bool $isAnonymous, bool $isReturning)
|
||||||
|
* @method static string EmailProjectAbandoned()
|
||||||
|
* @method static string EmailProjectAbandonedText()
|
||||||
|
* @method static string EmailProjectStalled()
|
||||||
|
* @method static string EmailProjectStalledText()
|
||||||
|
* @method static string Error(?Exception $exception)
|
||||||
|
* @method static string FeedHowTo()
|
||||||
|
* @method static string Footer()
|
||||||
|
* @method static string Header(?string $title = null, ?string $highlight = null, ?string $description = null, bool $isManual = false, bool $isXslt = false, ?string $feedUrl = null, ?string $feedTitle = null, bool $isErrorPage = false, ?string $downloadUrl = null, ?string $canonicalUrl = null, ?string $coverUrl = null, string $ogType = 'website', array<string> $css = [])
|
||||||
|
* @method static string ImageCopyrightNotice()
|
||||||
|
* @method static string OpdsAcquisitionEntry(Ebook $entry)
|
||||||
|
* @method static string OpdsAcquisitionFeed(string $id, string $url, string $parentUrl, string $title, ?string $subtitle, DateTimeImmutable $updated, array<Ebook> $entries, bool $isCrawlable = false)
|
||||||
|
* @method static string OpdsNavigationFeed(string $id, string $url, ?string $parentUrl, string $title, ?string $subtitle, DateTimeImmutable $updated, array<OpdsNavigationEntry> $entries)
|
||||||
|
* @method static string ProjectDetailsTable(Project $project, bool $useFullyQualifiedUrls = false, bool $showTitle = true, bool $showArtworkStatus = true)
|
||||||
|
* @method static string ProjectForm(Project $project, $areFieldsRequired = true, $isEditForm = false)
|
||||||
|
* @method static string ProjectsTable(array<Project> $projects, bool $includeTitle = true, bool $includeStatus = true, bool $showEditButton = false)
|
||||||
|
* @method static string RealisticEbook(Ebook $ebook)
|
||||||
|
* @method static string RssEntry(Ebook $entry)
|
||||||
|
* @method static string RssFeed(string $title, string $description, DateTimeImmutable $updated, string $url, array<Ebook> $entries)
|
||||||
|
* @method static string SearchForm(string $query, array<string> $tags, Enums\EbookSortType $sort, Enums\ViewType $view, int $perPage)
|
||||||
|
* @method static string UserForm(User $user, Enums\PasswordActionType $passwordAction, bool $generateNewUuid, bool $isEditForm = false)
|
||||||
|
* @method static string WantedEbooksList(array<Ebook> $ebooks, bool $showPlaceholderMetadata)
|
||||||
|
*/
|
||||||
|
class Template extends TemplateBase{
|
||||||
/**
|
/**
|
||||||
* Redirect the user to the login page.
|
* Redirect the user to the login page.
|
||||||
*
|
*
|
||||||
|
|
80
lib/TemplateBase.php
Normal file
80
lib/TemplateBase.php
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<?
|
||||||
|
use function Safe\ob_end_clean;
|
||||||
|
use function Safe\ob_start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple templating class that reads directly from PHP files.
|
||||||
|
*
|
||||||
|
* The `Template` class must extend the `TemplateBase` class. Methods corresponding to each template file are annotated using PHPDoc on the `Template` class.
|
||||||
|
*
|
||||||
|
* Place template files in `TEMPLATES_PATH`. Calling `Template::MyTemplateFilename(variable: value ...)` will expand passed in variables, execute `TEMPLATES_PATH/MyTemplateFilename.php`, and output the string contents of the executed PHP. For example:
|
||||||
|
*
|
||||||
|
* ````php
|
||||||
|
* <?
|
||||||
|
* // Outputs the contents of ``TEMPLATES_PATH`/Header.php`. Inside that file, the variable `$title` will be available.
|
||||||
|
* print(Template::Header(title: 'My Title'));
|
||||||
|
* ````
|
||||||
|
*
|
||||||
|
* # Template conventions
|
||||||
|
*
|
||||||
|
* At the top of each template file, use PHPDoc to define required variables and nullable optional variables that are `null` by default. Next, optional variables with default values are defined with the `$varName ??= $defaultValue;` pattern. For example:
|
||||||
|
*
|
||||||
|
* ````php
|
||||||
|
* <?
|
||||||
|
* // TEMPLATES_PATH/Header.php
|
||||||
|
*
|
||||||
|
* // @var string $title Required.
|
||||||
|
* // @var ?string $url Optional but nullable, we define the type of `string` here.
|
||||||
|
*
|
||||||
|
* $url ??= null; // Optional and nullable. The type was defined in the above PHPDoc, and we set the default as `null` here.
|
||||||
|
* $isFeed ??= false; // Optional and not nullable. Both the type and the default value are set here.
|
||||||
|
* ?>
|
||||||
|
* <?= $title ?>
|
||||||
|
* <? if($isFeed){ ?>
|
||||||
|
* <?= $url ?>
|
||||||
|
* <? } ?>
|
||||||
|
* ````
|
||||||
|
*/
|
||||||
|
abstract class TemplateBase{
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $arguments
|
||||||
|
*/
|
||||||
|
public static function __callStatic(string $function, array $arguments): string{
|
||||||
|
// Expand the passed variables to make them available to the included template.
|
||||||
|
// We use these funny names so that we can use `name` and `value` as template variables if we want to.
|
||||||
|
foreach($arguments as $innerName => $innerValue){
|
||||||
|
$$innerName = $innerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
include(TEMPLATES_PATH . '/' . $function . '.php');
|
||||||
|
$contents = ob_get_contents() ?: '';
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
return $contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit the script while outputting the given HTTP code.
|
||||||
|
*
|
||||||
|
* @param bool $showPage If **`TRUE`**, show a special page given the HTTP code (like a 404 page).
|
||||||
|
*
|
||||||
|
* @return never
|
||||||
|
*/
|
||||||
|
public static function ExitWithCode(Enums\HttpCode $httpCode, bool $showPage = true, Enums\HttpRequestType $requestType = Enums\HttpRequestType::Web): void{
|
||||||
|
http_response_code($httpCode->value);
|
||||||
|
|
||||||
|
if($requestType == Enums\HttpRequestType::Web && $showPage){
|
||||||
|
switch($httpCode){
|
||||||
|
case Enums\HttpCode::Forbidden:
|
||||||
|
include(WEB_ROOT . '/403.php');
|
||||||
|
break;
|
||||||
|
case Enums\HttpCode::NotFound:
|
||||||
|
include(WEB_ROOT . '/404.php');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -217,8 +217,8 @@ catch(Exception $ex){
|
||||||
$em = new Email(true);
|
$em = new Email(true);
|
||||||
$em->To = ADMIN_EMAIL_ADDRESS;
|
$em->To = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->Subject = 'Ingesting FA donations failed';
|
$em->Subject = 'Ingesting FA donations failed';
|
||||||
$em->Body = Template::EmailDonationProcessingFailed(['exception' => preg_replace('/^/m', "\t", $exceptionString)]);
|
$em->Body = Template::EmailDonationProcessingFailed(exception: preg_replace('/^/m', "\t", $exceptionString));
|
||||||
$em->TextBody = Template::EmailDonationProcessingFailedText(['exception' => preg_replace('/^/m', "\t", $exceptionString)]);
|
$em->TextBody = Template::EmailDonationProcessingFailedText(exception: preg_replace('/^/m', "\t", $exceptionString));
|
||||||
$em->Send();
|
$em->Send();
|
||||||
|
|
||||||
throw $ex;
|
throw $ex;
|
||||||
|
|
|
@ -277,8 +277,8 @@ try{
|
||||||
$em->To = ADMIN_EMAIL_ADDRESS;
|
$em->To = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->From = ADMIN_EMAIL_ADDRESS;
|
$em->From = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->Subject = 'New Patrons Circle member';
|
$em->Subject = 'New Patrons Circle member';
|
||||||
$em->Body = Template::EmailAdminNewPatron(['patron' => $patron, 'payment' => $payment]);
|
$em->Body = Template::EmailAdminNewPatron(patron: $patron, payment: $payment);
|
||||||
$em->TextBody = Template::EmailAdminNewPatronText(['patron' => $patron, 'payment' => $payment]);;
|
$em->TextBody = Template::EmailAdminNewPatronText(patron: $patron, payment: $payment);;
|
||||||
$em->Send();
|
$em->Send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,8 +324,8 @@ catch(Exception $ex){
|
||||||
$em = new Email(true);
|
$em = new Email(true);
|
||||||
$em->To = ADMIN_EMAIL_ADDRESS;
|
$em->To = ADMIN_EMAIL_ADDRESS;
|
||||||
$em->Subject = 'Donation processing failed';
|
$em->Subject = 'Donation processing failed';
|
||||||
$em->Body = Template::EmailDonationProcessingFailed(['exception' => preg_replace('/^/m', "\t", $exceptionString)]);
|
$em->Body = Template::EmailDonationProcessingFailed(exception: preg_replace('/^/m', "\t", $exceptionString));
|
||||||
$em->TextBody = Template::EmailDonationProcessingFailedText(['exception' => preg_replace('/^/m', "\t", $exceptionString)]);
|
$em->TextBody = Template::EmailDonationProcessingFailedText(exception: preg_replace('/^/m', "\t", $exceptionString));
|
||||||
$em->Send();
|
$em->Send();
|
||||||
|
|
||||||
throw $ex;
|
throw $ex;
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
* @var ?Artwork $artwork
|
* @var Artwork $artwork
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if($artwork === null){
|
$isEditForm ??= false;
|
||||||
$artwork = new Artwork();
|
|
||||||
$artwork->Artist = new Artist();
|
|
||||||
}
|
|
||||||
|
|
||||||
$isEditForm = $isEditForm ?? false;
|
|
||||||
?>
|
?>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Artist details</legend>
|
<legend>Artist details</legend>
|
||||||
|
|
|
@ -4,33 +4,33 @@
|
||||||
*/
|
*/
|
||||||
?>
|
?>
|
||||||
<ol class="artwork-list">
|
<ol class="artwork-list">
|
||||||
<? foreach($artworks as $artwork){ ?>
|
<? foreach($artworks as $artwork){ ?>
|
||||||
<?
|
<?
|
||||||
$class = '';
|
$class = '';
|
||||||
|
|
||||||
if($artwork->EbookUrl !== null){
|
if($artwork->EbookUrl !== null){
|
||||||
$class .= ' in-use';
|
$class .= ' in-use';
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($artwork->Status){
|
switch($artwork->Status){
|
||||||
case Enums\ArtworkStatusType::Unverified:
|
case Enums\ArtworkStatusType::Unverified:
|
||||||
$class .= ' unverified';
|
$class .= ' unverified';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Enums\ArtworkStatusType::Declined:
|
case Enums\ArtworkStatusType::Declined:
|
||||||
$class .= ' declined';
|
$class .= ' declined';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = trim($class);
|
$class = trim($class);
|
||||||
?>
|
?>
|
||||||
<li<? if($class != ''){ ?> class="<?= $class ?>"<? } ?>>
|
<li<? if($class != ''){ ?> class="<?= $class ?>"<? } ?>>
|
||||||
<a href="<?= $artwork->Url ?>">
|
<a href="<?= $artwork->Url ?>">
|
||||||
<picture>
|
<picture>
|
||||||
<source srcset="<?= $artwork->Thumb2xUrl ?> 2x, <?= $artwork->ThumbUrl ?> 1x" type="image/jpg"/>
|
<source srcset="<?= $artwork->Thumb2xUrl ?> 2x, <?= $artwork->ThumbUrl ?> 1x" type="image/jpg"/>
|
||||||
<img src="<?= $artwork->ThumbUrl ?>" alt="" property="schema:image"/>
|
<img src="<?= $artwork->ThumbUrl ?>" alt="" property="schema:image"/>
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<?
|
|
||||||
/**
|
|
||||||
* @var Artwork $artwork
|
|
||||||
*/
|
|
||||||
?>
|
|
||||||
<?= ucfirst($artwork->Status->value) ?>
|
|
||||||
<? if($artwork->EbookUrl !== null){ ?>
|
|
||||||
— in use by
|
|
||||||
<? if($artwork->Ebook !== null && $artwork->Ebook->Url !== null){ ?>
|
|
||||||
<i>
|
|
||||||
<a href="<?= $artwork->Ebook->Url ?>"><?= Formatter::EscapeHtml($artwork->Ebook->Title) ?></a>
|
|
||||||
</i><? if($artwork->Ebook->IsPlaceholder()){ ?>(unreleased)<? } ?>
|
|
||||||
<? }else{ ?>
|
|
||||||
<code><?= Formatter::EscapeHtml($artwork->EbookUrl) ?></code> (unreleased)
|
|
||||||
<? } ?>
|
|
||||||
<? } ?>
|
|
|
@ -8,7 +8,7 @@
|
||||||
* @var array<Ebook> $entries
|
* @var array<Ebook> $entries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$subtitle = $subtitle ?? null;
|
$subtitle ??= null;
|
||||||
|
|
||||||
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
||||||
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
||||||
|
@ -28,6 +28,6 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||||
</author>
|
</author>
|
||||||
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />
|
<link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />
|
||||||
<? foreach($entries as $entry){ ?>
|
<? foreach($entries as $entry){ ?>
|
||||||
<?= Template::AtomFeedEntry(['entry' => $entry]) ?>
|
<?= Template::AtomFeedEntry(entry: $entry) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</feed>
|
</feed>
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\preg_replace;
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
$collectionMembership = $collectionMembership ?? null;
|
/**
|
||||||
|
* @var ?CollectionMembership $collectionMembership
|
||||||
|
*/
|
||||||
|
|
||||||
$collection = $collectionMembership?->Collection;
|
$collection = $collectionMembership?->Collection;
|
||||||
$sequenceNumber = $collectionMembership?->SequenceNumber;
|
$sequenceNumber = $collectionMembership?->SequenceNumber;
|
||||||
?>
|
?>
|
||||||
<? if($sequenceNumber !== null){ ?>№ <?= number_format($sequenceNumber) ?> in the<? }else{ ?>Part of the<? } ?> <a href="<?= $collection->Url ?>" property="schema:isPartOf"><?= Formatter::EscapeHtml(preg_replace('/^The /ius', '', (string)$collection->Name)) ?></a>
|
<? if($collection !== null){ ?>
|
||||||
<? if($collection->Type !== null){ ?>
|
<? if($sequenceNumber !== null){ ?>№ <?= number_format($sequenceNumber) ?> in the<? }else{ ?>Part of the<? } ?> <a href="<?= $collection->Url ?>" property="schema:isPartOf"><?= Formatter::EscapeHtml(preg_replace('/^The /ius', '', $collection->Name)) ?></a>
|
||||||
|
<? } ?>
|
||||||
|
<? if($collection?->Type !== null){ ?>
|
||||||
<? if(substr_compare(mb_strtolower($collection->Name), mb_strtolower($collection->Type->value), -strlen(mb_strtolower($collection->Type->value))) !== 0){ ?><?= $collection->Type->value ?><? } ?>
|
<? if(substr_compare(mb_strtolower($collection->Name), mb_strtolower($collection->Type->value), -strlen(mb_strtolower($collection->Type->value))) !== 0){ ?><?= $collection->Type->value ?><? } ?>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
collection
|
collection
|
||||||
|
|
|
@ -4,8 +4,8 @@ if(!DONATION_DRIVE_COUNTER_ENABLED || ($autoHide ?? (HttpInput::Bool(COOKIE, 'hi
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$autoHide = $autoHide ?? true;
|
$autoHide ??= true;
|
||||||
$showDonateButton = $showDonateButton ?? true;
|
$showDonateButton ??= true;
|
||||||
$current = 0;
|
$current = 0;
|
||||||
|
|
||||||
if(NOW < DONATION_DRIVE_COUNTER_START || NOW > DONATION_DRIVE_COUNTER_END){
|
if(NOW < DONATION_DRIVE_COUNTER_START || NOW > DONATION_DRIVE_COUNTER_END){
|
||||||
|
|
|
@ -13,8 +13,8 @@ if(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$autoHide = $autoHide ?? true;
|
$autoHide ??= true;
|
||||||
$showDonateButton = $showDonateButton ?? true;
|
$showDonateButton ??= true;
|
||||||
|
|
||||||
$deadline = $donationDrive->End->format('F j');
|
$deadline = $donationDrive->End->format('F j');
|
||||||
$timeLeft = NOW->diff($donationDrive->End);
|
$timeLeft = NOW->diff($donationDrive->End);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* @var array<Ebook> $carousel
|
* @var array<Ebook> $carousel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$isMultiSize = $isMultiSize ?? false;
|
$isMultiSize ??= false;
|
||||||
?>
|
?>
|
||||||
<? if(sizeof($carousel) > 0){ ?>
|
<? if(sizeof($carousel) > 0){ ?>
|
||||||
<ul class="ebook-carousel<? if($isMultiSize){ ?> multi-size<? } ?>">
|
<ul class="ebook-carousel<? if($isMultiSize){ ?> multi-size<? } ?>">
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
* @var ?Collection $collection
|
|
||||||
* @var array<Ebook> $ebooks
|
* @var array<Ebook> $ebooks
|
||||||
|
* @var ?Collection $collection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$view = $view ?? Enums\ViewType::Grid;
|
$view ??= Enums\ViewType::Grid;
|
||||||
$collection = $collection ?? null;
|
$collection ??= null;
|
||||||
?>
|
?>
|
||||||
<ol class="ebooks-list<? if($view == Enums\ViewType::List){ ?> list<? }else{ ?> grid<? } ?>"<? if($collection !== null){ ?> typeof="schema:BookSeries" about="<?= $collection->Url ?>"<? } ?>>
|
<ol class="ebooks-list<? if($view == Enums\ViewType::List){ ?> list<? }else{ ?> grid<? } ?>"<? if($collection !== null){ ?> typeof="schema:BookSeries" about="<?= $collection->Url ?>"<? } ?>>
|
||||||
<? if($collection !== null){ ?>
|
<? if($collection !== null){ ?>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* @var Ebook $ebook
|
* @var Ebook $ebook
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$showPlaceholderMetadata = $showPlaceholderMetadata ?? false;
|
$showPlaceholderMetadata ??= false;
|
||||||
?>
|
?>
|
||||||
<section id="metadata">
|
<section id="metadata">
|
||||||
<h2>Metadata</h2>
|
<h2>Metadata</h2>
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<?
|
<?
|
||||||
$ebook = $ebook ?? new Ebook();
|
/**
|
||||||
$isEditForm = $isEditForm ?? false;
|
* @var Ebook $ebook
|
||||||
$showProjectForm = $showProjectForm ?? true;
|
*/
|
||||||
|
|
||||||
|
$isEditForm ??= false;
|
||||||
|
$showProjectForm ??= true;
|
||||||
?>
|
?>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Contributors</legend>
|
<legend>Contributors</legend>
|
||||||
|
@ -204,7 +207,7 @@ $showProjectForm = $showProjectForm ?? true;
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<fieldset class="project-form">
|
<fieldset class="project-form">
|
||||||
<?= Template::ProjectForm(['project' => $ebook->ProjectInProgress, 'areFieldsRequired' => false]) ?>
|
<?= Template::ProjectForm(project: $ebook->ProjectInProgress ?? new Project(), areFieldsRequired: false) ?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?
|
<?
|
||||||
$includeLinks = $includeLinks ?? true;
|
$includeLinks ??= true;
|
||||||
?>
|
?>
|
||||||
<div class="footer<? if(!$includeLinks){ ?> no-links<? } ?>">
|
<div class="footer<? if(!$includeLinks){ ?> no-links<? } ?>">
|
||||||
<? if($includeLinks){ ?>
|
<? if($includeLinks){ ?>
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<?
|
<?
|
||||||
$preheader = $preheader ?? null;
|
/**
|
||||||
$letterhead = $letterhead ?? false;
|
* @var ?string $preheader
|
||||||
$hasAdminTable = $hasAdminTable ?? false;
|
*/
|
||||||
|
|
||||||
|
$preheader ??= null;
|
||||||
|
$hasLetterhead ??= false;
|
||||||
|
$hasAdminTable ??= false;
|
||||||
?><!DOCTYPE html>
|
?><!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -38,7 +42,7 @@ $hasAdminTable = $hasAdminTable ?? false;
|
||||||
-webkit-text-size-adjust: none;
|
-webkit-text-size-adjust: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
<? if($letterhead){ ?>
|
<? if($hasLetterhead){ ?>
|
||||||
div.body.letterhead{
|
div.body.letterhead{
|
||||||
background-image: url("https://standardebooks.org/images/logo-email.png");
|
background-image: url("https://standardebooks.org/images/logo-email.png");
|
||||||
background-position: top 2em center;
|
background-position: top 2em center;
|
||||||
|
@ -222,7 +226,7 @@ $hasAdminTable = $hasAdminTable ?? false;
|
||||||
color: #4f9d85;
|
color: #4f9d85;
|
||||||
}
|
}
|
||||||
|
|
||||||
<? if($letterhead){ ?>
|
<? if($hasLetterhead){ ?>
|
||||||
div.body.letterhead{
|
div.body.letterhead{
|
||||||
background-image: url("https://standardebooks.org/images/logo-email-dark.png");
|
background-image: url("https://standardebooks.org/images/logo-email-dark.png");
|
||||||
}
|
}
|
||||||
|
@ -235,7 +239,7 @@ $hasAdminTable = $hasAdminTable ?? false;
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="body<? if($letterhead){ ?> letterhead<? } ?>">
|
<div class="body<? if($hasLetterhead){ ?> letterhead<? } ?>">
|
||||||
<? if($preheader){ ?>
|
<? if($preheader){ ?>
|
||||||
<p class="preheader"><?= Formatter::EscapeHtml($preheader) ?><? for($i = 0; $i < 150 - strlen($preheader); $i++){ ?>‌ <? } ?></p>
|
<p class="preheader"><?= Formatter::EscapeHtml($preheader) ?><? for($i = 0; $i < 150 - strlen($preheader); $i++){ ?>‌ <? } ?></p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* @var string $role
|
* @var string $role
|
||||||
* @var User $user
|
* @var User $user
|
||||||
*/
|
*/
|
||||||
?><?= Template::EmailHeader(['hasAdminTable' => true, 'letterhead' => true]) ?>
|
?><?= Template::EmailHeader(hasAdminTable: true, hasLetterhead: true) ?>
|
||||||
<p>You’ve been assigned a new ebook project to <strong><?= $role ?></strong>:</p>
|
<p>You’ve been assigned a new ebook project to <strong><?= $role ?></strong>:</p>
|
||||||
<?= Template::ProjectDetailsTable(['project' => $project, 'useFullyQualifiedUrls' => true, 'showArtworkStatus' => false]) ?>
|
<?= Template::ProjectDetailsTable(project: $project, useFullyQualifiedUrls: true, showArtworkStatus: false) ?>
|
||||||
<p>If you’re unable to <?= $role ?> this ebook project, <a href="mailto:<?= EDITOR_IN_CHIEF_EMAIL_ADDRESS ?>">email the Editor-in-Chief</a> and we’ll reassign it.</p>
|
<p>If you’re unable to <?= $role ?> this ebook project, <a href="mailto:<?= EDITOR_IN_CHIEF_EMAIL_ADDRESS ?>">email the Editor-in-Chief</a> and we’ll reassign it.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
@ -20,4 +20,4 @@
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<?= Template::EmailFooter(['includeLinks' => false]) ?>
|
<?= Template::EmailFooter(includeLinks: false) ?>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/**
|
/**
|
||||||
* @var int $ebooksThisYear
|
* @var int $ebooksThisYear
|
||||||
*/
|
*/
|
||||||
?><?= Template::EmailHeader(['letterhead' => true]) ?>
|
?><?= Template::EmailHeader(hasLetterhead: true) ?>
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
<p>Last year, your generous donation to <a href="<?= SITE_URL ?>">Standard Ebooks</a> made it possible for us to continue producing beautiful ebook editions for free distribution.</p>
|
<p>Last year, your generous donation to <a href="<?= SITE_URL ?>">Standard Ebooks</a> made it possible for us to continue producing beautiful ebook editions for free distribution.</p>
|
||||||
<p>It also allowed me to add you to our <a href="<?= SITE_URL ?>/about#patrons-circle">Patrons Circle</a>, a group of donors who are honored on our masthead, and who have a direct voice in the future of our <a href="<?= SITE_URL ?>/ebooks">ebook catalog</a>, for one year.</p>
|
<p>It also allowed me to add you to our <a href="<?= SITE_URL ?>/about#patrons-circle">Patrons Circle</a>, a group of donors who are honored on our masthead, and who have a direct voice in the future of our <a href="<?= SITE_URL ?>/ebooks">ebook catalog</a>, for one year.</p>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::EmailHeader(['letterhead' => true]) ?>
|
<?= Template::EmailHeader(hasLetterhead: true) ?>
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
<p>I couldn’t help but notice that your monthly donation to Standard Ebooks has recently ended. Your generous donation allowed me to add you to our <a href="<?= SITE_URL ?>/about#patrons-circle">Patrons Circle</a>, a group of donors who are honored on our masthead, and who have a direct voice in the future of our <a href="<?= SITE_URL ?>/ebooks">ebook catalog</a>.</p>
|
<p>I couldn’t help but notice that your monthly donation to Standard Ebooks has recently ended. Your generous donation allowed me to add you to our <a href="<?= SITE_URL ?>/about#patrons-circle">Patrons Circle</a>, a group of donors who are honored on our masthead, and who have a direct voice in the future of our <a href="<?= SITE_URL ?>/ebooks">ebook catalog</a>.</p>
|
||||||
<p>Oftentimes credit cards will expire, or recurring charges will get accidentally canceled for any number of nebulous administrative reasons. If you didn’t mean to cancel your recurring donation—and thus your Patrons Circle membership—now’s a great time to <a href="<?= SITE_URL ?>/donate#patrons-circle">renew it</a>.</p>
|
<p>Oftentimes credit cards will expire, or recurring charges will get accidentally canceled for any number of nebulous administrative reasons. If you didn’t mean to cancel your recurring donation—and thus your Patrons Circle membership—now’s a great time to <a href="<?= SITE_URL ?>/donate#patrons-circle">renew it</a>.</p>
|
||||||
|
|
|
@ -2,18 +2,32 @@
|
||||||
use Safe\DateTimeImmutable;
|
use Safe\DateTimeImmutable;
|
||||||
use function Safe\filemtime;
|
use function Safe\filemtime;
|
||||||
|
|
||||||
$title = $title ?? '';
|
/**
|
||||||
$highlight = $highlight ?? '';
|
* @var ?string $title
|
||||||
$description = $description ?? '';
|
* @var ?string $highlight
|
||||||
$manual = $manual ?? false;
|
* @var ?string $description
|
||||||
|
* @var ?string $feedUrl
|
||||||
|
* @var ?string $feedTitle
|
||||||
|
* @var ?string $downloadUrl
|
||||||
|
* @var ?string $canonicalUrl
|
||||||
|
* @var ?string $coverUrl
|
||||||
|
*/
|
||||||
|
|
||||||
|
$title ??= null;
|
||||||
|
$highlight ??= null;
|
||||||
|
$description ??= null;
|
||||||
|
$feedUrl ??= null;
|
||||||
|
$feedTitle ??= null;
|
||||||
|
$downloadUrl ??= null;
|
||||||
|
$canonicalUrl ??= null;
|
||||||
|
$coverUrl ??= null;
|
||||||
|
$css ??= [];
|
||||||
|
$isManual ??= false;
|
||||||
|
$isXslt ??= false;
|
||||||
|
$isErrorPage ??= false;
|
||||||
|
$ogType ??= 'website';
|
||||||
|
|
||||||
$colorScheme = Enums\ColorSchemeType::tryFrom(HttpInput::Str(COOKIE, 'color-scheme') ?? Enums\ColorSchemeType::Auto->value);
|
$colorScheme = Enums\ColorSchemeType::tryFrom(HttpInput::Str(COOKIE, 'color-scheme') ?? Enums\ColorSchemeType::Auto->value);
|
||||||
$isXslt = $isXslt ?? false;
|
|
||||||
$feedUrl = $feedUrl ?? null;
|
|
||||||
$feedTitle = $feedTitle ?? '';
|
|
||||||
$isErrorPage = $isErrorPage ?? false;
|
|
||||||
$downloadUrl = $downloadUrl ?? null;
|
|
||||||
$canonicalUrl = $canonicalUrl ?? null;
|
|
||||||
$css = $css ?? [];
|
|
||||||
$showPublicDomainDayBanner = PD_NOW > new DateTimeImmutable('January 1, 8:00 AM', SITE_TZ) && PD_NOW < new DateTimeImmutable('January 14', LATEST_CONTINENTAL_US_TZ) && !(HttpInput::Bool(COOKIE, 'hide-public-domain-day-banner') ?? false);
|
$showPublicDomainDayBanner = PD_NOW > new DateTimeImmutable('January 1, 8:00 AM', SITE_TZ) && PD_NOW < new DateTimeImmutable('January 14', LATEST_CONTINENTAL_US_TZ) && !(HttpInput::Bool(COOKIE, 'hide-public-domain-day-banner') ?? false);
|
||||||
|
|
||||||
// As of Sep. 2022, all versions of Safari have a bug where if the page is served as XHTML, then `<picture>` elements download all `<source>`s instead of the first supported match.
|
// As of Sep. 2022, all versions of Safari have a bug where if the page is served as XHTML, then `<picture>` elements download all `<source>`s instead of the first supported match.
|
||||||
|
@ -41,8 +55,8 @@ if(!$isXslt){
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
|
||||||
<head prefix="twitter: https://twitter.com/ schema: http://schema.org/"><? /* The `og` RDFa prefix is part of the RDFa spec */ ?>
|
<head prefix="twitter: https://twitter.com/ schema: http://schema.org/"><? /* The `og` RDFa prefix is part of the RDFa spec */ ?>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<title><? if($title != ''){ ?><?= Formatter::EscapeHtml($title) ?> - <? } ?>Standard Ebooks: Free and liberated ebooks, carefully produced for the true book lover</title>
|
<title><? if($title !== null){ ?><?= Formatter::EscapeHtml($title) ?> - <? } ?>Standard Ebooks: Free and liberated ebooks, carefully produced for the true book lover</title>
|
||||||
<? if($description != ''){ ?>
|
<? if($description !== null){ ?>
|
||||||
<meta content="<?= Formatter::EscapeHtml($description) ?>" name="description"/>
|
<meta content="<?= Formatter::EscapeHtml($description) ?>" name="description"/>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||||
|
@ -59,7 +73,7 @@ if(!$isXslt){
|
||||||
<link href="/css/dark.css?version=<?= filemtime(WEB_ROOT . '/css/dark.css') ?>" media="screen<? if($colorScheme == Enums\ColorSchemeType::Auto){ ?> and (prefers-color-scheme: dark)<? } ?>" rel="stylesheet" type="text/css"/>
|
<link href="/css/dark.css?version=<?= filemtime(WEB_ROOT . '/css/dark.css') ?>" media="screen<? if($colorScheme == Enums\ColorSchemeType::Auto){ ?> and (prefers-color-scheme: dark)<? } ?>" rel="stylesheet" type="text/css"/>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if($manual){ ?>
|
<? if($isManual){ ?>
|
||||||
<link href="/css/manual.css?version=<?= filemtime(WEB_ROOT . '/css/manual.css') ?>" media="screen" rel="stylesheet" type="text/css"/>
|
<link href="/css/manual.css?version=<?= filemtime(WEB_ROOT . '/css/manual.css') ?>" media="screen" rel="stylesheet" type="text/css"/>
|
||||||
<? if($colorScheme == Enums\ColorSchemeType::Auto || $colorScheme == Enums\ColorSchemeType::Dark){ ?>
|
<? if($colorScheme == Enums\ColorSchemeType::Auto || $colorScheme == Enums\ColorSchemeType::Dark){ ?>
|
||||||
<link href="/css/manual-dark.css?version=<?= filemtime(WEB_ROOT . '/css/manual-dark.css') ?>" media="screen<? if($colorScheme == Enums\ColorSchemeType::Auto){ ?> and (prefers-color-scheme: dark)<? } ?>" rel="stylesheet" type="text/css"/>
|
<link href="/css/manual-dark.css?version=<?= filemtime(WEB_ROOT . '/css/manual-dark.css') ?>" media="screen<? if($colorScheme == Enums\ColorSchemeType::Auto){ ?> and (prefers-color-scheme: dark)<? } ?>" rel="stylesheet" type="text/css"/>
|
||||||
|
@ -68,7 +82,7 @@ if(!$isXslt){
|
||||||
<? foreach($css as $url){ ?>
|
<? foreach($css as $url){ ?>
|
||||||
<link href="<?= Formatter::EscapeHtml($url) ?>?version=<?= filemtime(WEB_ROOT . $url) ?>" media="screen" rel="stylesheet" type="text/css"/>
|
<link href="<?= Formatter::EscapeHtml($url) ?>?version=<?= filemtime(WEB_ROOT . $url) ?>" media="screen" rel="stylesheet" type="text/css"/>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if($canonicalUrl){ ?>
|
<? if($canonicalUrl !== null){ ?>
|
||||||
<link rel="canonical" href="<?= Formatter::EscapeHtml($canonicalUrl) ?>" />
|
<link rel="canonical" href="<?= Formatter::EscapeHtml($canonicalUrl) ?>" />
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<link href="/apple-touch-icon-120x120.png" rel="apple-touch-icon" sizes="120x120"/>
|
<link href="/apple-touch-icon-120x120.png" rel="apple-touch-icon" sizes="120x120"/>
|
||||||
|
@ -90,8 +104,8 @@ if(!$isXslt){
|
||||||
<link rel="search" href="/ebooks/opensearch" type="application/opensearchdescription+xml; charset=utf-8"/>
|
<link rel="search" href="/ebooks/opensearch" type="application/opensearchdescription+xml; charset=utf-8"/>
|
||||||
<? if(!$isErrorPage){ ?>
|
<? if(!$isErrorPage){ ?>
|
||||||
<meta content="#394451" name="theme-color"/>
|
<meta content="#394451" name="theme-color"/>
|
||||||
<meta content="<? if($title != ''){ ?><?= Formatter::EscapeHtml($title) ?><? }else{ ?>Standard Ebooks<? } ?>" property="og:title"/>
|
<meta content="<? if($title !== null){ ?><?= Formatter::EscapeHtml($title) ?><? }else{ ?>Standard Ebooks<? } ?>" property="og:title"/>
|
||||||
<meta content="<?= $ogType ?? 'website' ?>" property="og:type"/>
|
<meta content="<?= $ogType ?>" property="og:type"/>
|
||||||
<meta content="<?= $pageUrl ?>" property="og:url"/>
|
<meta content="<?= $pageUrl ?>" property="og:url"/>
|
||||||
<meta content="<?= SITE_URL . ($coverUrl ?? '/images/logo.png') ?>" property="og:image"/>
|
<meta content="<?= SITE_URL . ($coverUrl ?? '/images/logo.png') ?>" property="og:image"/>
|
||||||
<meta content="summary_large_image" name="twitter:card"/>
|
<meta content="summary_large_image" name="twitter:card"/>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Notes:
|
* Notes:
|
||||||
*
|
*
|
||||||
* - *All* OPDS feeds must contain a `rel="http://opds-spec.org/crawlable"` link pointing to the `/feeds/opds/all` feed.
|
* - *All* OPDS feeds must contain a `rel="http://opds-spec.org/crawlable"` link pointing to the `/feeds/opds/all` feed.
|
||||||
* - The `<fh:complete/>` element is required to note this as a "Complete Acquisition Feeds"; see <https://specs.opds.io/opds-1.2#25-complete-acquisition-feeds>.
|
* - The `<fh:complete/>` element is required to note this as a "Complete Acquisition Feed"; see <https://specs.opds.io/opds-1.2#25-complete-acquisition-feeds>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
* @var array<Ebook> $entries
|
* @var array<Ebook> $entries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$isCrawlable = $isCrawlable ?? false;
|
$isCrawlable ??= false;
|
||||||
$subtitle = $subtitle ?? null;
|
$subtitle ??= null;
|
||||||
|
|
||||||
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
||||||
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
||||||
|
@ -45,6 +45,6 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||||
<uri><?= SITE_URL ?></uri>
|
<uri><?= SITE_URL ?></uri>
|
||||||
</author>
|
</author>
|
||||||
<? foreach($entries as $entry){ ?>
|
<? foreach($entries as $entry){ ?>
|
||||||
<?= Template::OpdsAcquisitionEntry(['entry' => $entry]) ?>
|
<?= Template::OpdsAcquisitionEntry(entry: $entry) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</feed>
|
</feed>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* @var array<OpdsNavigationEntry> $entries
|
* @var array<OpdsNavigationEntry> $entries
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$subtitle = $subtitle ?? null;
|
$subtitle ??= null;
|
||||||
|
|
||||||
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
|
||||||
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?
|
<?
|
||||||
|
use Enums\HttpMethod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Project $project
|
* @var Project $project
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Enums\HttpMethod;
|
$useFullyQualifiedUrls ??= false;
|
||||||
|
$showTitle ??= true;
|
||||||
$useFullyQualifiedUrls = $useFullyQualifiedUrls ?? false;
|
$showArtworkStatus ??= true;
|
||||||
$showTitle = $showTitle ?? true;
|
|
||||||
$showArtworkStatus = $showArtworkStatus ?? true;
|
|
||||||
?>
|
?>
|
||||||
<table class="admin-table">
|
<table class="admin-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
<?
|
<?
|
||||||
$project = $project ?? new Project();
|
/**
|
||||||
|
* @var Project $project
|
||||||
|
*/
|
||||||
|
|
||||||
|
$areFieldsRequired ??= true;
|
||||||
|
$isEditForm ??= false;
|
||||||
|
|
||||||
$managers = User::GetAllByCanManageProjects();
|
$managers = User::GetAllByCanManageProjects();
|
||||||
$reviewers = User::GetAllByCanReviewProjects();
|
$reviewers = User::GetAllByCanReviewProjects();
|
||||||
$pastProducers = User::GetNamesByHasProducedProject();
|
$pastProducers = User::GetNamesByHasProducedProject();
|
||||||
$areFieldsRequired = $areFieldsRequired ?? true;
|
|
||||||
$isEditForm = $isEditForm ?? false;
|
|
||||||
?>
|
?>
|
||||||
<? if(!$isEditForm){ ?>
|
<? if(!$isEditForm){ ?>
|
||||||
<input type="hidden" name="project-ebook-id" value="<?= $project->EbookId ?? '' ?>" />
|
<input type="hidden" name="project-ebook-id" value="<?= $project->EbookId ?? '' ?>" />
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
* @var array<Project> $projects
|
* @var array<Project> $projects
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$includeTitle = $includeTitle ?? true;
|
$includeTitle ??= true;
|
||||||
$includeStatus = $includeStatus ?? true;
|
$includeStatus ??= true;
|
||||||
$showEditButton = $showEditButton ?? false;
|
$showEditButton ??= false;
|
||||||
?>
|
?>
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<caption aria-hidden="true">Scroll right →</caption>
|
<caption aria-hidden="true">Scroll right →</caption>
|
||||||
|
|
|
@ -31,7 +31,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||||
<width>144</width>
|
<width>144</width>
|
||||||
</image>
|
</image>
|
||||||
<? foreach($entries as $entry){ ?>
|
<? foreach($entries as $entry){ ?>
|
||||||
<?= Template::RssEntry(['entry' => $entry]) ?>
|
<?= Template::RssEntry(entry: $entry) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
|
* @var string $query
|
||||||
* @var array<string> $tags
|
* @var array<string> $tags
|
||||||
* @var Enums\EbookSortType $sort
|
* @var Enums\EbookSortType $sort
|
||||||
* @var Enums\ViewType $view
|
* @var Enums\ViewType $view
|
||||||
|
@ -18,13 +19,13 @@ $isAllSelected = sizeof($tags) == 0 || in_array('all', $tags);
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>Keywords
|
<label>Keywords
|
||||||
<input type="search" name="query" value="<?= Formatter::EscapeHtml($query ?? '') ?>"/>
|
<input type="search" name="query" value="<?= Formatter::EscapeHtml($query) ?>"/>
|
||||||
</label>
|
</label>
|
||||||
<label class="sort">
|
<label class="sort">
|
||||||
<span>Sort</span>
|
<span>Sort</span>
|
||||||
<span>
|
<span>
|
||||||
<select name="sort">
|
<select name="sort">
|
||||||
<? if(isset($query) && $query != ''){ ?>
|
<? if($query != ''){ ?>
|
||||||
<option value="<?= Enums\EbookSortType::Relevance->value ?>"<? if($sort == Enums\EbookSortType::Relevance){ ?> selected="selected"<? } ?>>Relevance</option>
|
<option value="<?= Enums\EbookSortType::Relevance->value ?>"<? if($sort == Enums\EbookSortType::Relevance){ ?> selected="selected"<? } ?>>Relevance</option>
|
||||||
<option value="<?= Enums\EbookSortType::Newest->value ?>"<? if($sort == Enums\EbookSortType::Newest){ ?> selected="selected"<? } ?>>S.E. release date (new → old)</option>
|
<option value="<?= Enums\EbookSortType::Newest->value ?>"<? if($sort == Enums\EbookSortType::Newest){ ?> selected="selected"<? } ?>>S.E. release date (new → old)</option>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<?
|
<?
|
||||||
$user = $user ?? new User();
|
/**
|
||||||
$isEditForm = $isEditForm ?? false;
|
* @var User $user
|
||||||
$generateNewUuid = $generateNewUuid ?? false;
|
* @var Enums\PasswordActionType $passwordAction;
|
||||||
$passwordAction = $passwordAction ?? Enums\PasswordActionType::None;
|
* @var bool $generateNewUuid
|
||||||
|
*/
|
||||||
|
|
||||||
|
$isEditForm ??= false;
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<label class="email">
|
<label class="email">
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?
|
<?
|
||||||
/**
|
/**
|
||||||
* @var array<Ebook> $ebooks
|
* @var array<Ebook> $ebooks
|
||||||
|
* @var bool $showPlaceholderMetadata
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$showPlaceholderMetadata = $showPlaceholderMetadata ?? false;
|
|
||||||
?>
|
?>
|
||||||
<ul class="wanted-list">
|
<ul class="wanted-list">
|
||||||
<? foreach($ebooks as $ebook){ ?>
|
<? foreach($ebooks as $ebook){ ?>
|
||||||
|
@ -15,7 +14,7 @@ $showPlaceholderMetadata = $showPlaceholderMetadata ?? false;
|
||||||
by <?= Formatter::EscapeHtml($ebook->AuthorsString) ?>. <?= $ebook->ContributorsHtml ?>
|
by <?= Formatter::EscapeHtml($ebook->AuthorsString) ?>. <?= $ebook->ContributorsHtml ?>
|
||||||
|
|
||||||
<? foreach($ebook->CollectionMemberships as $index => $collectionMembership){ ?>
|
<? foreach($ebook->CollectionMemberships as $index => $collectionMembership){ ?>
|
||||||
<? if($index == 0){ ?><?= Template::CollectionDescriptor(['collectionMembership' => $collectionMembership]) ?><? }else{ ?><?= lcfirst(Template::CollectionDescriptor(['collectionMembership' => $collectionMembership])) ?><? } ?><? if($index < sizeof($ebook->CollectionMemberships) - 1){ ?>, <? } ?><? if($index == sizeof($ebook->CollectionMemberships) - 1){ ?>.<? } ?>
|
<? if($index == 0){ ?><?= Template::CollectionDescriptor(collectionMembership: $collectionMembership) ?><? }else{ ?><?= lcfirst(Template::CollectionDescriptor(collectionMembership: $collectionMembership)) ?><? } ?><? if($index < sizeof($ebook->CollectionMemberships) - 1){ ?>, <? } ?><? if($index == sizeof($ebook->CollectionMemberships) - 1){ ?>.<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if(isset($ebook->EbookPlaceholder->Notes)){ ?>
|
<? if(isset($ebook->EbookPlaceholder->Notes)){ ?>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'You Don’t Have Permission to View This Page', 'highlight' => '', 'description' => 'You don’t have permission to view this page.', 'isErrorPage' => true]) ?>
|
<?= Template::Header(title: 'You Don’t Have Permission to View This Page', description: 'You don’t have permission to view this page.', isErrorPage: true) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'We Couldn’t Find That Document', 'highlight' => '', 'description' => 'We couldn’t find that document.', 'isErrorPage' => true]) ?>
|
<?= Template::Header(title: 'We Couldn’t Find That Document', description: 'We couldn’t find that document.', isErrorPage: true) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'This Ebook Is No Longer Available', 'highlight' => '', 'description' => 'This ebook is unavailable due to legal reasons.']) ?>
|
<?= Template::Header(title: 'This Ebook Is No Longer Available', description: 'This ebook is unavailable due to legal reasons.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Accessibility', 'highlight' => 'about', 'description' => 'How we make Standard Ebooks accessible.']) ?>
|
<?= Template::Header(title: 'Accessibility', highlight: 'about', description: 'How we make Standard Ebooks accessible.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="accessibility narrow">
|
<section class="accessibility narrow">
|
||||||
<h1>Accessibility</h1>
|
<h1>Accessibility</h1>
|
||||||
|
|
|
@ -35,7 +35,7 @@ $anonymousPatronCount = Db::QueryInt('
|
||||||
) x
|
) x
|
||||||
');
|
');
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'About Standard Ebooks', 'highlight' => 'about', 'description' => 'Standard Ebooks is a volunteer-driven effort to produce a collection of high quality, carefully formatted, accessible, open source, and free public domain ebooks that meet or exceed the quality of commercially produced ebooks. The text and cover art in our ebooks is already believed to be in the public domain, and Standard Ebook dedicates its own work to the public domain, thus releasing the entirety of each ebook file into the public domain.']) ?>
|
?><?= Template::Header(title: 'About Standard Ebooks', highlight: 'about', description: 'Standard Ebooks is a volunteer-driven effort to produce a collection of high quality, carefully formatted, accessible, open source, and free public domain ebooks that meet or exceed the quality of commercially produced ebooks. The text and cover art in our ebooks is already believed to be in the public domain, and Standard Ebook dedicates its own work to the public domain, thus releasing the entirety of each ebook file into the public domain.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>About Standard Ebooks</h1>
|
<h1>About Standard Ebooks</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Our Goals', 'highlight' => 'about', 'description' => 'The goals of Standard Ebooks.']) ?>
|
<?= Template::Header(title: 'Our Goals', highlight: 'about', description: 'The goals of Standard Ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Our Goals</h1>
|
<h1>Our Goals</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Standard Ebooks and the Public Domain', 'highlight' => 'about', 'description' => 'The Standard Ebooks’ philosophy on copyright and the public domain.']) ?>
|
<?= Template::Header(title: 'Standard Ebooks and the Public Domain', highlight: 'about', description: 'The Standard Ebooks’ philosophy on copyright and the public domain.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Standard Ebooks and the Public Domain</h1>
|
<h1>Standard Ebooks and the Public Domain</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'What Makes Standard Ebooks Different', 'highlight' => 'about', 'description' => 'How Standard Ebooks differs from other free ebook projects.']) ?>
|
<?= Template::Header(title: 'What Makes Standard Ebooks Different', highlight: 'about', description: 'How Standard Ebooks differs from other free ebook projects.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>What Makes Standard Ebooks Different</h1>
|
<h1>What Makes Standard Ebooks Different</h1>
|
||||||
|
|
|
@ -23,14 +23,14 @@ try{
|
||||||
catch(Exceptions\ArtistNotFoundException){
|
catch(Exceptions\ArtistNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => 'Artwork by ' . $artworks[0]->Artist->Name, 'css' => ['/css/artwork.css']]) ?>
|
?><?= Template::Header(title: 'Artwork by ' . $artworks[0]->Artist->Name, css: ['/css/artwork.css']) ?>
|
||||||
<main class="artworks">
|
<main class="artworks">
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Artwork by <?= Formatter::EscapeHtml($artworks[0]->Artist->Name) ?></h1>
|
<h1>Artwork by <?= Formatter::EscapeHtml($artworks[0]->Artist->Name) ?></h1>
|
||||||
|
|
||||||
<?= Template::ImageCopyrightNotice() ?>
|
<?= Template::ImageCopyrightNotice() ?>
|
||||||
|
|
||||||
<?= Template::ArtworkList(['artworks' => $artworks]) ?>
|
<?= Template::ArtworkList(artworks: $artworks) ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
|
||||||
$artwork = HttpInput::SessionObject('artwork', Artwork::class);
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(Session::$User === null){
|
if(Session::$User === null){
|
||||||
throw new Exceptions\LoginRequiredException();
|
throw new Exceptions\LoginRequiredException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
||||||
|
$artwork = HttpInput::SessionObject('artwork', Artwork::class);
|
||||||
|
|
||||||
if($artwork === null){
|
if($artwork === null){
|
||||||
$artwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
$artwork = Artwork::GetByUrl(HttpInput::Str(GET, 'artist-url-name'), HttpInput::Str(GET, 'artwork-url-name'));
|
||||||
}
|
}
|
||||||
|
@ -34,21 +34,17 @@ catch(Exceptions\LoginRequiredException){
|
||||||
catch(Exceptions\InvalidPermissionsException){
|
catch(Exceptions\InvalidPermissionsException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::Forbidden); // No permissions to edit artwork.
|
Template::ExitWithCode(Enums\HttpCode::Forbidden); // No permissions to edit artwork.
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(
|
<?= Template::Header(
|
||||||
[
|
title: 'Edit ' . $artwork->Name . ', by ' . $artwork->Artist->Name,
|
||||||
'title' => 'Edit ' . $artwork->Name . ', by ' . $artwork->Artist->Name,
|
css: ['/css/artwork.css'],
|
||||||
'css' => ['/css/artwork.css'],
|
description: 'Edit ' . $artwork->Name . ', by ' . $artwork->Artist->Name . ' in the Standard Ebooks cover art database.'
|
||||||
'highlight' => '',
|
|
||||||
'description' => 'Edit ' . $artwork->Name . ', by ' . $artwork->Artist->Name . ' in the Standard Ebooks cover art database.'
|
|
||||||
]
|
|
||||||
) ?>
|
) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Edit Artwork</h1>
|
<h1>Edit Artwork</h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<picture>
|
<picture>
|
||||||
<source srcset="<?= $artwork->Thumb2xUrl ?> 2x, <?= $artwork->ThumbUrl ?> 1x" type="image/jpg"/>
|
<source srcset="<?= $artwork->Thumb2xUrl ?> 2x, <?= $artwork->ThumbUrl ?> 1x" type="image/jpg"/>
|
||||||
|
@ -57,7 +53,7 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
|
|
||||||
<form class="create-update-artwork" method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $artwork->Url ?>" enctype="multipart/form-data" autocomplete="off">
|
<form class="create-update-artwork" method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $artwork->Url ?>" enctype="multipart/form-data" autocomplete="off">
|
||||||
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Put->value ?>" />
|
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Put->value ?>" />
|
||||||
<?= Template::ArtworkForm(['artwork' => $artwork, 'isEditForm' => true]) ?>
|
<?= Template::ArtworkForm(artwork: $artwork, isEditForm: true) ?>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -64,12 +64,12 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::Forbidden);
|
Template::ExitWithCode(Enums\HttpCode::Forbidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => $artwork->Name, 'css' => ['/css/artwork.css']]) ?>
|
?><?= Template::Header(title: $artwork->Name, css: ['/css/artwork.css']) ?>
|
||||||
<main class="artworks">
|
<main class="artworks">
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1><?= Formatter::EscapeHtml($artwork->Name) ?></h1>
|
<h1><?= Formatter::EscapeHtml($artwork->Name) ?></h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<? if($isSaved){ ?>
|
<? if($isSaved){ ?>
|
||||||
<p class="message success">Artwork saved!</p>
|
<p class="message success">Artwork saved!</p>
|
||||||
|
@ -118,7 +118,19 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Status:</td>
|
<td>Status:</td>
|
||||||
<td><?= Template::ArtworkStatus(['artwork' => $artwork]) ?></td>
|
<td>
|
||||||
|
<?= ucfirst($artwork->Status->value) ?>
|
||||||
|
<? if($artwork->EbookUrl !== null){ ?>
|
||||||
|
— in use by
|
||||||
|
<? if($artwork->Ebook !== null && $artwork->Ebook->Url !== null){ ?>
|
||||||
|
<i>
|
||||||
|
<a href="<?= $artwork->Ebook->Url ?>"><?= Formatter::EscapeHtml($artwork->Ebook->Title) ?></a>
|
||||||
|
</i><? if($artwork->Ebook->IsPlaceholder()){ ?>(unreleased)<? } ?>
|
||||||
|
<? }else{ ?>
|
||||||
|
<code><?= Formatter::EscapeHtml($artwork->EbookUrl) ?></code> (unreleased)
|
||||||
|
<? } ?>
|
||||||
|
<? } ?>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<? if($isReviewerView){ ?>
|
<? if($isReviewerView){ ?>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -136,7 +136,7 @@ catch(Exceptions\PageOutOfBoundsException){
|
||||||
header('Location: ' . $url);
|
header('Location: ' . $url);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $pageTitle, 'css' => ['/css/artwork.css'], 'description' => $pageDescription, 'canonicalUrl' => $canonicalUrl]) ?>
|
?><?= Template::Header(title: $pageTitle, css: ['/css/artwork.css'], description: $pageDescription, canonicalUrl: $canonicalUrl) ?>
|
||||||
<main class="artworks">
|
<main class="artworks">
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Browse U.S. Public Domain Artwork</h1>
|
<h1>Browse U.S. Public Domain Artwork</h1>
|
||||||
|
@ -199,7 +199,7 @@ catch(Exceptions\PageOutOfBoundsException){
|
||||||
<? if($totalArtworkCount == 0){ ?>
|
<? if($totalArtworkCount == 0){ ?>
|
||||||
<p class="no-results">No artwork matched your filters. You can try different filters, or <a href="/artworks">browse all artwork</a>.</p>
|
<p class="no-results">No artwork matched your filters. You can try different filters, or <a href="/artworks">browse all artwork</a>.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::ArtworkList(['artworks' => $artworks]) ?>
|
<?= Template::ArtworkList(artworks: $artworks) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if($totalArtworkCount > 0){ ?>
|
<? if($totalArtworkCount > 0){ ?>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
$isCreated = HttpInput::Bool(SESSION, 'is-artwork-created') ?? false;
|
|
||||||
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
|
||||||
$artwork = HttpInput::SessionObject('artwork', Artwork::class);
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(Session::$User === null){
|
if(Session::$User === null){
|
||||||
throw new Exceptions\LoginRequiredException();
|
throw new Exceptions\LoginRequiredException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$isCreated = HttpInput::Bool(SESSION, 'is-artwork-created') ?? false;
|
||||||
|
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
||||||
|
$artwork = HttpInput::SessionObject('artwork', Artwork::class);
|
||||||
|
|
||||||
if(!Session::$User->Benefits->CanUploadArtwork){
|
if(!Session::$User->Benefits->CanUploadArtwork){
|
||||||
throw new Exceptions\InvalidPermissionsException();
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
}
|
}
|
||||||
|
@ -46,25 +46,22 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(
|
<?= Template::Header(
|
||||||
[
|
title: 'Submit an Artwork',
|
||||||
'title' => 'Submit an Artwork',
|
css: ['/css/artwork.css'],
|
||||||
'css' => ['/css/artwork.css'],
|
description: 'Submit public domain artwork to the database for use as cover art.'
|
||||||
'highlight' => '',
|
|
||||||
'description' => 'Submit public domain artwork to the database for use as cover art.'
|
|
||||||
]
|
|
||||||
) ?>
|
) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Submit an Artwork</h1>
|
<h1>Submit an Artwork</h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<? if($isCreated){ ?>
|
<? if($isCreated){ ?>
|
||||||
<p class="message success">Artwork submitted!</p>
|
<p class="message success">Artwork submitted!</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<form class="create-update-artwork" method="<?= Enums\HttpMethod::Post->value ?>" action="/artworks" enctype="multipart/form-data" autocomplete="off">
|
<form class="create-update-artwork" method="<?= Enums\HttpMethod::Post->value ?>" action="/artworks" enctype="multipart/form-data" autocomplete="off">
|
||||||
<?= Template::ArtworkForm(['artwork' => $artwork]) ?>
|
<?= Template::ArtworkForm(artwork: $artwork) ?>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -31,7 +31,7 @@ try{
|
||||||
catch(Exceptions\AuthorNotFoundException){
|
catch(Exceptions\AuthorNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => 'Ebooks by ' . $author, 'feedUrl' => str_replace('/ebooks/', '/authors/', $authorUrl), 'feedTitle' => 'Standard Ebooks - Ebooks by ' . $author, 'highlight' => 'ebooks', 'description' => 'All of the Standard Ebooks ebooks by ' . $author, 'canonicalUrl' => SITE_URL . $authorUrl]) ?>
|
?><?= Template::Header(title: 'Ebooks by ' . $author, feedUrl: str_replace('/ebooks/', '/authors/', $authorUrl), feedTitle: 'Standard Ebooks - Ebooks by ' . $author, highlight: 'ebooks', description: 'All of the Standard Ebooks ebooks by ' . $author, canonicalUrl: SITE_URL . $authorUrl) ?>
|
||||||
<main class="ebooks">
|
<main class="ebooks">
|
||||||
<h1 class="is-collection">Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
|
<h1 class="is-collection">Ebooks by <?= $ebooks[0]->AuthorsHtml ?></h1>
|
||||||
<? if($showLinks){ ?>
|
<? if($showLinks){ ?>
|
||||||
|
@ -40,7 +40,7 @@ catch(Exceptions\AuthorNotFoundException){
|
||||||
<a class="button" href="<?= Formatter::EscapeHtml($authorUrl) ?>/feeds">Feeds for this author</a>
|
<a class="button" href="<?= Formatter::EscapeHtml($authorUrl) ?>/feeds">Feeds for this author</a>
|
||||||
</p>
|
</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => Enums\ViewType::Grid]) ?>
|
<?= Template::EbookGrid(ebooks: $ebooks, view: Enums\ViewType::Grid) ?>
|
||||||
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
||||||
<?= Template::ContributeAlert() ?>
|
<?= Template::ContributeAlert() ?>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
$ebookIds = [1085, 1052];
|
$ebookIds = [1085, 1052];
|
||||||
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(['title' => 'Death and Beauty in the Alps', 'css' => ['/css/blog.css'], 'highlight' => '', 'description' => '']) ?>
|
<?= Template::Header(title: 'Death and Beauty in the Alps', css: ['/css/blog.css']) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow blog">
|
<section class="narrow blog">
|
||||||
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
||||||
|
@ -31,7 +31,7 @@ $carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSq
|
||||||
<p><em>Scrambles Amongst the Alps</em> has something of both “darkling thrush” and “darkling plain”: an “eternal note of sadness” following terrible loss, but also real, if fleeting, notes of joy in laboring for, and realizing, a hope widely believed impossible.</p>
|
<p><em>Scrambles Amongst the Alps</em> has something of both “darkling thrush” and “darkling plain”: an “eternal note of sadness” following terrible loss, but also real, if fleeting, notes of joy in laboring for, and realizing, a hope widely believed impossible.</p>
|
||||||
<p>The woe of its best-known story is confounded by lesser-known, brighter elements—even if they’re only “thin atomies” in comparison—praising the worth of the endeavour and the value of the toil it required, despite the cruel hand the explorers were dealt.</p>
|
<p>The woe of its best-known story is confounded by lesser-known, brighter elements—even if they’re only “thin atomies” in comparison—praising the worth of the endeavour and the value of the toil it required, despite the cruel hand the explorers were dealt.</p>
|
||||||
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
||||||
<?= Template::EbookCarousel(['carousel' => $carousel]) ?>
|
<?= Template::EbookCarousel(carousel: $carousel) ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
$ebookIds = [288, 485, 289, 908, 565, 2114];
|
$ebookIds = [288, 485, 289, 908, 565, 2114];
|
||||||
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(['title' => 'Edith Wharton’s Vision of Literary Art', 'css' => ['/css/blog.css'], 'highlight' => '', 'description' => '']) ?>
|
<?= Template::Header(title: 'Edith Wharton’s Vision of Literary Art', css: ['/css/blog.css']) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow blog">
|
<section class="narrow blog">
|
||||||
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
||||||
|
@ -33,7 +33,7 @@ $carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSq
|
||||||
<p><em>Hudson River Bracketed</em> is long out of print. Wharton patently lost the critical and commercial “<em>Wettgesang</em>” of the 1930s; even her sympathizers tend to admit that she’s in no way a star of that period, so the analogy to the Prologue in Heaven falls (or sounds) very flat.</p>
|
<p><em>Hudson River Bracketed</em> is long out of print. Wharton patently lost the critical and commercial “<em>Wettgesang</em>” of the 1930s; even her sympathizers tend to admit that she’s in no way a star of that period, so the analogy to the Prologue in Heaven falls (or sounds) very flat.</p>
|
||||||
<p>But whether Wharton’s second-last work falls entirely flat too is something that can be judged, if at all, only in the old way, by reading it. This wasn’t very easy to do until January 1, but now you can read our <a href="https://standardebooks.org/ebooks/edith-wharton/hudson-river-bracketed">new ebook edition for free</a> at Standard Ebooks.</p>
|
<p>But whether Wharton’s second-last work falls entirely flat too is something that can be judged, if at all, only in the old way, by reading it. This wasn’t very easy to do until January 1, but now you can read our <a href="https://standardebooks.org/ebooks/edith-wharton/hudson-river-bracketed">new ebook edition for free</a> at Standard Ebooks.</p>
|
||||||
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
||||||
<?= Template::EbookCarousel(['carousel' => $carousel]) ?>
|
<?= Template::EbookCarousel(carousel: $carousel) ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Blog', 'highlight' => '', 'description' => 'The Standard Ebooks blog.']) ?>
|
<?= Template::Header(title: 'Blog', description: 'The Standard Ebooks blog.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Blog</h1>
|
<h1>Blog</h1>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
$ebookIds = [565, 778, 561, 1059];
|
$ebookIds = [565, 778, 561, 1059];
|
||||||
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
$carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSql($ebookIds), $ebookIds, Ebook::class);
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(['title' => 'Joyce’s Ulysses, the Rubáiyát, and “Yes”', 'css' => ['/css/blog.css'], 'highlight' => '', 'description' => '']) ?>
|
<?= Template::Header(title: 'Joyce’s Ulysses, the Rubáiyát, and “Yes”', css: ['/css/blog.css']) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow blog">
|
<section class="narrow blog">
|
||||||
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
||||||
|
@ -44,7 +44,7 @@ $carousel = Db::Query('SELECT * from Ebooks where EbookId in ' . Db::CreateSetSq
|
||||||
<p>Speaking of consonance: Brown says, citing Ellmann, that the last record Joyce heard before he died was a performance of Lehmann’s setting of Fitzgerald’s Omar. As is often the case with Ellmann, this might not be true, but it’s not absurd to suppose that it could be.</p>
|
<p>Speaking of consonance: Brown says, citing Ellmann, that the last record Joyce heard before he died was a performance of Lehmann’s setting of Fitzgerald’s Omar. As is often the case with Ellmann, this might not be true, but it’s not absurd to suppose that it could be.</p>
|
||||||
<p>And as very often with <i>Ulysses</i>, what first seems like nothing, or like material for a joke, may also turn out to be something else too, even something that matters. If <i>Ulysses</i> doesn’t entirely affirm life, then it does, in this respect at least, reflect it.</p>
|
<p>And as very often with <i>Ulysses</i>, what first seems like nothing, or like material for a joke, may also turn out to be something else too, even something that matters. If <i>Ulysses</i> doesn’t entirely affirm life, then it does, in this respect at least, reflect it.</p>
|
||||||
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
<h2 id="ebooks-in-this-newsletter">Free ebooks in this post</h2>
|
||||||
<?= Template::EbookCarousel(['carousel' => $carousel]) ?>
|
<?= Template::EbookCarousel(carousel: $carousel) ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -100,7 +100,7 @@ foreach($ebooks as $ebook){
|
||||||
|
|
||||||
ksort($ebooksWithDescriptions);
|
ksort($ebooksWithDescriptions);
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Public Domain Day 2025 in Literature - Blog', 'highlight' => '', 'description' => 'Read about the new ebooks Standard Ebooks is releasing for Public Domain Day 2025!', 'css' => ['/css/public-domain-day.css']]) ?>
|
?><?= Template::Header(title: 'Public Domain Day 2025 in Literature - Blog', description: 'Read about the new ebooks Standard Ebooks is releasing for Public Domain Day 2025!', css: ['/css/public-domain-day.css']) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow blog has-hero">
|
<section class="narrow blog has-hero">
|
||||||
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
<nav class="breadcrumbs"><a href="/blog">Blog</a> →</nav>
|
||||||
|
@ -133,7 +133,7 @@ ksort($ebooksWithDescriptions);
|
||||||
<li>
|
<li>
|
||||||
<div>
|
<div>
|
||||||
<a href="<?= $ebookGroup['ebook']->Url ?>">
|
<a href="<?= $ebookGroup['ebook']->Url ?>">
|
||||||
<?= Template::RealisticEbook(['ebook' => $ebookGroup['ebook']]) ?>
|
<?= Template::RealisticEbook(ebook: $ebookGroup['ebook']) ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ catch(Safe\Exceptions\ApcuException){
|
||||||
|
|
||||||
$title = preg_replace('/s$/', '', ucfirst($class));
|
$title = preg_replace('/s$/', '', ucfirst($class));
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Downloads by ' . $title, 'highlight' => '', 'description' => 'Download zip files containing all of the Standard Ebooks in a given collection.']) ?>
|
?><?= Template::Header(title: 'Downloads by ' . $title, description: 'Download zip files containing all of the Standard Ebooks in a given collection.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="bulk-downloads">
|
<section class="bulk-downloads">
|
||||||
<h1>Downloads by <?= $title ?></h1>
|
<h1>Downloads by <?= $title ?></h1>
|
||||||
|
@ -80,7 +80,10 @@ $title = preg_replace('/s$/', '', ucfirst($class));
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::BulkDownloadTable(['label' => $title, 'collections' => $collection]); ?>
|
<?
|
||||||
|
/** @var array<stdClass> $collection */
|
||||||
|
?>
|
||||||
|
<?= Template::BulkDownloadTable(label: $title, collections: $collection); ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -54,7 +54,7 @@ catch(Exceptions\InvalidFileException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Downloading Ebook Collections', 'highlight' => '', 'description' => 'Download zip files containing all of the Standard Ebooks released in a given month.']) ?>
|
?><?= Template::Header(title: 'Downloading Ebook Collections', description: 'Download zip files containing all of the Standard Ebooks released in a given month.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Downloading Ebook Collections</h1>
|
<h1>Downloading Ebook Collections</h1>
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\apcu_fetch;
|
use function Safe\apcu_fetch;
|
||||||
|
|
||||||
$collection = null;
|
|
||||||
$collectionUrlName = HttpInput::Str(GET, 'collection');
|
|
||||||
$collection = null;
|
|
||||||
$authorUrlName = HttpInput::Str(GET, 'author');
|
|
||||||
$canDownload = false;
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
$collection = null;
|
||||||
|
$collectionUrlName = HttpInput::Str(GET, 'collection');
|
||||||
|
$authorUrlName = HttpInput::Str(GET, 'author');
|
||||||
|
$canDownload = false;
|
||||||
|
|
||||||
if(Session::$User?->Benefits->CanBulkDownload){
|
if(Session::$User?->Benefits->CanBulkDownload){
|
||||||
$canDownload = true;
|
$canDownload = true;
|
||||||
}
|
}
|
||||||
|
@ -33,10 +32,6 @@ try{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($collection === null){
|
|
||||||
throw new Exceptions\CollectionNotFoundException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($authorUrlName !== null){
|
if($authorUrlName !== null){
|
||||||
|
@ -65,6 +60,10 @@ try{
|
||||||
throw new Exceptions\AuthorNotFoundException();
|
throw new Exceptions\AuthorNotFoundException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($collection === null){
|
||||||
|
throw new Exceptions\CollectionNotFoundException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(Exceptions\AuthorNotFoundException){
|
catch(Exceptions\AuthorNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
|
@ -73,17 +72,17 @@ catch(Exceptions\CollectionNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Download ', 'highlight' => '', 'description' => 'Download zip files containing all of the Standard Ebooks released in a given month.']) ?>
|
?><?= Template::Header(title: 'Download ', description: 'Download zip files containing all of the Standard Ebooks released in a given month.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="bulk-downloads">
|
<section class="bulk-downloads">
|
||||||
<h1>Download the <?= $collection?->Label ?> Collection</h1>
|
<h1>Download the <?= $collection->Label ?> Collection</h1>
|
||||||
<? if($canDownload){ ?>
|
<? if($canDownload){ ?>
|
||||||
<p>Select the ebook format in which you’d like to download this collection.</p>
|
<p>Select the ebook format in which you’d like to download this collection.</p>
|
||||||
<p>You can also read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which ebook format to download</a>.</p>
|
<p>You can also read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which ebook format to download</a>.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<p><a href="/about#patrons-circle">Patrons circle members</a> can download zip files containing all of the ebooks in a collection. You can <a href="/donate#patrons-circle">join the Patrons Circle</a> with a small donation in support of our continuing mission to create free, beautiful digital literature.</p>
|
<p><a href="/about#patrons-circle">Patrons circle members</a> can download zip files containing all of the ebooks in a collection. You can <a href="/donate#patrons-circle">join the Patrons Circle</a> with a small donation in support of our continuing mission to create free, beautiful digital literature.</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<?= Template::BulkDownloadTable(['label' => 'Collection', 'collections' => [$collection]]); ?>
|
<?= Template::BulkDownloadTable(label: 'Collection', collections: [$collection]); ?>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<?= Template::Footer() ?>
|
<?= Template::Footer() ?>
|
||||||
|
|
|
@ -4,7 +4,7 @@ if(Session::$User?->Benefits->CanBulkDownload){
|
||||||
$canDownload = true;
|
$canDownload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Bulk Ebook Downloads', 'highlight' => '', 'description' => 'Download zip files containing all of the Standard Ebooks released in a given month.']) ?>
|
?><?= Template::Header(title: 'Bulk Ebook Downloads', description: 'Download zip files containing all of the Standard Ebooks released in a given month.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<h1>Bulk Ebook Downloads</h1>
|
<h1>Bulk Ebook Downloads</h1>
|
||||||
|
|
|
@ -16,7 +16,7 @@ try{
|
||||||
catch(Exceptions\CollectionNotFoundException){
|
catch(Exceptions\CollectionNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $pageTitle, 'feedUrl' => $feedUrl, 'feedTitle' => $feedTitle, 'highlight' => 'ebooks', 'description' => $pageDescription]) ?>
|
?><?= Template::Header(title: $pageTitle, feedUrl: $feedUrl, feedTitle: $feedTitle, highlight: 'ebooks', description: $pageDescription) ?>
|
||||||
<main class="ebooks">
|
<main class="ebooks">
|
||||||
<h1 class="is-collection"><?= $pageHeader ?></h1>
|
<h1 class="is-collection"><?= $pageHeader ?></h1>
|
||||||
<?= Template::DonationCounter() ?>
|
<?= Template::DonationCounter() ?>
|
||||||
|
@ -32,7 +32,7 @@ catch(Exceptions\CollectionNotFoundException){
|
||||||
<? if(sizeof($collection->Ebooks) == 0){ ?>
|
<? if(sizeof($collection->Ebooks) == 0){ ?>
|
||||||
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::EbookGrid(['ebooks' => $collection->Ebooks, 'view' => Enums\ViewType::Grid, 'collection' => $collection]) ?>
|
<?= Template::EbookGrid(ebooks: $collection->Ebooks, view: Enums\ViewType::Grid, collection: $collection) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if(Session::$User?->Benefits->CanEditCollections){ ?>
|
<? if(Session::$User?->Benefits->CanEditCollections){ ?>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?
|
<?
|
||||||
$collections = Collection::GetAll();
|
$collections = Collection::GetAll();
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Ebook Collections', 'highlight' => '', 'description' => 'Browse collections of Standard Ebooks.']) ?>
|
?><?= Template::Header(title: 'Ebook Collections', description: 'Browse collections of Standard Ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<h1>Ebook Collections</h1>
|
<h1>Ebook Collections</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'A Basic Standard Ebooks Source Folder', 'manual' => true, 'highlight' => 'contribute', 'description' => 'All Standard Ebooks source folders have the same basic structure, described here.']) ?>
|
<?= Template::Header(title: 'A Basic Standard Ebooks Source Folder', isManual: true, highlight: 'contribute', description: 'All Standard Ebooks source folders have the same basic structure, described here.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article id="a-basic-standard-ebooks-source-folder">
|
<article id="a-basic-standard-ebooks-source-folder">
|
||||||
<h1>A Basic Standard Ebooks Source Folder</h1>
|
<h1>A Basic Standard Ebooks Source Folder</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Collections Policy', 'highlight' => 'contribute', 'description' => 'Standard Ebooks only accepts certain kinds of ebooks for production and hosting. This is the full list.']) ?>
|
<?= Template::Header(title: 'Collections Policy', highlight: 'contribute', description: 'Standard Ebooks only accepts certain kinds of ebooks for production and hosting. This is the full list.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<hgroup>
|
<hgroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Common Issues When Working on Public Domain Ebooks', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A list of common issues encountered when converting from public domain transcriptions.']) ?>
|
<?= Template::Header(title: 'Common Issues When Working on Public Domain Ebooks', isManual: true, highlight: 'contribute', description: 'A list of common issues encountered when converting from public domain transcriptions.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Common Issues When Working on Public Domain Ebooks</h1>
|
<h1>Common Issues When Working on Public Domain Ebooks</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Choose and Create a Cover Image', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to choosing, clearing, and formatting your cover image.']) ?>
|
<?= Template::Header(title: 'How to Choose and Create a Cover Image', isManual: true, highlight: 'contribute', description: 'A guide to choosing, clearing, and formatting your cover image.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Choose and Create a Cover Image</h1>
|
<h1>How to Choose and Create a Cover Image</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Conquer Complex Drama Formatting', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to formatting any complex plays or dramatic dialog sections.']) ?>
|
<?= Template::Header(title: 'How to Conquer Complex Drama Formatting', isManual: true, highlight: 'contribute', description: 'A guide to formatting any complex plays or dramatic dialog sections.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Conquer Complex Drama Formatting</h1>
|
<h1>How to Conquer Complex Drama Formatting</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Create Figures for Music Scores', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to producing SVG figures of music notation.']) ?>
|
<?= Template::Header(title: 'How to Create Figures for Music Scores', isManual: true, highlight: 'contribute', description: 'A guide to producing SVG figures of music notation.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Create Figures for Music Scores</h1>
|
<h1>How to Create Figures for Music Scores</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Create SVGs from Maps with Several Colors', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to producing SVG from images such as maps with more than a single color.']) ?>
|
<?= Template::Header(title: 'How to Create SVGs from Maps with Several Colors', isManual: true, highlight: 'contribute', description: 'A guide to producing SVG from images such as maps with more than a single color.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Create SVGs from Maps with Several Colors</h1>
|
<h1>How to Create SVGs from Maps with Several Colors</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Review an Ebook Production for Publication', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to proofread and review an ebook production for publication.']) ?>
|
<?= Template::Header(title: 'How to Review an Ebook Production for Publication', isManual: true, highlight: 'contribute', description: 'A guide to proofread and review an ebook production for publication.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Review an Ebook Production for Publication</h1>
|
<h1>How to Review an Ebook Production for Publication</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How to Structure and Style Large Poetic Productions', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A guide to formatting poetry collections, long narrative poems, and unusual poetic features.']) ?>
|
<?= Template::Header(title: 'How to Structure and Style Large Poetic Productions', isManual: true, highlight: 'contribute', description: 'A guide to formatting poetry collections, long narrative poems, and unusual poetic features.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>How to Structure and Style Large Poetic Productions</h1>
|
<h1>How to Structure and Style Large Poetic Productions</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'How-to Guides For Difficult Productions', 'manual' => true, 'highlight' => 'contribute', 'description' => 'Guides on how to produce more difficult productions.']) ?>
|
<?= Template::Header(title: 'How-to Guides For Difficult Productions', isManual: true, highlight: 'contribute', description: 'Guides on how to produce more difficult productions.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>How-to Guides</h1>
|
<h1>How-to Guides</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Things to Look Out For When Proofreading', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A list of things to look out for when proofreading.']) ?>
|
<?= Template::Header(title: 'Things to Look Out For When Proofreading', isManual: true, highlight: 'contribute', description: 'A list of things to look out for when proofreading.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Things to Look Out For When Proofreading</h1>
|
<h1>Things to Look Out For When Proofreading</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Get Involved', 'highlight' => 'contribute', 'description' => 'Details on how to contribute your time and talent to the volunteer-driven Standard Ebooks project.']) ?>
|
<?= Template::Header(title: 'Get Involved', highlight: 'contribute', description: 'Details on how to contribute your time and talent to the volunteer-driven Standard Ebooks project.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article class="has-hero">
|
<article class="has-hero">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Producing an Ebook for Standard Ebooks', 'highlight' => 'contribute', 'description' => 'A high-level outline of the process of producing an ebook for Standard Ebooks.']) ?>
|
<?= Template::Header(title: 'Producing an Ebook for Standard Ebooks', highlight: 'contribute', description: 'A high-level outline of the process of producing an ebook for Standard Ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Producing an Ebook for Standard Ebooks</h1>
|
<h1>Producing an Ebook for Standard Ebooks</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Producing an Ebook, Step by Step', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A detailed step-by-step description of the complete process of producing an ebook for Standard Ebooks, start to finish.']) ?>
|
<?= Template::Header(title: 'Producing an Ebook, Step by Step', isManual: true, highlight: 'contribute', description: 'A detailed step-by-step description of the complete process of producing an ebook for Standard Ebooks, start to finish.') ?>
|
||||||
<main class="manual">
|
<main class="manual">
|
||||||
<article class="step-by-step-guide">
|
<article class="step-by-step-guide">
|
||||||
<h1>Producing an Ebook, Step by Step</h1>
|
<h1>Producing an Ebook, Step by Step</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Report Errors Upstream', 'highlight' => 'contribute', 'description' => 'Our guide to reporting errors to Gutenberg and other sources.']) ?>
|
<?= Template::Header(title: 'Report Errors Upstream', highlight: 'contribute', description: 'Our guide to reporting errors to Gutenberg and other sources.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Report Errors Upstream</h1>
|
<h1>Report Errors Upstream</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Report Errors', 'highlight' => 'contribute', 'description' => 'How to report a typo or error you’ve found in a Standard Ebooks ebook.']) ?>
|
<?= Template::Header(title: 'Report Errors', highlight: 'contribute', description: 'How to report a typo or error you’ve found in a Standard Ebooks ebook.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Report Errors</h1>
|
<h1>Report Errors</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Research Spreadsheets', 'highlight' => 'contribute', 'description' => 'A list of spreadsheets created and used by Standard Ebooks producers.']) ?>
|
<?= Template::Header(title: 'Research Spreadsheets', highlight: 'contribute', description: 'A list of spreadsheets created and used by Standard Ebooks producers.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Research Spreadsheets</h1>
|
<h1>Research Spreadsheets</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Tips for Editors and Proofreaders', 'manual' => true, 'highlight' => 'contribute', 'description' => 'A list of tips and tricks for people who’d like to proofread a Standard Ebooks ebook.']) ?>
|
<?= Template::Header(title: 'Tips for Editors and Proofreaders', isManual: true, highlight: 'contribute', description: 'A list of tips and tricks for people who’d like to proofread a Standard Ebooks ebook.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Tips for Editors and Proofreaders</h1>
|
<h1>Tips for Editors and Proofreaders</h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Uncategorized Art Resources', 'highlight' => 'contribute', 'description' => 'A list of US-PD art books for use when conducting cover art research.']) ?>
|
<?= Template::Header(title: 'Uncategorized Art Resources', highlight: 'contribute', description: 'A list of US-PD art books for use when conducting cover art research.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article id="a-basic-standard-ebooks-source-folder">
|
<article id="a-basic-standard-ebooks-source-folder">
|
||||||
<h1>Uncategorized Art Resources</h1>
|
<h1>Uncategorized Art Resources</h1>
|
||||||
|
|
|
@ -3,7 +3,7 @@ $beginnerEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDiffic
|
||||||
$intermediateEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDifficulty::Intermediate);
|
$intermediateEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDifficulty::Intermediate);
|
||||||
$advancedEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDifficulty::Advanced);
|
$advancedEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDifficulty::Advanced);
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(['title' => 'Wanted Ebooks', 'highlight' => 'contribute', 'description' => 'A list of ebooks the Standard Ebooks editor would like to see produced, including suggestions for first-time producers.']) ?>
|
<?= Template::Header(title: 'Wanted Ebooks', highlight: 'contribute', description: 'A list of ebooks the Standard Ebooks editor would like to see produced, including suggestions for first-time producers.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Wanted Ebooks</h1>
|
<h1>Wanted Ebooks</h1>
|
||||||
|
@ -18,13 +18,13 @@ $advancedEbooks = Ebook::GetByIsWantedAndDifficulty(Enums\EbookPlaceholderDiffic
|
||||||
<h2>For your first production</h2>
|
<h2>For your first production</h2>
|
||||||
<p>If nothing on the list below interests you, you can pitch us something else you’d like to work on.</p>
|
<p>If nothing on the list below interests you, you can pitch us something else you’d like to work on.</p>
|
||||||
<p>First productions should be on the shorter side (less than 100,000 words maximum) and without too many complex formatting issues like illustrations, significant endnotes, letters, poems, etc. Most short plain fiction novels fall in this category.</p>
|
<p>First productions should be on the shorter side (less than 100,000 words maximum) and without too many complex formatting issues like illustrations, significant endnotes, letters, poems, etc. Most short plain fiction novels fall in this category.</p>
|
||||||
<?= Template::WantedEbooksList(['ebooks' => $beginnerEbooks, 'showPlaceholderMetadata' => Session::$User?->Benefits->CanEditEbookPlaceholders]) ?>
|
<?= Template::WantedEbooksList(ebooks: $beginnerEbooks, showPlaceholderMetadata: Session::$User->Benefits->CanEditEbookPlaceholders ?? false) ?>
|
||||||
|
|
||||||
<h2>Moderate-difficulty productions</h2>
|
<h2>Moderate-difficulty productions</h2>
|
||||||
<?= Template::WantedEbooksList(['ebooks' => $intermediateEbooks, 'showPlaceholderMetadata' => Session::$User?->Benefits->CanEditEbookPlaceholders]) ?>
|
<?= Template::WantedEbooksList(ebooks: $intermediateEbooks, showPlaceholderMetadata: Session::$User->Benefits->CanEditEbookPlaceholders ?? false) ?>
|
||||||
|
|
||||||
<h2>Advanced productions</h2>
|
<h2>Advanced productions</h2>
|
||||||
<?= Template::WantedEbooksList(['ebooks' => $advancedEbooks, 'showPlaceholderMetadata' => Session::$User?->Benefits->CanEditEbookPlaceholders]) ?>
|
<?= Template::WantedEbooksList(ebooks: $advancedEbooks, showPlaceholderMetadata: Session::$User->Benefits->CanEditEbookPlaceholders ?? false) ?>
|
||||||
|
|
||||||
<h2 id="verne">Jules Verne</h2>
|
<h2 id="verne">Jules Verne</h2>
|
||||||
<p>Verne has a complex publication and translation history. Please review these notes before starting any Verne books.</p>
|
<p>Verne has a complex publication and translation history. Please review these notes before starting any Verne books.</p>
|
||||||
|
|
|
@ -5,15 +5,15 @@ $newsletterSubscriberCount = floor(Db::QueryInt('
|
||||||
where IsConfirmed = true
|
where IsConfirmed = true
|
||||||
') / 100) * 100;
|
') / 100) * 100;
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'Donate', 'highlight' => 'donate', 'description' => 'Donate to Standard Ebooks.']) ?>
|
?><?= Template::Header(title: 'Donate', highlight: 'donate', description: 'Donate to Standard Ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="donate narrow has-hero">
|
<section class="donate narrow has-hero">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h1>Donate to Standard Ebooks</h1>
|
<h1>Donate to Standard Ebooks</h1>
|
||||||
<p>and help bring the beauty of literature to the digital age</p>
|
<p>and help bring the beauty of literature to the digital age</p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<?= Template::DonationCounter(['autoHide' => false, 'showDonateButton' => false]) ?>
|
<?= Template::DonationCounter(autoHide: false, showDonateButton: false) ?>
|
||||||
<?= Template::DonationProgress(['autoHide' => false, 'showDonateButton' => false]) ?>
|
<?= Template::DonationProgress(autoHide: false, showDonateButton: false) ?>
|
||||||
<picture data-caption="The Quiet Hour. Albert Chevallier Tayler, 1925">
|
<picture data-caption="The Quiet Hour. Albert Chevallier Tayler, 1925">
|
||||||
<source srcset="/images/the-quiet-hour@2x.avif 2x, /images/the-quiet-hour.avif 1x" type="image/avif"/>
|
<source srcset="/images/the-quiet-hour@2x.avif 2x, /images/the-quiet-hour.avif 1x" type="image/avif"/>
|
||||||
<source srcset="/images/the-quiet-hour@2x.jpg 2x, /images/the-quiet-hour.jpg 1x" type="image/jpg"/>
|
<source srcset="/images/the-quiet-hour@2x.jpg 2x, /images/the-quiet-hour.jpg 1x" type="image/jpg"/>
|
||||||
|
|
|
@ -40,12 +40,9 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(
|
<?= Template::Header(
|
||||||
[
|
title: 'Delete ' . $ebook->Title,
|
||||||
'title' => 'Delete ' . $ebook->Title,
|
css: ['/css/ebook-placeholder.css'],
|
||||||
'css' => ['/css/ebook-placeholder.css'],
|
description: 'Delete ' . $ebook->Title
|
||||||
'highlight' => '',
|
|
||||||
'description' => 'Delete ' . $ebook->Title
|
|
||||||
]
|
|
||||||
) ?>
|
) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
|
@ -55,7 +52,7 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
</nav>
|
</nav>
|
||||||
<h1>Delete</h1>
|
<h1>Delete</h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<form method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $ebook->Url ?>">
|
<form method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $ebook->Url ?>">
|
||||||
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Delete->value ?>" />
|
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Delete->value ?>" />
|
||||||
|
|
|
@ -40,12 +40,9 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(
|
<?= Template::Header(
|
||||||
[
|
title: 'Edit ' . $ebook->Title,
|
||||||
'title' => 'Edit ' . $ebook->Title,
|
css: ['/css/ebook-placeholder.css'],
|
||||||
'css' => ['/css/ebook-placeholder.css'],
|
description: 'Edit ' . $ebook->Title
|
||||||
'highlight' => '',
|
|
||||||
'description' => 'Edit ' . $ebook->Title
|
|
||||||
]
|
|
||||||
) ?>
|
) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
|
@ -55,11 +52,11 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
</nav>
|
</nav>
|
||||||
<h1>Edit</h1>
|
<h1>Edit</h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $ebook->Url ?>" autocomplete="off">
|
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $ebook->Url ?>" autocomplete="off">
|
||||||
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Put->value ?>" />
|
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Put->value ?>" />
|
||||||
<?= Template::EbookPlaceholderForm(['ebook' => $ebook, 'isEditForm' => true]) ?>
|
<?= Template::EbookPlaceholderForm(ebook: $ebook, isEditForm: true) ?>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button>Save</button>
|
<button>Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,12 +24,11 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(
|
?><?= Template::Header(
|
||||||
[
|
title: strip_tags($ebook->TitleWithCreditsHtml),
|
||||||
'title' => strip_tags($ebook->TitleWithCreditsHtml),
|
css: ['/css/ebook-placeholder.css'],
|
||||||
'css' => ['/css/ebook-placeholder.css'],
|
highlight: 'ebooks',
|
||||||
'highlight' => 'ebooks',
|
canonicalUrl: SITE_URL . $ebook->Url
|
||||||
'canonicalUrl' => SITE_URL . $ebook->Url
|
)
|
||||||
])
|
|
||||||
?>
|
?>
|
||||||
<main>
|
<main>
|
||||||
<article class="ebook ebook-placeholder" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
<article class="ebook ebook-placeholder" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
||||||
|
@ -77,7 +76,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<? if(sizeof($ebook->CollectionMemberships) > 0){ ?>
|
<? if(sizeof($ebook->CollectionMemberships) > 0){ ?>
|
||||||
<? foreach($ebook->CollectionMemberships as $collectionMembership){ ?>
|
<? foreach($ebook->CollectionMemberships as $collectionMembership){ ?>
|
||||||
<p>
|
<p>
|
||||||
<?= Template::CollectionDescriptor(['collectionMembership' => $collectionMembership]) ?>.
|
<?= Template::CollectionDescriptor(collectionMembership: $collectionMembership) ?>.
|
||||||
</p>
|
</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
@ -111,7 +110,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<? if(Session::$User?->Benefits->CanEditEbooks || Session::$User?->Benefits->CanEditEbookPlaceholders){ ?>
|
<? if(Session::$User?->Benefits->CanEditEbooks || Session::$User?->Benefits->CanEditEbookPlaceholders){ ?>
|
||||||
<?= Template::EbookMetadata(['ebook' => $ebook, 'showPlaceholderMetadata' => Session::$User->Benefits->CanEditEbookPlaceholders]) ?>
|
<?= Template::EbookMetadata(ebook: $ebook, showPlaceholderMetadata: Session::$User->Benefits->CanEditEbookPlaceholders) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if(Session::$User?->Benefits->CanEditProjects || Session::$User?->Benefits->CanManageProjects || Session::$User?->Benefits->CanReviewProjects){ ?>
|
<? if(Session::$User?->Benefits->CanEditProjects || Session::$User?->Benefits->CanManageProjects || Session::$User?->Benefits->CanReviewProjects){ ?>
|
||||||
|
@ -123,7 +122,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<a href="<?= $ebook->ProjectInProgress->EditUrl ?>">Edit project</a>
|
<a href="<?= $ebook->ProjectInProgress->EditUrl ?>">Edit project</a>
|
||||||
</p>
|
</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<?= Template::ProjectDetailsTable(['project' => $ebook->ProjectInProgress, 'showTitle' => false]) ?>
|
<?= Template::ProjectDetailsTable(project: $ebook->ProjectInProgress, showTitle: false) ?>
|
||||||
</section>
|
</section>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
|
@ -137,7 +136,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<? if(sizeof($ebook->PastProjects) == 0){ ?>
|
<? if(sizeof($ebook->PastProjects) == 0){ ?>
|
||||||
<p class="empty-notice">None.</p>
|
<p class="empty-notice">None.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::ProjectsTable(['projects' => $ebook->PastProjects, 'includeTitle' => false, 'showEditButton' => Session::$User->Benefits->CanEditProjects]) ?>
|
<?= Template::ProjectsTable(projects: $ebook->PastProjects, includeTitle: false, showEditButton: Session::$User->Benefits->CanEditProjects) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</section>
|
</section>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
<?
|
<?
|
||||||
use function Safe\session_unset;
|
use function Safe\session_unset;
|
||||||
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
$isCreated = HttpInput::Bool(SESSION, 'is-ebook-placeholder-created') ?? false;
|
|
||||||
$isOnlyProjectCreated = HttpInput::Bool(SESSION, 'is-only-ebook-project-created') ?? false;
|
|
||||||
$isDeleted = HttpInput::Bool(SESSION, 'is-ebook-placeholder-deleted') ?? false;
|
|
||||||
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
|
||||||
$ebook = HttpInput::SessionObject('ebook', Ebook::class);
|
|
||||||
$project = HttpInput::SessionObject('project', Project::class);
|
|
||||||
$deletedEbookTitle = '';
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(Session::$User === null){
|
if(Session::$User === null){
|
||||||
|
@ -20,6 +11,16 @@ try{
|
||||||
throw new Exceptions\InvalidPermissionsException();
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$isCreated = HttpInput::Bool(SESSION, 'is-ebook-placeholder-created') ?? false;
|
||||||
|
$isOnlyProjectCreated = HttpInput::Bool(SESSION, 'is-only-ebook-project-created') ?? false;
|
||||||
|
$isDeleted = HttpInput::Bool(SESSION, 'is-ebook-placeholder-deleted') ?? false;
|
||||||
|
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
||||||
|
$ebook = HttpInput::SessionObject('ebook', Ebook::class);
|
||||||
|
$project = HttpInput::SessionObject('project', Project::class);
|
||||||
|
$deletedEbookTitle = '';
|
||||||
|
|
||||||
if($isCreated || $isOnlyProjectCreated){
|
if($isCreated || $isOnlyProjectCreated){
|
||||||
// We got here because an `Ebook` was successfully created.
|
// We got here because an `Ebook` was successfully created.
|
||||||
http_response_code(Enums\HttpCode::Created->value);
|
http_response_code(Enums\HttpCode::Created->value);
|
||||||
|
@ -70,18 +71,15 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?= Template::Header(
|
<?= Template::Header(
|
||||||
[
|
title: 'Create an Ebook Placeholder',
|
||||||
'title' => 'Create an Ebook Placeholder',
|
css: ['/css/ebook-placeholder.css', '/css/project.css'],
|
||||||
'css' => ['/css/ebook-placeholder.css', '/css/project.css'],
|
description: 'Create a placeholder for an ebook not yet in the collection.'
|
||||||
'highlight' => '',
|
|
||||||
'description' => 'Create a placeholder for an ebook not yet in the collection.'
|
|
||||||
]
|
|
||||||
) ?>
|
) ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Create an Ebook Placeholder</h1>
|
<h1>Create an Ebook Placeholder</h1>
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(exception: $exception) ?>
|
||||||
|
|
||||||
<? if(isset($createdEbook)){ ?>
|
<? if(isset($createdEbook)){ ?>
|
||||||
<? if($isOnlyProjectCreated){ ?>
|
<? if($isOnlyProjectCreated){ ?>
|
||||||
|
@ -94,7 +92,7 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="/ebook-placeholders" autocomplete="off">
|
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="/ebook-placeholders" autocomplete="off">
|
||||||
<?= Template::EbookPlaceholderForm(['ebook' => $ebook]) ?>
|
<?= Template::EbookPlaceholderForm(ebook: $ebook ?? new Ebook()) ?>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button>Submit</button>
|
<button>Submit</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -61,7 +61,7 @@ try{
|
||||||
catch(Exceptions\InvalidFileException | Exceptions\EbookNotFoundException){
|
catch(Exceptions\InvalidFileException | Exceptions\EbookNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => 'Your Download Has Started!', 'downloadUrl' => $downloadUrl]) ?>
|
?><?= Template::Header(title: 'Your Download Has Started!', downloadUrl: $downloadUrl) ?>
|
||||||
<main class="donate">
|
<main class="donate">
|
||||||
<h1>Your Download Has Started!</h1>
|
<h1>Your Download Has Started!</h1>
|
||||||
<div class="thank-you-container">
|
<div class="thank-you-container">
|
||||||
|
|
|
@ -71,7 +71,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
|
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => strip_tags($ebook->TitleWithCreditsHtml) . ' - Free ebook download', 'ogType' => 'book', 'coverUrl' => $ebook->DistCoverUrl, 'highlight' => 'ebooks', 'description' => 'Free epub ebook download of the Standard Ebooks edition of ' . $ebook->Title . ': ' . $ebook->Description, 'canonicalUrl' => SITE_URL . $ebook->Url]) ?>
|
?><?= Template::Header(title: strip_tags($ebook->TitleWithCreditsHtml) . ' - Free ebook download', ogType: 'book', coverUrl: $ebook->DistCoverUrl, highlight: 'ebooks', description: 'Free epub ebook download of the Standard Ebooks edition of ' . $ebook->Title . ': ' . $ebook->Description, canonicalUrl: SITE_URL . $ebook->Url) ?>
|
||||||
<main>
|
<main>
|
||||||
<article class="ebook" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
<article class="ebook" typeof="schema:Book" about="<?= $ebook->Url ?>">
|
||||||
<meta property="schema:description" content="<?= Formatter::EscapeHtml($ebook->Description) ?>"/>
|
<meta property="schema:description" content="<?= Formatter::EscapeHtml($ebook->Description) ?>"/>
|
||||||
|
@ -126,7 +126,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<? if(sizeof($ebook->CollectionMemberships) > 0){ ?>
|
<? if(sizeof($ebook->CollectionMemberships) > 0){ ?>
|
||||||
<? foreach($ebook->CollectionMemberships as $collectionMembership){ ?>
|
<? foreach($ebook->CollectionMemberships as $collectionMembership){ ?>
|
||||||
<p>
|
<p>
|
||||||
<?= Template::CollectionDescriptor(['collectionMembership' => $collectionMembership]) ?>.
|
<?= Template::CollectionDescriptor(collectionMembership: $collectionMembership) ?>.
|
||||||
</p>
|
</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
@ -188,7 +188,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<p class="us-pd-warning">This ebook is thought to be free of copyright restrictions in the United States. It may still be under copyright in other countries. If you’re not located in the United States, you must check your local laws to verify that this ebook is free of copyright restrictions in the country you’re located in before accessing, downloading, or using it.</p>
|
<p class="us-pd-warning">This ebook is thought to be free of copyright restrictions in the United States. It may still be under copyright in other countries. If you’re not located in the United States, you must check your local laws to verify that this ebook is free of copyright restrictions in the country you’re located in before accessing, downloading, or using it.</p>
|
||||||
|
|
||||||
<div class="downloads-container">
|
<div class="downloads-container">
|
||||||
<?= Template::RealisticEbook(['ebook' => $ebook]) ?>
|
<?= Template::RealisticEbook(ebook: $ebook) ?>
|
||||||
<div>
|
<div>
|
||||||
<section id="download">
|
<section id="download">
|
||||||
<h3>Download for ereaders</h3>
|
<h3>Download for ereaders</h3>
|
||||||
|
@ -383,13 +383,13 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<? if(Session::$User?->Benefits->CanEditEbooks){ ?>
|
<? if(Session::$User?->Benefits->CanEditEbooks){ ?>
|
||||||
<?= Template::EbookMetadata(['ebook' => $ebook]) ?>
|
<?= Template::EbookMetadata(ebook: $ebook) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if(sizeof($carousel) > 0){ ?>
|
<? if(sizeof($carousel) > 0){ ?>
|
||||||
<aside id="more-ebooks">
|
<aside id="more-ebooks">
|
||||||
<h2>More free<? if($carouselTag !== null){ ?> <?= strtolower($carouselTag->Name) ?><? } ?> ebooks</h2>
|
<h2>More free<? if($carouselTag !== null){ ?> <?= strtolower($carouselTag->Name) ?><? } ?> ebooks</h2>
|
||||||
<?= Template::EbookCarousel(['carousel' => $carousel, 'isMultiSize' => true]) ?>
|
<?= Template::EbookCarousel(carousel: $carousel, isMultiSize: true) ?>
|
||||||
</aside>
|
</aside>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -7,8 +7,8 @@ $pages = 0;
|
||||||
$perPage = HttpInput::Int(GET, 'per-page') ?? EBOOKS_PER_PAGE;
|
$perPage = HttpInput::Int(GET, 'per-page') ?? EBOOKS_PER_PAGE;
|
||||||
$query = HttpInput::Str(GET, 'query') ?? '';
|
$query = HttpInput::Str(GET, 'query') ?? '';
|
||||||
$tags = HttpInput::Array(GET, 'tags') ?? [];
|
$tags = HttpInput::Array(GET, 'tags') ?? [];
|
||||||
$view = Enums\ViewType::tryFrom(HttpInput::Str(GET, 'view') ?? '');
|
$view = Enums\ViewType::tryFrom(HttpInput::Str(GET, 'view') ?? '') ?? Enums\ViewType::Grid;
|
||||||
$sort = Enums\EbookSortType::tryFrom(HttpInput::Str(GET, 'sort') ?? '');
|
$sort = Enums\EbookSortType::tryFrom(HttpInput::Str(GET, 'sort') ?? '') ?? Enums\EbookSortType::Default;
|
||||||
$queryString = '';
|
$queryString = '';
|
||||||
$queryStringParams = [];
|
$queryStringParams = [];
|
||||||
$queryStringWithoutPage = '';
|
$queryStringWithoutPage = '';
|
||||||
|
@ -38,13 +38,8 @@ try{
|
||||||
$sort = Enums\EbookSortType::Newest;
|
$sort = Enums\EbookSortType::Newest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're passed string values that are the same as the defaults, set them to null so that we can have cleaner query strings in the navigation footer.
|
|
||||||
if($view === Enums\ViewType::Grid){
|
|
||||||
$view = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(($sort == Enums\EbookSortType::Newest && $query == '') || ($sort == Enums\EbookSortType::Relevance && $query != '')){
|
if(($sort == Enums\EbookSortType::Newest && $query == '') || ($sort == Enums\EbookSortType::Relevance && $query != '')){
|
||||||
$sort = null;
|
$sort = Enums\EbookSortType::Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sizeof($tags) == 1 && mb_strtolower($tags[0]) == 'all'){
|
if(sizeof($tags) == 1 && mb_strtolower($tags[0]) == 'all'){
|
||||||
|
@ -61,11 +56,12 @@ try{
|
||||||
$queryStringParams['tags'] = $tags;
|
$queryStringParams['tags'] = $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($view !== null){
|
// If we're passed string values that are the same as the defaults, don't include them in the query string so that we can have cleaner query strings in the navigation footer.
|
||||||
|
if($view != Enums\ViewType::Grid){
|
||||||
$queryStringParams['view'] = $view->value;
|
$queryStringParams['view'] = $view->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($sort !== null){
|
if($sort != Enums\EbookSortType::Default){
|
||||||
$queryStringParams['sort'] = $sort->value;
|
$queryStringParams['sort'] = $sort->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +130,7 @@ catch(Exceptions\PageOutOfBoundsException){
|
||||||
header('Location: ' . $url);
|
header('Location: ' . $url);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $pageTitle, 'highlight' => 'ebooks', 'description' => $pageDescription, 'canonicalUrl' => $canonicalUrl]) ?>
|
?><?= Template::Header(title: $pageTitle, highlight: 'ebooks', description: $pageDescription, canonicalUrl: $canonicalUrl) ?>
|
||||||
<main class="ebooks">
|
<main class="ebooks">
|
||||||
<h1><?= $pageHeader ?></h1>
|
<h1><?= $pageHeader ?></h1>
|
||||||
<?= Template::DonationCounter() ?>
|
<?= Template::DonationCounter() ?>
|
||||||
|
@ -142,11 +138,12 @@ catch(Exceptions\PageOutOfBoundsException){
|
||||||
|
|
||||||
<?= Template::DonationAlert() ?>
|
<?= Template::DonationAlert() ?>
|
||||||
|
|
||||||
<?= Template::SearchForm(['query' => $query, 'tags' => $tags, 'sort' => $sort, 'view' => $view, 'perPage' => $perPage]) ?>
|
<?= Template::SearchForm(query: $query, tags: $tags, sort: $sort, view: $view, perPage: $perPage) ?>
|
||||||
|
|
||||||
<? if(sizeof($ebooks) == 0){ ?>
|
<? if(sizeof($ebooks) == 0){ ?>
|
||||||
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => $view]) ?>
|
<?= Template::EbookGrid(ebooks: $ebooks, view: $view) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if(sizeof($ebooks) > 0){ ?>
|
<? if(sizeof($ebooks) > 0){ ?>
|
||||||
<nav class="pagination">
|
<nav class="pagination">
|
||||||
|
|
|
@ -23,7 +23,7 @@ if($feedType == Enums\FeedType::Atom){
|
||||||
$title = 'Standard Ebooks Atom Feeds';
|
$title = 'Standard Ebooks Atom Feeds';
|
||||||
}
|
}
|
||||||
|
|
||||||
?><?= Template::Header(['title' => 'The Standard Ebooks OPDS feed', 'highlight' => '', 'description' => 'Get access to the Standard Ebooks OPDS feed for use in ereading programs in scripting.']) ?>
|
?><?= Template::Header(title: 'The Standard Ebooks OPDS feed', description: 'Get access to the Standard Ebooks OPDS feed for use in ereading programs in scripting.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<? if($feedType == Enums\FeedType::Opds){ ?>
|
<? if($feedType == Enums\FeedType::Opds){ ?>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Atom 1.0 Ebook Feeds', 'description' => 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks.']) ?>
|
<?= Template::Header(title: 'Atom 1.0 Ebook Feeds', description: 'A list of available Atom 1.0 feeds of Standard Ebooks ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow">
|
<section class="narrow">
|
||||||
<h1>Atom 1.0 Ebook Feeds</h1>
|
<h1>Atom 1.0 Ebook Feeds</h1>
|
||||||
|
|
|
@ -24,7 +24,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"" . S
|
||||||
<uri><?= SITE_URL ?></uri>
|
<uri><?= SITE_URL ?></uri>
|
||||||
</author>
|
</author>
|
||||||
<opensearch:totalResults><?= sizeof($ebooks) ?></opensearch:totalResults>
|
<opensearch:totalResults><?= sizeof($ebooks) ?></opensearch:totalResults>
|
||||||
<? foreach($ebooks as $ebook){ ?>
|
<? foreach($ebooks as $ebook){ ?>
|
||||||
<?= Template::AtomFeedEntry(['entry' => $ebook]) ?>
|
<?= Template::AtomFeedEntry(entry: $ebook) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</feed>
|
</feed>
|
||||||
|
|
|
@ -15,7 +15,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
||||||
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
|
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
|
||||||
<xsl:output method="html" html-version="5.0" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat"/> <? /* doctype-system outputs the HTML5 doctype */ ?>
|
<xsl:output method="html" html-version="5.0" encoding="utf-8" indent="yes" doctype-system="about:legacy-compat"/> <? /* doctype-system outputs the HTML5 doctype */ ?>
|
||||||
<xsl:template match="/">
|
<xsl:template match="/">
|
||||||
<?= Template::Header(['isXslt' => true]) ?>
|
<?= Template::Header(isXslt: true) ?>
|
||||||
<main class="opds">
|
<main class="opds">
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test="contains(/atom:feed/atom:title, 'Standard Ebooks - ')">
|
<xsl:when test="contains(/atom:feed/atom:title, 'Standard Ebooks - ')">
|
||||||
|
|
|
@ -29,7 +29,7 @@ catch(Safe\Exceptions\ApcuException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $type->GetDisplayName() . ' Ebook Feeds by ' . $ucTitle, 'description' => 'A list of available ' . $type->GetDisplayName() . ' feeds of Standard Ebooks ebooks by ' . $lcTitle . '.']) ?>
|
?><?= Template::Header(title: $type->GetDisplayName() . ' Ebook Feeds by ' . $ucTitle, description: 'A list of available ' . $type->GetDisplayName() . ' feeds of Standard Ebooks ebooks by ' . $lcTitle . '.') ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1><?= $type->GetDisplayName() ?> Ebook Feeds by <?= $ucTitle ?></h1>
|
<h1><?= $type->GetDisplayName() ?> Ebook Feeds by <?= $ucTitle ?></h1>
|
||||||
|
|
|
@ -55,7 +55,7 @@ try{
|
||||||
catch(Exceptions\CollectionNotFoundException){
|
catch(Exceptions\CollectionNotFoundException){
|
||||||
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
Template::ExitWithCode(Enums\HttpCode::NotFound);
|
||||||
}
|
}
|
||||||
?><?= Template::Header(['title' => $title, 'feedTitle' => $feedTitle, 'feedUrl' => $feedUrl, 'description' => $description]) ?>
|
?><?= Template::Header(title: $title, feedTitle: $feedTitle, feedUrl: $feedUrl, description: $description) ?>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h1>Ebook Feeds for <?= Formatter::EscapeHtml($label) ?></h1>
|
<h1>Ebook Feeds for <?= Formatter::EscapeHtml($label) ?></h1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?= Template::Header(['title' => 'Ebook Feeds', 'description' => 'A list of available feeds of Standard Ebooks ebooks.']) ?>
|
<?= Template::Header(title: 'Ebook Feeds', description: 'A list of available feeds of Standard Ebooks ebooks.') ?>
|
||||||
<main>
|
<main>
|
||||||
<section class="narrow has-hero">
|
<section class="narrow has-hero">
|
||||||
<h1>Ebook Feeds</h1>
|
<h1>Ebook Feeds</h1>
|
||||||
|
|
|
@ -27,6 +27,6 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"". SI
|
||||||
</author>
|
</author>
|
||||||
<opensearch:totalResults><?= sizeof($ebooks) ?></opensearch:totalResults>
|
<opensearch:totalResults><?= sizeof($ebooks) ?></opensearch:totalResults>
|
||||||
<? foreach($ebooks as $ebook){ ?>
|
<? foreach($ebooks as $ebook){ ?>
|
||||||
<?= Template::OpdsAcquisitionEntry(['entry' => $ebook]) ?>
|
<?= Template::OpdsAcquisitionEntry(entry: $ebook) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</feed>
|
</feed>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue